~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/lib/strnlen_user.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 #include <linux/kernel.h>
  3 #include <linux/export.h>
  4 #include <linux/uaccess.h>
  5 #include <linux/mm.h>
  6 #include <linux/bitops.h>
  7 
  8 #include <asm/word-at-a-time.h>
  9 
 10 /*
 11  * Do a strnlen, return length of string *with* final '\0'.
 12  * 'count' is the user-supplied count, while 'max' is the
 13  * address space maximum.
 14  *
 15  * Return 0 for exceptions (which includes hitting the address
 16  * space maximum), or 'count+1' if hitting the user-supplied
 17  * maximum count.
 18  *
 19  * NOTE! We can sometimes overshoot the user-supplied maximum
 20  * if it fits in a aligned 'long'. The caller needs to check
 21  * the return value against "> max".
 22  */
 23 static __always_inline long do_strnlen_user(const char __user *src, unsigned long count, unsigned long max)
 24 {
 25         const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
 26         unsigned long align, res = 0;
 27         unsigned long c;
 28 
 29         /*
 30          * Do everything aligned. But that means that we
 31          * need to also expand the maximum..
 32          */
 33         align = (sizeof(unsigned long) - 1) & (unsigned long)src;
 34         src -= align;
 35         max += align;
 36 
 37         unsafe_get_user(c, (unsigned long __user *)src, efault);
 38         c |= aligned_byte_mask(align);
 39 
 40         for (;;) {
 41                 unsigned long data;
 42                 if (has_zero(c, &data, &constants)) {
 43                         data = prep_zero_mask(c, data, &constants);
 44                         data = create_zero_mask(data);
 45                         return res + find_zero(data) + 1 - align;
 46                 }
 47                 res += sizeof(unsigned long);
 48                 /* We already handled 'unsigned long' bytes. Did we do it all ? */
 49                 if (unlikely(max <= sizeof(unsigned long)))
 50                         break;
 51                 max -= sizeof(unsigned long);
 52                 unsafe_get_user(c, (unsigned long __user *)(src+res), efault);
 53         }
 54         res -= align;
 55 
 56         /*
 57          * Uhhuh. We hit 'max'. But was that the user-specified maximum
 58          * too? If so, return the marker for "too long".
 59          */
 60         if (res >= count)
 61                 return count+1;
 62 
 63         /*
 64          * Nope: we hit the address space limit, and we still had more
 65          * characters the caller would have wanted. That's 0.
 66          */
 67 efault:
 68         return 0;
 69 }
 70 
 71 /**
 72  * strnlen_user: - Get the size of a user string INCLUDING final NUL.
 73  * @str: The string to measure.
 74  * @count: Maximum count (including NUL character)
 75  *
 76  * Context: User context only. This function may sleep if pagefaults are
 77  *          enabled.
 78  *
 79  * Get the size of a NUL-terminated string in user space.
 80  *
 81  * Returns the size of the string INCLUDING the terminating NUL.
 82  * If the string is too long, returns a number larger than @count. User
 83  * has to check the return value against "> count".
 84  * On exception (or invalid count), returns 0.
 85  *
 86  * NOTE! You should basically never use this function. There is
 87  * almost never any valid case for using the length of a user space
 88  * string, since the string can be changed at any time by other
 89  * threads. Use "strncpy_from_user()" instead to get a stable copy
 90  * of the string.
 91  */
 92 long strnlen_user(const char __user *str, long count)
 93 {
 94         unsigned long max_addr, src_addr;
 95 
 96         if (unlikely(count <= 0))
 97                 return 0;
 98 
 99         max_addr = TASK_SIZE_MAX;
100         src_addr = (unsigned long)untagged_addr(str);
101         if (likely(src_addr < max_addr)) {
102                 unsigned long max = max_addr - src_addr;
103                 long retval;
104 
105                 /*
106                  * Truncate 'max' to the user-specified limit, so that
107                  * we only have one limit we need to check in the loop
108                  */
109                 if (max > count)
110                         max = count;
111 
112                 if (user_read_access_begin(str, max)) {
113                         retval = do_strnlen_user(str, count, max);
114                         user_read_access_end();
115                         return retval;
116                 }
117         }
118         return 0;
119 }
120 EXPORT_SYMBOL(strnlen_user);
121 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php