The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/lib/strncpy_from_user.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 #include <linux/module.h>
    2 #include <linux/uaccess.h>
    3 #include <linux/kernel.h>
    4 #include <linux/errno.h>
    5 
    6 #include <asm/byteorder.h>
    7 #include <asm/word-at-a-time.h>
    8 
    9 #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
   10 #define IS_UNALIGNED(src, dst)  0
   11 #else
   12 #define IS_UNALIGNED(src, dst)  \
   13         (((long) dst | (long) src) & (sizeof(long) - 1))
   14 #endif
   15 
   16 /*
   17  * Do a strncpy, return length of string without final '\0'.
   18  * 'count' is the user-supplied count (return 'count' if we
   19  * hit it), 'max' is the address space maximum (and we return
   20  * -EFAULT if we hit it).
   21  */
   22 static inline long do_strncpy_from_user(char *dst, const char __user *src, long count, unsigned long max)
   23 {
   24         const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
   25         long res = 0;
   26 
   27         /*
   28          * Truncate 'max' to the user-specified limit, so that
   29          * we only have one limit we need to check in the loop
   30          */
   31         if (max > count)
   32                 max = count;
   33 
   34         if (IS_UNALIGNED(src, dst))
   35                 goto byte_at_a_time;
   36 
   37         while (max >= sizeof(unsigned long)) {
   38                 unsigned long c, data;
   39 
   40                 /* Fall back to byte-at-a-time if we get a page fault */
   41                 if (unlikely(__get_user(c,(unsigned long __user *)(src+res))))
   42                         break;
   43                 *(unsigned long *)(dst+res) = c;
   44                 if (has_zero(c, &data, &constants)) {
   45                         data = prep_zero_mask(c, data, &constants);
   46                         data = create_zero_mask(data);
   47                         return res + find_zero(data);
   48                 }
   49                 res += sizeof(unsigned long);
   50                 max -= sizeof(unsigned long);
   51         }
   52 
   53 byte_at_a_time:
   54         while (max) {
   55                 char c;
   56 
   57                 if (unlikely(__get_user(c,src+res)))
   58                         return -EFAULT;
   59                 dst[res] = c;
   60                 if (!c)
   61                         return res;
   62                 res++;
   63                 max--;
   64         }
   65 
   66         /*
   67          * Uhhuh. We hit 'max'. But was that the user-specified maximum
   68          * too? If so, that's ok - we got as much as the user asked for.
   69          */
   70         if (res >= count)
   71                 return res;
   72 
   73         /*
   74          * Nope: we hit the address space limit, and we still had more
   75          * characters the caller would have wanted. That's an EFAULT.
   76          */
   77         return -EFAULT;
   78 }
   79 
   80 /**
   81  * strncpy_from_user: - Copy a NUL terminated string from userspace.
   82  * @dst:   Destination address, in kernel space.  This buffer must be at
   83  *         least @count bytes long.
   84  * @src:   Source address, in user space.
   85  * @count: Maximum number of bytes to copy, including the trailing NUL.
   86  *
   87  * Copies a NUL-terminated string from userspace to kernel space.
   88  *
   89  * On success, returns the length of the string (not including the trailing
   90  * NUL).
   91  *
   92  * If access to userspace fails, returns -EFAULT (some data may have been
   93  * copied).
   94  *
   95  * If @count is smaller than the length of the string, copies @count bytes
   96  * and returns @count.
   97  */
   98 long strncpy_from_user(char *dst, const char __user *src, long count)
   99 {
  100         unsigned long max_addr, src_addr;
  101 
  102         if (unlikely(count <= 0))
  103                 return 0;
  104 
  105         max_addr = user_addr_max();
  106         src_addr = (unsigned long)src;
  107         if (likely(src_addr < max_addr)) {
  108                 unsigned long max = max_addr - src_addr;
  109                 return do_strncpy_from_user(dst, src, count, max);
  110         }
  111         return -EFAULT;
  112 }
  113 EXPORT_SYMBOL(strncpy_from_user);

Cache object: 1c1ae770842dd9e348e3abb1b86914ac


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.