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 ]

001 /* Copyright (C) 2005  David Decotigny
002 
003    This program is free software; you can redistribute it and/or
004    modify it under the terms of the GNU General Public License
005    as published by the Free Software Foundation; either version 2
006    of the License, or (at your option) any later version.
007    
008    This program is distributed in the hope that it will be useful,
009    but WITHOUT ANY WARRANTY; without even the implied warranty of
010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
011    GNU General Public License for more details.
012    
013    You should have received a copy of the GNU General Public License
014    along with this program; if not, write to the Free Software
015    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
016    USA. 
017 */
018 
019 #include <hwcore/paging.h>
020 #include <sos/thread.h>
021 #include <sos/assert.h>
022 #include <sos/kmalloc.h>
023 
024 #include "uaccess.h"
025 
026 
027 int __uaccess_zero_fool_gcc = 0;
028 /**
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 return is "above" (wrt
031  * source code lines), 2/ it is never "goto"
032  */
033 #define KEEP_LABEL(lbl) \
034  ({ if (__uaccess_zero_fool_gcc) goto lbl; })
035 
036 
037 static sos_ret_t nocheck_user_memcpy(sos_vaddr_t dest,
038                                      sos_vaddr_t src,
039                                      sos_size_t size,
040                                      sos_bool_t transfer_from_user)
041 {
042   __label__ catch_pgflt;
043   char *cptr_dst;
044   const char *cptr_src;
045   sos_size_t transfer_sz;
046   sos_ret_t retval;
047 
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);
055   if (SOS_OK != retval)
056     return retval;
057 
058   /* Version of memcpy that does not alter the stack pointer, in
059      order to be able to abruptedly jump to catch_pgflt without stack
060      inconsistency. That's the reason why we don't call the normal
061      memcpy here: on page fault, it would return back in here, with
062      the stack frame returning back here again */
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;
069 
070   retval = sos_thread_end_user_space_access();
071   if (SOS_OK != retval)
072     return retval;
073 
074   return size;
075 
076   /* An unresolved page fault occured while accessing user space */
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   }
098 }
099 
100 
101 sos_ret_t sos_memcpy_from_user(sos_vaddr_t kernel_to,
102                                sos_uaddr_t user_from,
103                                sos_size_t size)
104 {
105   /* Make sure user is trying to access user space */
106   if (user_from < SOS_PAGING_BASE_USER_ADDRESS)
107     return -SOS_EPERM;
108 
109   if (user_from > SOS_PAGING_TOP_USER_ADDRESS - size)
110     return -SOS_EPERM;
111 
112   return nocheck_user_memcpy(kernel_to, user_from, size, TRUE);
113 }
114 
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 ((sos_ret_t)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 
143 sos_ret_t sos_memcpy_to_user(sos_uaddr_t user_to,
144                              sos_vaddr_t kernel_from,
145                              sos_size_t size)
146 {
147   /* Make sure user is trying to access user space */
148   if (user_to < SOS_PAGING_BASE_USER_ADDRESS)
149     return -SOS_EPERM;
150 
151   if (user_to > SOS_PAGING_TOP_USER_ADDRESS - size)
152     return -SOS_EPERM;
153 
154   return nocheck_user_memcpy(user_to, kernel_from, size, FALSE);
155 }
156 
157 
158 sos_ret_t sos_strnlen_from_user(sos_uaddr_t user_str, sos_size_t max_len)
159 {
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;
168 
169   /* Make sure user is trying to access user space */
170   if (user_str < SOS_PAGING_BASE_USER_ADDRESS)
171     return -SOS_EPERM;
172 
173   /* Don't allow invalid max_len */
174   if ( (max_len < 1) || (max_len > SOS_PAGING_USER_SPACE_SIZE) )
175     return -SOS_EINVAL;
176 
177   retval = sos_thread_prepare_user_space_access(NULL,
178                                                 (sos_vaddr_t) && catch_pgflt);
179   if (SOS_OK != retval)
180     return retval;
181 
182   /* Version of strnlen that does not alter the stack pointer, in
183      order to be able to abruptedly jump to catch_pgflt without stack
184      inconsistency. That's the reason why we don't call the normal
185      strnlen here: on page fault, it would return back in here, with
186      the stack frame returning back here again */
187   for (sc = (const char *)user_str; max_len-- && *sc != '\0'; ++sc)
188     continue;
189 
190 
191   retval = sos_thread_end_user_space_access();
192   if (SOS_OK != retval)
193     return retval;
194 
195   return ((sos_uaddr_t)sc - user_str);
196 
197   /* An unresolved page fault occured while accessing user space */
198  catch_pgflt:
199   {
200     sos_thread_end_user_space_access();
201     return -SOS_EFAULT;
202   }
203 }
204 
205 
206 static sos_ret_t nocheck_user_strzcpy(char *dst, const char *src,
207                                       sos_size_t len)
208 {
209   __label__ catch_pgflt;
210   unsigned int i;
211   sos_ret_t retval;
212 
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);
220   if (SOS_OK != retval)
221     return retval;
222 
223   /* Version of strzcpy that does not alter the stack pointer, in
224      order to be able to abruptedly jump to catch_pgflt without stack
225      inconsistency. That's the reason why we don't call the normal
226      strzcpy here: on page fault, it would return back in here, with
227      the stack frame returning back here again */
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'; 
236 
237   retval = sos_thread_end_user_space_access();
238   if (SOS_OK != retval)
239     return retval;
240 
241   return SOS_OK;
242 
243   /* An unresolved page fault occured while accessing user space */
244  catch_pgflt:
245   {
246     sos_thread_end_user_space_access();
247     return -SOS_EFAULT;
248   }
249 }
250 
251 
252 sos_ret_t sos_strzcpy_from_user(char *kernel_to, sos_uaddr_t user_from,
253                                 sos_size_t max_len)
254 {
255   /* Make sure user is trying to access user space */
256   if ((sos_uaddr_t)user_from < SOS_PAGING_BASE_USER_ADDRESS)
257     return -SOS_EPERM;
258 
259   /* Don't allow invalid max_len */
260   if ( (max_len < 1) || (max_len > SOS_PAGING_USER_SPACE_SIZE) )
261     return -SOS_EINVAL;
262 
263   return nocheck_user_strzcpy(kernel_to, (const char*)user_from, max_len);
264 }
265 
266 
267 sos_ret_t sos_strzcpy_to_user(sos_uaddr_t user_to, const char *kernel_from,
268                               sos_size_t max_len)
269 {
270   /* Make sure user is trying to access user space */
271   if ((sos_uaddr_t)user_to < SOS_PAGING_BASE_USER_ADDRESS)
272     return -SOS_EPERM;
273 
274   /* Don't allow invalid max_len */
275   if ( (max_len < 1) || (max_len > SOS_PAGING_USER_SPACE_SIZE) )
276     return -SOS_EINVAL;
277 
278   return nocheck_user_strzcpy((char*)user_to, kernel_from, max_len);
279 }
280 
281 
282 sos_ret_t sos_strndup_from_user(char ** kernel_to, sos_uaddr_t from_user,
283                                 sos_size_t max_len,
284                                 sos_ui32_t kmalloc_flags)
285 {
286   sos_ret_t retval = sos_strnlen_from_user(from_user, max_len);
287   if (retval < 0)
288     return retval;
289 
290   *kernel_to = (char*)sos_kmalloc(retval + 1, kmalloc_flags);
291   if (NULL == *kernel_to)
292     return -SOS_ENOMEM;
293 
294   retval = sos_strzcpy_from_user(*kernel_to, from_user, retval + 1);
295   if (SOS_OK != retval)
296     {
297       sos_kfree((sos_vaddr_t)*kernel_to);
298       *kernel_to = NULL;
299     }
300 
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;
324 }

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