-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathuaccess.c
More file actions
133 lines (98 loc) · 3.23 KB
/
uaccess.c
File metadata and controls
133 lines (98 loc) · 3.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include "types.h"
#include "vmm.h"
#include "process.h"
#include "kstring.h"
#define USER_SPACE_START 0x1000ULL
#define USER_SPACE_END 0x00007FFFFFFFFFFFULL
bool access_ok(const void *addr, size_t size) {
uintptr_t start = (uintptr_t)addr;
uintptr_t end = start + size;
if (end < start)
return false;
if (start < USER_SPACE_START)
return false;
if (end > USER_SPACE_END)
return false;
return true;
}
bool access_ok_write(const void *addr, size_t size) {
if (!access_ok(addr, size))
return false;
uintptr_t page_start = (uintptr_t)addr & ~(PAGE_SIZE - 1);
uintptr_t page_end = ((uintptr_t)addr + size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
for (uintptr_t p = page_start; p < page_end; p += PAGE_SIZE) {
if (!vmm_is_mapped(p))
return false;
}
return true;
}
int copy_from_user(void *kernel_dst, const void *user_src, size_t size) {
if (!size)
return 0;
if (!access_ok(user_src, size))
return -EFAULT;
uintptr_t page_start = (uintptr_t)user_src & ~(PAGE_SIZE - 1);
uintptr_t page_end = ((uintptr_t)user_src + size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
for (uintptr_t p = page_start; p < page_end; p += PAGE_SIZE) {
if (!vmm_is_mapped(p))
return -EFAULT;
}
kmemcpy(kernel_dst, user_src, size);
return 0;
}
int copy_to_user(void *user_dst, const void *kernel_src, size_t size) {
if (!size)
return 0;
if (!access_ok(user_dst, size))
return -EFAULT;
uintptr_t page_start = (uintptr_t)user_dst & ~(PAGE_SIZE - 1);
uintptr_t page_end = ((uintptr_t)user_dst + size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
for (uintptr_t p = page_start; p < page_end; p += PAGE_SIZE) {
if (!vmm_is_mapped(p))
return -EFAULT;
}
kmemcpy(user_dst, kernel_src, size);
return 0;
}
int strncpy_from_user(char *kernel_dst, const char *user_src, size_t max_len) {
if (!access_ok(user_src, 1))
return -EFAULT;
for (size_t i = 0; i < max_len; i++) {
uintptr_t addr = (uintptr_t)(user_src + i);
if ((addr & (PAGE_SIZE - 1)) == 0) {
if (!vmm_is_mapped(addr))
return -EFAULT;
}
kernel_dst[i] = user_src[i];
if (user_src[i] == '\0')
return (int)i;
}
kernel_dst[max_len - 1] = '\0';
return (int)(max_len - 1);
}
size_t strnlen_user(const char *user_str, size_t max_len) {
if (!access_ok(user_str, 1))
return 0;
for (size_t i = 0; i < max_len; i++) {
uintptr_t addr = (uintptr_t)(user_str + i);
if ((addr & (PAGE_SIZE - 1)) == 0) {
if (!vmm_is_mapped(addr))
return 0;
}
if (user_str[i] == '\0')
return i + 1;
}
return max_len + 1;
}
int clear_user(void *user_dst, size_t size) {
if (!access_ok(user_dst, size))
return -EFAULT;
uintptr_t page_start = (uintptr_t)user_dst & ~(PAGE_SIZE - 1);
uintptr_t page_end = ((uintptr_t)user_dst + size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
for (uintptr_t p = page_start; p < page_end; p += PAGE_SIZE) {
if (!vmm_is_mapped(p))
return -EFAULT;
}
kmemset(user_dst, 0, size);
return 0;
}