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