SimpleOS

LXR

Navigation



Site hébergé par : enix

The LXR Cross Referencer for SOS

source navigation ]
diff markup ]
identifier search ]
general search ]
 
 
Article:1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 6.5 ] [ 7 ] [ 7.5 ] [ 8 ] [ 9 ] [ 9.5 ]

Diff markup

Differences between /sos/uaccess.c (Article 9.5) and /sos/uaccess.c (Article 9)


001 /* Copyright (C) 2005  David Decotigny            001 /* Copyright (C) 2005  David Decotigny
002                                                   002 
003    This program is free software; you can redi    003    This program is free software; you can redistribute it and/or
004    modify it under the terms of the GNU Genera    004    modify it under the terms of the GNU General Public License
005    as published by the Free Software Foundatio    005    as published by the Free Software Foundation; either version 2
006    of the License, or (at your option) any lat    006    of the License, or (at your option) any later version.
007                                                   007    
008    This program is distributed in the hope tha    008    This program is distributed in the hope that it will be useful,
009    but WITHOUT ANY WARRANTY; without even the     009    but WITHOUT ANY WARRANTY; without even the implied warranty of
010    MERCHANTABILITY or FITNESS FOR A PARTICULAR    010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
011    GNU General Public License for more details    011    GNU General Public License for more details.
012                                                   012    
013    You should have received a copy of the GNU     013    You should have received a copy of the GNU General Public License
014    along with this program; if not, write to t    014    along with this program; if not, write to the Free Software
015    Foundation, Inc., 59 Temple Place - Suite 3    015    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
016    USA.                                           016    USA. 
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  * Make sure gcc optimizations don't go too fa    029  * Make sure gcc optimizations don't go too far and don't suppress the
030  * code at the given label because 1/ a global    030  * code at the given label because 1/ a global return is "above" (wrt
031  * source code lines), 2/ it is never "goto"      031  * source code lines), 2/ it is never "goto"
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   /* Version of memcpy that does not alter the    058   /* Version of memcpy that does not alter the stack pointer, in
059      order to be able to abruptedly jump to ca    059      order to be able to abruptedly jump to catch_pgflt without stack
060      inconsistency. That's the reason why we d    060      inconsistency. That's the reason why we don't call the normal
061      memcpy here: on page fault, it would retu    061      memcpy here: on page fault, it would return back in here, with
062      the stack frame returning back here again    062      the stack frame returning back here again */
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   /* An unresolved page fault occured while ac    076   /* An unresolved page fault occured while accessing user space */
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   /* Make sure user is trying to access user s    105   /* Make sure user is trying to access user space */
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 -SOS_EINVAL;                           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 ((sos_ret_t)length != retval)             !! 130   if (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   /* Make sure user is trying to access user s    147   /* Make sure user is trying to access user space */
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   /* Make sure user is trying to access user s    169   /* Make sure user is trying to access user space */
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   /* Don't allow invalid max_len */               173   /* Don't allow invalid max_len */
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   /* Version of strnlen that does not alter th    182   /* Version of strnlen that does not alter the stack pointer, in
183      order to be able to abruptedly jump to ca    183      order to be able to abruptedly jump to catch_pgflt without stack
184      inconsistency. That's the reason why we d    184      inconsistency. That's the reason why we don't call the normal
185      strnlen here: on page fault, it would ret    185      strnlen here: on page fault, it would return back in here, with
186      the stack frame returning back here again    186      the stack frame returning back here again */
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   /* An unresolved page fault occured while ac    197   /* An unresolved page fault occured while accessing user space */
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   /* Version of strzcpy that does not alter th    223   /* Version of strzcpy that does not alter the stack pointer, in
224      order to be able to abruptedly jump to ca    224      order to be able to abruptedly jump to catch_pgflt without stack
225      inconsistency. That's the reason why we d    225      inconsistency. That's the reason why we don't call the normal
226      strzcpy here: on page fault, it would ret    226      strzcpy here: on page fault, it would return back in here, with
227      the stack frame returning back here again    227      the stack frame returning back here again */
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   /* An unresolved page fault occured while ac    243   /* An unresolved page fault occured while accessing user space */
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   /* Make sure user is trying to access user s    255   /* Make sure user is trying to access user space */
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   /* Don't allow invalid max_len */               259   /* Don't allow invalid max_len */
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   /* Make sure user is trying to access user s    270   /* Make sure user is trying to access user space */
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   /* Don't allow invalid max_len */               274   /* Don't allow invalid max_len */
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  << 
306                                 sos_vaddr_t ke << 
307                                 sos_size_t siz << 
308 {                                              << 
309   if (to_addr.is_user)                         << 
310     return sos_memcpy_to_user(to_addr.addr, ke << 
311   memcpy((void*)to_addr.addr, (const void*)ker << 
312   return size;                                 << 
313 }                                              << 
314                                                << 
315                                                << 
316 sos_ret_t sos_memcpy_generic_from(sos_vaddr_t  << 
317                                   sos_genaddr_ << 
318                                   sos_size_t s << 
319 {                                              << 
320   if (from_addr.is_user)                       << 
321     return sos_memcpy_from_user(kernel_from, f << 
322   memcpy((void*)kernel_from, (const void*)from << 
323   return size;                                 << 
324 }                                                 302 }
                                                      

source navigation ] diff markup ] identifier search ] general search ]