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