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