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   retval = sos_thread_prepare_user_space_access(NULL,
051                                                 (sos_vaddr_t) && catch_pgflt);
052   if (SOS_OK != retval)
053     return retval;
054 
055   /* Version of memcpy that does not alter the stack pointer, in
056      order to be able to abruptedly jump to catch_pgflt without stack
057      inconsistency. That's the reason why we don't call the normal
058      memcpy here: on page fault, it would return back in here, with
059      the stack frame returning back here again */
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 
067   retval = sos_thread_end_user_space_access();
068   if (SOS_OK != retval)
069     return retval;
070 
071   return size;
072 
073   /* An unresolved page fault occured while accessing user space */
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   }
095 }
096 
097 
098 sos_ret_t sos_memcpy_from_user(sos_vaddr_t kernel_to,
099                                sos_uaddr_t user_from,
100                                sos_size_t size)
101 {
102   /* Make sure user is trying to access user space */
103   if (user_from < SOS_PAGING_BASE_USER_ADDRESS)
104     return -SOS_EPERM;
105 
106   if (user_from > SOS_PAGING_TOP_USER_ADDRESS - size)
107     return -SOS_EPERM;
108 
109   return nocheck_user_memcpy(kernel_to, user_from, size, TRUE);
110 }
111 
112 
113 sos_ret_t sos_memcpy_to_user(sos_uaddr_t user_to,
114                              sos_vaddr_t kernel_from,
115                              sos_size_t size)
116 {
117   /* Make sure user is trying to access user space */
118   if (user_to < SOS_PAGING_BASE_USER_ADDRESS)
119     return -SOS_EPERM;
120 
121   if (user_to > SOS_PAGING_TOP_USER_ADDRESS - size)
122     return -SOS_EPERM;
123 
124   return nocheck_user_memcpy(user_to, kernel_from, size, FALSE);
125 }
126 
127 
128 sos_ret_t sos_strnlen_from_user(sos_uaddr_t user_str, sos_size_t max_len)
129 {
130   __label__ catch_pgflt;
131   const char *sc;
132   sos_ret_t retval;
133 
134   KEEP_LABEL(catch_pgflt);
135 
136   /* Make sure user is trying to access user space */
137   if (user_str < SOS_PAGING_BASE_USER_ADDRESS)
138     return -SOS_EPERM;
139 
140   /* Don't allow invalid max_len */
141   if ( (max_len < 1) || (max_len > SOS_PAGING_USER_SPACE_SIZE) )
142     return -SOS_EINVAL;
143 
144   retval = sos_thread_prepare_user_space_access(NULL,
145                                                 (sos_vaddr_t) && catch_pgflt);
146   if (SOS_OK != retval)
147     return retval;
148 
149   /* Version of strnlen that does not alter the stack pointer, in
150      order to be able to abruptedly jump to catch_pgflt without stack
151      inconsistency. That's the reason why we don't call the normal
152      strnlen here: on page fault, it would return back in here, with
153      the stack frame returning back here again */
154   for (sc = (const char *)user_str; max_len-- && *sc != '\0'; ++sc)
155     continue;
156 
157 
158   retval = sos_thread_end_user_space_access();
159   if (SOS_OK != retval)
160     return retval;
161 
162   return ((sos_uaddr_t)sc - user_str);
163 
164   /* An unresolved page fault occured while accessing user space */
165  catch_pgflt:
166   {
167     sos_thread_end_user_space_access();
168     return -SOS_EFAULT;
169   }
170 }
171 
172 
173 static sos_ret_t nocheck_user_strzcpy(char *dst, const char *src,
174                                       sos_size_t len)
175 {
176   __label__ catch_pgflt;
177   unsigned int i;
178   sos_ret_t retval;
179 
180   KEEP_LABEL(catch_pgflt);
181 
182   retval = sos_thread_prepare_user_space_access(NULL,
183                                                 (sos_vaddr_t) && catch_pgflt);
184   if (SOS_OK != retval)
185     return retval;
186 
187   /* Version of strzcpy that does not alter the stack pointer, in
188      order to be able to abruptedly jump to catch_pgflt without stack
189      inconsistency. That's the reason why we don't call the normal
190      strzcpy here: on page fault, it would return back in here, with
191      the stack frame returning back here again */
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'; 
200 
201   retval = sos_thread_end_user_space_access();
202   if (SOS_OK != retval)
203     return retval;
204 
205   return SOS_OK;
206 
207   /* An unresolved page fault occured while accessing user space */
208  catch_pgflt:
209   {
210     sos_thread_end_user_space_access();
211     return -SOS_EFAULT;
212   }
213 }
214 
215 
216 sos_ret_t sos_strzcpy_from_user(char *kernel_to, sos_uaddr_t user_from,
217                                 sos_size_t max_len)
218 {
219   /* Make sure user is trying to access user space */
220   if ((sos_uaddr_t)user_from < SOS_PAGING_BASE_USER_ADDRESS)
221     return -SOS_EPERM;
222 
223   /* Don't allow invalid max_len */
224   if ( (max_len < 1) || (max_len > SOS_PAGING_USER_SPACE_SIZE) )
225     return -SOS_EINVAL;
226 
227   return nocheck_user_strzcpy(kernel_to, (const char*)user_from, max_len);
228 }
229 
230 
231 sos_ret_t sos_strzcpy_to_user(sos_uaddr_t user_to, const char *kernel_from,
232                               sos_size_t max_len)
233 {
234   /* Make sure user is trying to access user space */
235   if ((sos_uaddr_t)user_to < SOS_PAGING_BASE_USER_ADDRESS)
236     return -SOS_EPERM;
237 
238   /* Don't allow invalid max_len */
239   if ( (max_len < 1) || (max_len > SOS_PAGING_USER_SPACE_SIZE) )
240     return -SOS_EINVAL;
241 
242   return nocheck_user_strzcpy((char*)user_to, kernel_from, max_len);
243 }
244 
245 
246 sos_ret_t sos_strndup_from_user(char ** kernel_to, sos_uaddr_t from_user,
247                                 sos_size_t max_len,
248                                 sos_ui32_t kmalloc_flags)
249 {
250   sos_ret_t retval = sos_strnlen_from_user(from_user, max_len);
251   if (retval < 0)
252     return retval;
253 
254   *kernel_to = (char*)sos_kmalloc(retval + 1, kmalloc_flags);
255   if (NULL == *kernel_to)
256     return -SOS_ENOMEM;
257 
258   retval = sos_strzcpy_from_user(*kernel_to, from_user, retval + 1);
259   if (SOS_OK != retval)
260     {
261       sos_kfree((sos_vaddr_t)*kernel_to);
262       *kernel_to = NULL;
263     }
264 
265   return retval;
266 }

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