os161-1.99
 All Data Structures
copyinout.c
00001 /*
00002  * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
00003  *      The President and Fellows of Harvard College.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the University nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  */
00029 
00030 #include <types.h>
00031 #include <kern/errno.h>
00032 #include <lib.h>
00033 #include <setjmp.h>
00034 #include <thread.h>
00035 #include <current.h>
00036 #include <vm.h>
00037 #include <copyinout.h>
00038 
00039 /*
00040  * User/kernel memory copying functions.
00041  *
00042  * These are arranged to prevent fatal kernel memory faults if invalid
00043  * addresses are supplied by user-level code. This code is itself
00044  * machine-independent; it uses the machine-dependent C setjmp/longjmp
00045  * facility to perform recovery.
00046  *
00047  * However, it assumes things about the memory subsystem that may not
00048  * be true on all platforms. 
00049  *
00050  * (1) It assumes that user memory is mapped into the current address
00051  * space while running in the kernel, and can be accessed by just
00052  * dereferencing a pointer in the ordinary way. (And not, for example,
00053  * with special instructions or via special segment registers.)
00054  *
00055  * (2) It assumes that the user-space region of memory is contiguous
00056  * and extends from 0 to some virtual address USERSPACETOP, and so if
00057  * a user process passes a kernel address the logic in copycheck()
00058  * will trap it.
00059  *
00060  * (3) It assumes that access to user memory from the kernel behaves
00061  * the same way as access to user memory from user space: for
00062  * instance, that the processor honors read-only bits on memory pages
00063  * when in kernel mode.
00064  *
00065  * (4) It assumes that if a proper user-space address that is valid
00066  * but not present, or not valid at all, is touched from the kernel,
00067  * that the correct faults will occur and the VM system will load the
00068  * necessary pages and whatnot.
00069  *
00070  * (5) It assumes that the machine-dependent trap logic provides and
00071  * honors a tm_badfaultfunc field in the thread_machdep structure.
00072  * This feature works as follows: if an otherwise fatal fault occurs
00073  * in kernel mode, and tm_badfaultfunc is set, execution resumes in
00074  * the function pointed to by tm_badfaultfunc.
00075  *
00076  * This code works by setting tm_badfaultfunc and then copying memory
00077  * in an ordinary fashion. If these five assumptions are satisfied,
00078  * which is the case for many ordinary CPU types, this code should
00079  * function correctly. If the assumptions are not satisfied on some
00080  * platform (for instance, certain old 80386 processors violate
00081  * assumption 3), this code cannot be used, and cpu- or platform-
00082  * specific code must be written.
00083  *
00084  * To make use of this code, in addition to tm_badfaultfunc the
00085  * thread_machdep structure should contain a jmp_buf called
00086  * "tm_copyjmp".
00087  */
00088 
00089 /*
00090  * Recovery function. If a fatal fault occurs during copyin, copyout,
00091  * copyinstr, or copyoutstr, execution resumes here. (This behavior is
00092  * caused by setting t_machdep.tm_badfaultfunc and is implemented in
00093  * machine-dependent code.)
00094  *
00095  * We use the C standard function longjmp() to teleport up the call
00096  * stack to where setjmp() was called. At that point we return EFAULT.
00097  */
00098 static
00099 void
00100 copyfail(void)
00101 {
00102         longjmp(curthread->t_machdep.tm_copyjmp, 1);
00103 }
00104 
00105 /*
00106  * Memory region check function. This checks to make sure the block of
00107  * user memory provided (an address and a length) falls within the
00108  * proper userspace region. If it does not, EFAULT is returned.
00109  *
00110  * stoplen is set to the actual maximum length that can be copied.
00111  * This differs from len if and only if the region partially overlaps
00112  * the kernel.
00113  *
00114  * Assumes userspace runs from 0 through USERSPACETOP-1.
00115  */
00116 static
00117 int
00118 copycheck(const_userptr_t userptr, size_t len, size_t *stoplen)
00119 {
00120         vaddr_t bot, top;
00121 
00122         *stoplen = len;
00123 
00124         bot = (vaddr_t) userptr;
00125         top = bot+len-1;
00126 
00127         if (top < bot) {
00128                 /* addresses wrapped around */
00129                 return EFAULT;
00130         }
00131 
00132         if (bot >= USERSPACETOP) {
00133                 /* region is within the kernel */
00134                 return EFAULT;
00135         }
00136 
00137         if (top >= USERSPACETOP) {
00138                 /* region overlaps the kernel. adjust the max length. */
00139                 *stoplen = USERSPACETOP - bot;
00140         }
00141 
00142         return 0;
00143 }
00144 
00145 /*
00146  * copyin
00147  *
00148  * Copy a block of memory of length LEN from user-level address USERSRC 
00149  * to kernel address DEST. We can use memcpy because it's protected by
00150  * the tm_badfaultfunc/copyfail logic.
00151  */
00152 int
00153 copyin(const_userptr_t usersrc, void *dest, size_t len)
00154 {
00155         int result;
00156         size_t stoplen;
00157 
00158         result = copycheck(usersrc, len, &stoplen);
00159         if (result) {
00160                 return result;
00161         }
00162         if (stoplen != len) {
00163                 /* Single block, can't legally truncate it. */
00164                 return EFAULT;
00165         }
00166 
00167         curthread->t_machdep.tm_badfaultfunc = copyfail;
00168 
00169         result = setjmp(curthread->t_machdep.tm_copyjmp);
00170         if (result) {
00171                 curthread->t_machdep.tm_badfaultfunc = NULL;
00172                 return EFAULT;
00173         }
00174 
00175         memcpy(dest, (const void *)usersrc, len);
00176 
00177         curthread->t_machdep.tm_badfaultfunc = NULL;
00178         return 0;
00179 }
00180 
00181 /*
00182  * copyout
00183  *
00184  * Copy a block of memory of length LEN from kernel address SRC to
00185  * user-level address USERDEST. We can use memcpy because it's
00186  * protected by the tm_badfaultfunc/copyfail logic.
00187  */
00188 int
00189 copyout(const void *src, userptr_t userdest, size_t len)
00190 {
00191         int result;
00192         size_t stoplen;
00193 
00194         result = copycheck(userdest, len, &stoplen);
00195         if (result) {
00196                 return result;
00197         }
00198         if (stoplen != len) {
00199                 /* Single block, can't legally truncate it. */
00200                 return EFAULT;
00201         }
00202 
00203         curthread->t_machdep.tm_badfaultfunc = copyfail;
00204 
00205         result = setjmp(curthread->t_machdep.tm_copyjmp);
00206         if (result) {
00207                 curthread->t_machdep.tm_badfaultfunc = NULL;
00208                 return EFAULT;
00209         }
00210 
00211         memcpy((void *)userdest, src, len);
00212 
00213         curthread->t_machdep.tm_badfaultfunc = NULL;
00214         return 0;
00215 }
00216 
00217 /*
00218  * Common string copying function that behaves the way that's desired
00219  * for copyinstr and copyoutstr.
00220  *
00221  * Copies a null-terminated string of maximum length MAXLEN from SRC
00222  * to DEST. If GOTLEN is not null, store the actual length found
00223  * there. Both lengths include the null-terminator. If the string
00224  * exceeds the available length, the call fails and returns
00225  * ENAMETOOLONG.
00226  *
00227  * STOPLEN is like MAXLEN but is assumed to have come from copycheck.
00228  * If we hit MAXLEN it's because the string is too long to fit; if we
00229  * hit STOPLEN it's because the string has run into the end of
00230  * userspace. Thus in the latter case we return EFAULT, not 
00231  * ENAMETOOLONG.
00232  */
00233 static
00234 int
00235 copystr(char *dest, const char *src, size_t maxlen, size_t stoplen,
00236         size_t *gotlen)
00237 {
00238         size_t i;
00239 
00240         for (i=0; i<maxlen && i<stoplen; i++) {
00241                 dest[i] = src[i];
00242                 if (src[i] == 0) {
00243                         if (gotlen != NULL) {
00244                                 *gotlen = i+1;
00245                         }
00246                         return 0;
00247                 }
00248         }
00249         if (stoplen < maxlen) {
00250                 /* ran into user-kernel boundary */
00251                 return EFAULT;
00252         }
00253         /* otherwise just ran out of space */
00254         return ENAMETOOLONG;
00255 }
00256 
00257 /*
00258  * copyinstr
00259  *
00260  * Copy a string from user-level address USERSRC to kernel address
00261  * DEST, as per copystr above. Uses the tm_badfaultfunc/copyfail
00262  * logic to protect against invalid addresses supplied by a user
00263  * process.
00264  */
00265 int
00266 copyinstr(const_userptr_t usersrc, char *dest, size_t len, size_t *actual)
00267 {
00268         int result;
00269         size_t stoplen;
00270 
00271         result = copycheck(usersrc, len, &stoplen);
00272         if (result) {
00273                 return result;
00274         }
00275 
00276         curthread->t_machdep.tm_badfaultfunc = copyfail;
00277 
00278         result = setjmp(curthread->t_machdep.tm_copyjmp);
00279         if (result) {
00280                 curthread->t_machdep.tm_badfaultfunc = NULL;
00281                 return EFAULT;
00282         }
00283 
00284         result = copystr(dest, (const char *)usersrc, len, stoplen, actual);
00285 
00286         curthread->t_machdep.tm_badfaultfunc = NULL;
00287         return result;
00288 }
00289 
00290 /*
00291  * copyoutstr
00292  *
00293  * Copy a string from kernel address SRC to user-level address
00294  * USERDEST, as per copystr above. Uses the tm_badfaultfunc/copyfail
00295  * logic to protect against invalid addresses supplied by a user
00296  * process.
00297  */
00298 int
00299 copyoutstr(const char *src, userptr_t userdest, size_t len, size_t *actual)
00300 {
00301         int result;
00302         size_t stoplen;
00303 
00304         result = copycheck(userdest, len, &stoplen);
00305         if (result) {
00306                 return result;
00307         }
00308 
00309         curthread->t_machdep.tm_badfaultfunc = copyfail;
00310 
00311         result = setjmp(curthread->t_machdep.tm_copyjmp);
00312         if (result) {
00313                 curthread->t_machdep.tm_badfaultfunc = NULL;
00314                 return EFAULT;
00315         }
00316 
00317         result = copystr((char *)userdest, src, len, stoplen, actual);
00318 
00319         curthread->t_machdep.tm_badfaultfunc = NULL;
00320         return result;
00321 }
 All Data Structures