root/kern/vm/copyinout.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. copyfail
  2. copycheck
  3. copyin
  4. copyout
  5. copystr
  6. copyinstr
  7. copyoutstr

   1 /*
   2  * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
   3  *      The President and Fellows of Harvard College.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  * 1. Redistributions of source code must retain the above copyright
   9  *    notice, this list of conditions and the following disclaimer.
  10  * 2. Redistributions in binary form must reproduce the above copyright
  11  *    notice, this list of conditions and the following disclaimer in the
  12  *    documentation and/or other materials provided with the distribution.
  13  * 3. Neither the name of the University nor the names of its contributors
  14  *    may be used to endorse or promote products derived from this software
  15  *    without specific prior written permission.
  16  *
  17  * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
  18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
  21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27  * SUCH DAMAGE.
  28  */
  29 
  30 #include <types.h>
  31 #include <kern/errno.h>
  32 #include <lib.h>
  33 #include <setjmp.h>
  34 #include <thread.h>
  35 #include <current.h>
  36 #include <vm.h>
  37 #include <copyinout.h>
  38 
  39 /*
  40  * User/kernel memory copying functions.
  41  *
  42  * These are arranged to prevent fatal kernel memory faults if invalid
  43  * addresses are supplied by user-level code. This code is itself
  44  * machine-independent; it uses the machine-dependent C setjmp/longjmp
  45  * facility to perform recovery.
  46  *
  47  * However, it assumes things about the memory subsystem that may not
  48  * be true on all platforms. 
  49  *
  50  * (1) It assumes that user memory is mapped into the current address
  51  * space while running in the kernel, and can be accessed by just
  52  * dereferencing a pointer in the ordinary way. (And not, for example,
  53  * with special instructions or via special segment registers.)
  54  *
  55  * (2) It assumes that the user-space region of memory is contiguous
  56  * and extends from 0 to some virtual address USERSPACETOP, and so if
  57  * a user process passes a kernel address the logic in copycheck()
  58  * will trap it.
  59  *
  60  * (3) It assumes that access to user memory from the kernel behaves
  61  * the same way as access to user memory from user space: for
  62  * instance, that the processor honors read-only bits on memory pages
  63  * when in kernel mode.
  64  *
  65  * (4) It assumes that if a proper user-space address that is valid
  66  * but not present, or not valid at all, is touched from the kernel,
  67  * that the correct faults will occur and the VM system will load the
  68  * necessary pages and whatnot.
  69  *
  70  * (5) It assumes that the machine-dependent trap logic provides and
  71  * honors a tm_badfaultfunc field in the thread_machdep structure.
  72  * This feature works as follows: if an otherwise fatal fault occurs
  73  * in kernel mode, and tm_badfaultfunc is set, execution resumes in
  74  * the function pointed to by tm_badfaultfunc.
  75  *
  76  * This code works by setting tm_badfaultfunc and then copying memory
  77  * in an ordinary fashion. If these five assumptions are satisfied,
  78  * which is the case for many ordinary CPU types, this code should
  79  * function correctly. If the assumptions are not satisfied on some
  80  * platform (for instance, certain old 80386 processors violate
  81  * assumption 3), this code cannot be used, and cpu- or platform-
  82  * specific code must be written.
  83  *
  84  * To make use of this code, in addition to tm_badfaultfunc the
  85  * thread_machdep structure should contain a jmp_buf called
  86  * "tm_copyjmp".
  87  */
  88 
  89 /*
  90  * Recovery function. If a fatal fault occurs during copyin, copyout,
  91  * copyinstr, or copyoutstr, execution resumes here. (This behavior is
  92  * caused by setting t_machdep.tm_badfaultfunc and is implemented in
  93  * machine-dependent code.)
  94  *
  95  * We use the C standard function longjmp() to teleport up the call
  96  * stack to where setjmp() was called. At that point we return EFAULT.
  97  */
  98 static
  99 void
 100 copyfail(void)
 101 {
 102         longjmp(curthread->t_machdep.tm_copyjmp, 1);
 103 }
 104 
 105 /*
 106  * Memory region check function. This checks to make sure the block of
 107  * user memory provided (an address and a length) falls within the
 108  * proper userspace region. If it does not, EFAULT is returned.
 109  *
 110  * stoplen is set to the actual maximum length that can be copied.
 111  * This differs from len if and only if the region partially overlaps
 112  * the kernel.
 113  *
 114  * Assumes userspace runs from 0 through USERSPACETOP-1.
 115  */
 116 static
 117 int
 118 copycheck(const_userptr_t userptr, size_t len, size_t *stoplen)
 119 {
 120         vaddr_t bot, top;
 121 
 122         *stoplen = len;
 123 
 124         bot = (vaddr_t) userptr;
 125         top = bot+len-1;
 126 
 127         if (top < bot) {
 128                 /* addresses wrapped around */
 129                 return EFAULT;
 130         }
 131 
 132         if (bot >= USERSPACETOP) {
 133                 /* region is within the kernel */
 134                 return EFAULT;
 135         }
 136 
 137         if (top >= USERSPACETOP) {
 138                 /* region overlaps the kernel. adjust the max length. */
 139                 *stoplen = USERSPACETOP - bot;
 140         }
 141 
 142         return 0;
 143 }
 144 
 145 /*
 146  * copyin
 147  *
 148  * Copy a block of memory of length LEN from user-level address USERSRC 
 149  * to kernel address DEST. We can use memcpy because it's protected by
 150  * the tm_badfaultfunc/copyfail logic.
 151  */
 152 int
 153 copyin(const_userptr_t usersrc, void *dest, size_t len)
 154 {
 155         int result;
 156         size_t stoplen;
 157 
 158         result = copycheck(usersrc, len, &stoplen);
 159         if (result) {
 160                 return result;
 161         }
 162         if (stoplen != len) {
 163                 /* Single block, can't legally truncate it. */
 164                 return EFAULT;
 165         }
 166 
 167         curthread->t_machdep.tm_badfaultfunc = copyfail;
 168 
 169         result = setjmp(curthread->t_machdep.tm_copyjmp);
 170         if (result) {
 171                 curthread->t_machdep.tm_badfaultfunc = NULL;
 172                 return EFAULT;
 173         }
 174 
 175         memcpy(dest, (const void *)usersrc, len);
 176 
 177         curthread->t_machdep.tm_badfaultfunc = NULL;
 178         return 0;
 179 }
 180 
 181 /*
 182  * copyout
 183  *
 184  * Copy a block of memory of length LEN from kernel address SRC to
 185  * user-level address USERDEST. We can use memcpy because it's
 186  * protected by the tm_badfaultfunc/copyfail logic.
 187  */
 188 int
 189 copyout(const void *src, userptr_t userdest, size_t len)
 190 {
 191         int result;
 192         size_t stoplen;
 193 
 194         result = copycheck(userdest, len, &stoplen);
 195         if (result) {
 196                 return result;
 197         }
 198         if (stoplen != len) {
 199                 /* Single block, can't legally truncate it. */
 200                 return EFAULT;
 201         }
 202 
 203         curthread->t_machdep.tm_badfaultfunc = copyfail;
 204 
 205         result = setjmp(curthread->t_machdep.tm_copyjmp);
 206         if (result) {
 207                 curthread->t_machdep.tm_badfaultfunc = NULL;
 208                 return EFAULT;
 209         }
 210 
 211         memcpy((void *)userdest, src, len);
 212 
 213         curthread->t_machdep.tm_badfaultfunc = NULL;
 214         return 0;
 215 }
 216 
 217 /*
 218  * Common string copying function that behaves the way that's desired
 219  * for copyinstr and copyoutstr.
 220  *
 221  * Copies a null-terminated string of maximum length MAXLEN from SRC
 222  * to DEST. If GOTLEN is not null, store the actual length found
 223  * there. Both lengths include the null-terminator. If the string
 224  * exceeds the available length, the call fails and returns
 225  * ENAMETOOLONG.
 226  *
 227  * STOPLEN is like MAXLEN but is assumed to have come from copycheck.
 228  * If we hit MAXLEN it's because the string is too long to fit; if we
 229  * hit STOPLEN it's because the string has run into the end of
 230  * userspace. Thus in the latter case we return EFAULT, not 
 231  * ENAMETOOLONG.
 232  */
 233 static
 234 int
 235 copystr(char *dest, const char *src, size_t maxlen, size_t stoplen,
 236         size_t *gotlen)
 237 {
 238         size_t i;
 239 
 240         for (i=0; i<maxlen && i<stoplen; i++) {
 241                 dest[i] = src[i];
 242                 if (src[i] == 0) {
 243                         if (gotlen != NULL) {
 244                                 *gotlen = i+1;
 245                         }
 246                         return 0;
 247                 }
 248         }
 249         if (stoplen < maxlen) {
 250                 /* ran into user-kernel boundary */
 251                 return EFAULT;
 252         }
 253         /* otherwise just ran out of space */
 254         return ENAMETOOLONG;
 255 }
 256 
 257 /*
 258  * copyinstr
 259  *
 260  * Copy a string from user-level address USERSRC to kernel address
 261  * DEST, as per copystr above. Uses the tm_badfaultfunc/copyfail
 262  * logic to protect against invalid addresses supplied by a user
 263  * process.
 264  */
 265 int
 266 copyinstr(const_userptr_t usersrc, char *dest, size_t len, size_t *actual)
 267 {
 268         int result;
 269         size_t stoplen;
 270 
 271         result = copycheck(usersrc, len, &stoplen);
 272         if (result) {
 273                 return result;
 274         }
 275 
 276         curthread->t_machdep.tm_badfaultfunc = copyfail;
 277 
 278         result = setjmp(curthread->t_machdep.tm_copyjmp);
 279         if (result) {
 280                 curthread->t_machdep.tm_badfaultfunc = NULL;
 281                 return EFAULT;
 282         }
 283 
 284         result = copystr(dest, (const char *)usersrc, len, stoplen, actual);
 285 
 286         curthread->t_machdep.tm_badfaultfunc = NULL;
 287         return result;
 288 }
 289 
 290 /*
 291  * copyoutstr
 292  *
 293  * Copy a string from kernel address SRC to user-level address
 294  * USERDEST, as per copystr above. Uses the tm_badfaultfunc/copyfail
 295  * logic to protect against invalid addresses supplied by a user
 296  * process.
 297  */
 298 int
 299 copyoutstr(const char *src, userptr_t userdest, size_t len, size_t *actual)
 300 {
 301         int result;
 302         size_t stoplen;
 303 
 304         result = copycheck(userdest, len, &stoplen);
 305         if (result) {
 306                 return result;
 307         }
 308 
 309         curthread->t_machdep.tm_badfaultfunc = copyfail;
 310 
 311         result = setjmp(curthread->t_machdep.tm_copyjmp);
 312         if (result) {
 313                 curthread->t_machdep.tm_badfaultfunc = NULL;
 314                 return EFAULT;
 315         }
 316 
 317         result = copystr((char *)userdest, src, len, stoplen, actual);
 318 
 319         curthread->t_machdep.tm_badfaultfunc = NULL;
 320         return result;
 321 }

/* [<][>][^][v][top][bottom][index][help] */