Diff markup
001 001
002 002
003 003
004 004
005 005
006 006
007 007
008 008
009 009
010 010
011 011
012 012
013 013
014 014
015 015
016 016
017 017
018 018
019 #include <hwcore/paging.h> 019 #include <hwcore/paging.h>
020 #include <sos/thread.h> 020 #include <sos/thread.h>
021 #include <sos/assert.h> 021 #include <sos/assert.h>
022 #include <sos/kmalloc.h> 022 #include <sos/kmalloc.h>
023 023
024 #include "uaccess.h" 024 #include "uaccess.h"
025 025
026 026
027 int __uaccess_zero_fool_gcc = 0; <<
028 027
029 !! 028
030 !! 029
031 <<
032 030
033 #define KEEP_LABEL(lbl) \ !! 031 static sos_ret_t bindto_user_mm_context()
034 ({ if (__uaccess_zero_fool_gcc) goto lbl; }) !! 032 {
>> 033 struct sos_thread * current_thread;
>> 034 struct sos_mm_context * process_mm_ctxt;
>> 035
>> 036 current_thread = sos_thread_get_current();
>> 037 SOS_ASSERT_FATAL(NULL != current_thread->process);
>> 038
>> 039
>> 040 process_mm_ctxt
>> 041 = sos_process_get_mm_context(current_thread->process);
>> 042 return sos_thread_change_current_mm_context(process_mm_ctxt);
>> 043 }
>> 044
>> 045
>> 046
>> 047
>> 048
>> 049
>> 050 #define unbindto_user_mm_context() \
>> 051 sos_thread_change_current_mm_context(NULL)
035 052
036 053
037 static sos_ret_t nocheck_user_memcpy(sos_vaddr 054 static sos_ret_t nocheck_user_memcpy(sos_vaddr_t dest,
038 sos_vaddr 055 sos_vaddr_t src,
039 sos_size_ 056 sos_size_t size,
040 sos_bool_ 057 sos_bool_t transfer_from_user)
041 { 058 {
042 __label__ catch_pgflt; <<
043 char *cptr_dst; <<
044 const char *cptr_src; <<
045 sos_size_t transfer_sz; <<
046 sos_ret_t retval; 059 sos_ret_t retval;
047 060
048 KEEP_LABEL(catch_pgflt); !! 061 retval = bindto_user_mm_context();
049 <<
050 if (size <= 0) <<
051 return 0; <<
052 <<
053 retval = sos_thread_prepare_user_space_acces <<
054 <<
055 if (SOS_OK != retval) 062 if (SOS_OK != retval)
056 return retval; 063 return retval;
057 064
058 !! 065 memcpy((void*) dest, (void*) src, size);
059 <<
060 <<
061 <<
062 <<
063 for (cptr_dst = (char*)dest, <<
064 cptr_src = (const char*)src, <<
065 transfer_sz = size ; <<
066 transfer_sz > 0 ; <<
067 cptr_dst++, cptr_src++, transfer_sz--) <<
068 *cptr_dst = *cptr_src; <<
069 066
070 retval = sos_thread_end_user_space_access(); !! 067 retval = unbindto_user_mm_context();
071 if (SOS_OK != retval) 068 if (SOS_OK != retval)
072 return retval; 069 return retval;
073 070
074 return size; 071 return size;
075 <<
076 <<
077 catch_pgflt: <<
078 { <<
079 struct sos_thread * cur_thr = sos_thread_g <<
080 sos_uaddr_t faulted_uaddr = cur_thr->fixup <<
081 <<
082 if (transfer_from_user) <<
083 { <<
084 if ( (faulted_uaddr < src) || (faulted <<
085 sos_display_fatal_error("Unexpected <<
086 retval = faulted_uaddr - src; <<
087 } <<
088 else <<
089 { <<
090 if ( (faulted_uaddr < dest) || (faulte <<
091 sos_display_fatal_error("Unexpected <<
092 retval = faulted_uaddr - dest; <<
093 } <<
094 <<
095 sos_thread_end_user_space_access(); <<
096 return retval; <<
097 } <<
098 } 072 }
099 073
100 074
101 sos_ret_t sos_memcpy_from_user(sos_vaddr_t ker 075 sos_ret_t sos_memcpy_from_user(sos_vaddr_t kernel_to,
102 sos_uaddr_t use 076 sos_uaddr_t user_from,
103 sos_size_t size 077 sos_size_t size)
104 { 078 {
105 079
106 if (user_from < SOS_PAGING_BASE_USER_ADDRESS 080 if (user_from < SOS_PAGING_BASE_USER_ADDRESS)
107 return -SOS_EPERM; 081 return -SOS_EPERM;
108 082
109 if (user_from > SOS_PAGING_TOP_USER_ADDRESS 083 if (user_from > SOS_PAGING_TOP_USER_ADDRESS - size)
110 return -SOS_EPERM; 084 return -SOS_EPERM;
111 085
112 return nocheck_user_memcpy(kernel_to, user_f 086 return nocheck_user_memcpy(kernel_to, user_from, size, TRUE);
113 } 087 }
114 088
115 089
116 sos_ret_t sos_memdup_from_user(sos_vaddr_t * k <<
117 sos_size_t leng <<
118 sos_ui32_t kmal <<
119 { <<
120 sos_ret_t retval; <<
121 <<
122 if (length <= 0) <<
123 return 0; <<
124 <<
125 *kernel_to = sos_kmalloc(length, kmalloc_fla <<
126 if (NULL == (void*) *kernel_to) <<
127 return -SOS_ENOMEM; <<
128 <<
129 retval = sos_memcpy_from_user(*kernel_to, fr <<
130 if (length != retval) <<
131 { <<
132 sos_kfree((sos_vaddr_t)*kernel_to); <<
133 *kernel_to = (sos_vaddr_t) NULL; <<
134 retval = -SOS_EFAULT; <<
135 } <<
136 else <<
137 retval = SOS_OK; <<
138 <<
139 return retval; <<
140 } <<
141 <<
142 <<
143 sos_ret_t sos_memcpy_to_user(sos_uaddr_t user_ 090 sos_ret_t sos_memcpy_to_user(sos_uaddr_t user_to,
144 sos_vaddr_t kerne 091 sos_vaddr_t kernel_from,
145 sos_size_t size) 092 sos_size_t size)
146 { 093 {
147 094
148 if (user_to < SOS_PAGING_BASE_USER_ADDRESS) 095 if (user_to < SOS_PAGING_BASE_USER_ADDRESS)
149 return -SOS_EPERM; 096 return -SOS_EPERM;
150 097
151 if (user_to > SOS_PAGING_TOP_USER_ADDRESS - 098 if (user_to > SOS_PAGING_TOP_USER_ADDRESS - size)
152 return -SOS_EPERM; 099 return -SOS_EPERM;
153 100
154 return nocheck_user_memcpy(user_to, kernel_f 101 return nocheck_user_memcpy(user_to, kernel_from, size, FALSE);
155 } 102 }
156 103
157 104
158 sos_ret_t sos_strnlen_from_user(sos_uaddr_t us 105 sos_ret_t sos_strnlen_from_user(sos_uaddr_t user_str, sos_size_t max_len)
159 { 106 {
160 __label__ catch_pgflt; !! 107 sos_ret_t retval, len;
161 const char *sc; <<
162 sos_ret_t retval; <<
163 <<
164 KEEP_LABEL(catch_pgflt); <<
165 <<
166 if (max_len <= 0) <<
167 return 0; <<
168 108
169 109
170 if (user_str < SOS_PAGING_BASE_USER_ADDRESS) 110 if (user_str < SOS_PAGING_BASE_USER_ADDRESS)
171 return -SOS_EPERM; 111 return -SOS_EPERM;
172 112
173 113
174 if ( (max_len < 1) || (max_len > SOS_PAGING_ 114 if ( (max_len < 1) || (max_len > SOS_PAGING_USER_SPACE_SIZE) )
175 return -SOS_EINVAL; 115 return -SOS_EINVAL;
176 116
177 retval = sos_thread_prepare_user_space_acces !! 117 retval = bindto_user_mm_context();
178 <<
179 if (SOS_OK != retval) 118 if (SOS_OK != retval)
180 return retval; 119 return retval;
181 120
182 !! 121 len = strnlen((const char*)user_str, max_len);
183 <<
184 <<
185 <<
186 <<
187 for (sc = (const char *)user_str; max_len-- <<
188 continue; <<
189 122
190 !! 123 retval = unbindto_user_mm_context();
191 retval = sos_thread_end_user_space_access(); <<
192 if (SOS_OK != retval) 124 if (SOS_OK != retval)
193 return retval; 125 return retval;
194 126
195 return ((sos_uaddr_t)sc - user_str); !! 127 return len;
196 <<
197 <<
198 catch_pgflt: <<
199 { <<
200 sos_thread_end_user_space_access(); <<
201 return -SOS_EFAULT; <<
202 } <<
203 } 128 }
204 129
205 130
206 static sos_ret_t nocheck_user_strzcpy(char *ds 131 static sos_ret_t nocheck_user_strzcpy(char *dst, const char *src,
207 sos_size 132 sos_size_t len)
208 { 133 {
209 __label__ catch_pgflt; <<
210 unsigned int i; <<
211 sos_ret_t retval; 134 sos_ret_t retval;
212 135
213 KEEP_LABEL(catch_pgflt); !! 136 retval = bindto_user_mm_context();
214 <<
215 if (len <= 0) <<
216 return 0; <<
217 <<
218 retval = sos_thread_prepare_user_space_acces <<
219 <<
220 if (SOS_OK != retval) 137 if (SOS_OK != retval)
221 return retval; 138 return retval;
222 139
223 !! 140 strzcpy(dst, src, len);
224 <<
225 <<
226 <<
227 <<
228 for (i = 0; i < len; i++) <<
229 { <<
230 dst[i] = src[i]; <<
231 if(src[i] == '\0') <<
232 break; <<
233 } <<
234 <<
235 dst[len-1] = '\0'; <<
236 141
237 retval = sos_thread_end_user_space_access(); !! 142 retval = unbindto_user_mm_context();
238 if (SOS_OK != retval) 143 if (SOS_OK != retval)
239 return retval; 144 return retval;
240 145
241 return SOS_OK; 146 return SOS_OK;
242 <<
243 <<
244 catch_pgflt: <<
245 { <<
246 sos_thread_end_user_space_access(); <<
247 return -SOS_EFAULT; <<
248 } <<
249 } 147 }
250 148
251 149
252 sos_ret_t sos_strzcpy_from_user(char *kernel_t 150 sos_ret_t sos_strzcpy_from_user(char *kernel_to, sos_uaddr_t user_from,
253 sos_size_t max 151 sos_size_t max_len)
254 { 152 {
255 153
256 if ((sos_uaddr_t)user_from < SOS_PAGING_BASE 154 if ((sos_uaddr_t)user_from < SOS_PAGING_BASE_USER_ADDRESS)
257 return -SOS_EPERM; 155 return -SOS_EPERM;
258 156
259 157
260 if ( (max_len < 1) || (max_len > SOS_PAGING_ 158 if ( (max_len < 1) || (max_len > SOS_PAGING_USER_SPACE_SIZE) )
261 return -SOS_EINVAL; 159 return -SOS_EINVAL;
262 160
263 return nocheck_user_strzcpy(kernel_to, (cons 161 return nocheck_user_strzcpy(kernel_to, (const char*)user_from, max_len);
264 } 162 }
265 163
266 164
267 sos_ret_t sos_strzcpy_to_user(sos_uaddr_t user 165 sos_ret_t sos_strzcpy_to_user(sos_uaddr_t user_to, const char *kernel_from,
268 sos_size_t max_l 166 sos_size_t max_len)
269 { 167 {
270 168
271 if ((sos_uaddr_t)user_to < SOS_PAGING_BASE_U 169 if ((sos_uaddr_t)user_to < SOS_PAGING_BASE_USER_ADDRESS)
272 return -SOS_EPERM; 170 return -SOS_EPERM;
273 171
274 172
275 if ( (max_len < 1) || (max_len > SOS_PAGING_ 173 if ( (max_len < 1) || (max_len > SOS_PAGING_USER_SPACE_SIZE) )
276 return -SOS_EINVAL; 174 return -SOS_EINVAL;
277 175
278 return nocheck_user_strzcpy((char*)user_to, 176 return nocheck_user_strzcpy((char*)user_to, kernel_from, max_len);
279 } 177 }
280 178
281 179
282 sos_ret_t sos_strndup_from_user(char ** kernel 180 sos_ret_t sos_strndup_from_user(char ** kernel_to, sos_uaddr_t from_user,
283 sos_size_t max 181 sos_size_t max_len,
284 sos_ui32_t kma 182 sos_ui32_t kmalloc_flags)
285 { 183 {
286 sos_ret_t retval = sos_strnlen_from_user(fro 184 sos_ret_t retval = sos_strnlen_from_user(from_user, max_len);
287 if (retval < 0) 185 if (retval < 0)
288 return retval; 186 return retval;
289 187
290 *kernel_to = (char*)sos_kmalloc(retval + 1, 188 *kernel_to = (char*)sos_kmalloc(retval + 1, kmalloc_flags);
291 if (NULL == *kernel_to) 189 if (NULL == *kernel_to)
292 return -SOS_ENOMEM; 190 return -SOS_ENOMEM;
293 191
294 retval = sos_strzcpy_from_user(*kernel_to, f 192 retval = sos_strzcpy_from_user(*kernel_to, from_user, retval + 1);
295 if (SOS_OK != retval) 193 if (SOS_OK != retval)
296 { 194 {
297 sos_kfree((sos_vaddr_t)*kernel_to); 195 sos_kfree((sos_vaddr_t)*kernel_to);
298 *kernel_to = NULL; 196 *kernel_to = NULL;
299 } 197 }
300 198
301 return retval; 199 return retval;
302 } 200 }