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