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/strnlen_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/kernel.h>
    2 #include <linux/export.h>
    3 #include <linux/uaccess.h>
    4 
    5 #include <asm/word-at-a-time.h>
    6 
    7 /* Set bits in the first 'n' bytes when loaded from memory */
    8 #ifdef __LITTLE_ENDIAN
    9 #  define aligned_byte_mask(n) ((1ul << 8*(n))-1)
   10 #else
   11 #  define aligned_byte_mask(n) (~0xfful << (BITS_PER_LONG - 8 - 8*(n)))
   12 #endif
   13 
   14 /*
   15  * Do a strnlen, return length of string *with* final '\0'.
   16  * 'count' is the user-supplied count, while 'max' is the
   17  * address space maximum.
   18  *
   19  * Return 0 for exceptions (which includes hitting the address
   20  * space maximum), or 'count+1' if hitting the user-supplied
   21  * maximum count.
   22  *
   23  * NOTE! We can sometimes overshoot the user-supplied maximum
   24  * if it fits in a aligned 'long'. The caller needs to check
   25  * the return value against "> max".
   26  */
   27 static inline long do_strnlen_user(const char __user *src, unsigned long count, unsigned long max)
   28 {
   29         const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
   30         long align, res = 0;
   31         unsigned long c;
   32 
   33         /*
   34          * Truncate 'max' to the user-specified limit, so that
   35          * we only have one limit we need to check in the loop
   36          */
   37         if (max > count)
   38                 max = count;
   39 
   40         /*
   41          * Do everything aligned. But that means that we
   42          * need to also expand the maximum..
   43          */
   44         align = (sizeof(long) - 1) & (unsigned long)src;
   45         src -= align;
   46         max += align;
   47 
   48         if (unlikely(__get_user(c,(unsigned long __user *)src)))
   49                 return 0;
   50         c |= aligned_byte_mask(align);
   51 
   52         for (;;) {
   53                 unsigned long data;
   54                 if (has_zero(c, &data, &constants)) {
   55                         data = prep_zero_mask(c, data, &constants);
   56                         data = create_zero_mask(data);
   57                         return res + find_zero(data) + 1 - align;
   58                 }
   59                 res += sizeof(unsigned long);
   60                 if (unlikely(max < sizeof(unsigned long)))
   61                         break;
   62                 max -= sizeof(unsigned long);
   63                 if (unlikely(__get_user(c,(unsigned long __user *)(src+res))))
   64                         return 0;
   65         }
   66         res -= align;
   67 
   68         /*
   69          * Uhhuh. We hit 'max'. But was that the user-specified maximum
   70          * too? If so, return the marker for "too long".
   71          */
   72         if (res >= count)
   73                 return count+1;
   74 
   75         /*
   76          * Nope: we hit the address space limit, and we still had more
   77          * characters the caller would have wanted. That's 0.
   78          */
   79         return 0;
   80 }
   81 
   82 /**
   83  * strnlen_user: - Get the size of a user string INCLUDING final NUL.
   84  * @str: The string to measure.
   85  * @count: Maximum count (including NUL character)
   86  *
   87  * Context: User context only.  This function may sleep.
   88  *
   89  * Get the size of a NUL-terminated string in user space.
   90  *
   91  * Returns the size of the string INCLUDING the terminating NUL.
   92  * If the string is too long, returns 'count+1'.
   93  * On exception (or invalid count), returns 0.
   94  */
   95 long strnlen_user(const char __user *str, long count)
   96 {
   97         unsigned long max_addr, src_addr;
   98 
   99         if (unlikely(count <= 0))
  100                 return 0;
  101 
  102         max_addr = user_addr_max();
  103         src_addr = (unsigned long)str;
  104         if (likely(src_addr < max_addr)) {
  105                 unsigned long max = max_addr - src_addr;
  106                 return do_strnlen_user(str, count, max);
  107         }
  108         return 0;
  109 }
  110 EXPORT_SYMBOL(strnlen_user);
  111 
  112 /**
  113  * strlen_user: - Get the size of a user string INCLUDING final NUL.
  114  * @str: The string to measure.
  115  *
  116  * Context: User context only.  This function may sleep.
  117  *
  118  * Get the size of a NUL-terminated string in user space.
  119  *
  120  * Returns the size of the string INCLUDING the terminating NUL.
  121  * On exception, returns 0.
  122  *
  123  * If there is a limit on the length of a valid string, you may wish to
  124  * consider using strnlen_user() instead.
  125  */
  126 long strlen_user(const char __user *str)
  127 {
  128         unsigned long max_addr, src_addr;
  129 
  130         max_addr = user_addr_max();
  131         src_addr = (unsigned long)str;
  132         if (likely(src_addr < max_addr)) {
  133                 unsigned long max = max_addr - src_addr;
  134                 return do_strnlen_user(str, ~0ul, max);
  135         }
  136         return 0;
  137 }
  138 EXPORT_SYMBOL(strlen_user);

Cache object: a59a57861c06293d4a72b75eb1a62416


[ 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.