Line data Source code
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 77071 : 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 77071 : align = (sizeof(long) - 1) & (unsigned long)src;
45 77071 : src -= align;
46 77071 : max += align;
47 :
48 77071 : if (unlikely(__get_user(c,(unsigned long __user *)src)))
49 : return 0;
50 77071 : c |= aligned_byte_mask(align);
51 :
52 : for (;;) {
53 : unsigned long data;
54 472826 : if (has_zero(c, &data, &constants)) {
55 : data = prep_zero_mask(c, data, &constants);
56 : data = create_zero_mask(data);
57 77071 : return res + find_zero(data) + 1 - align;
58 : }
59 395755 : res += sizeof(unsigned long);
60 395755 : if (unlikely(max < sizeof(unsigned long)))
61 : break;
62 395755 : max -= sizeof(unsigned long);
63 395755 : if (unlikely(__get_user(c,(unsigned long __user *)(src+res))))
64 : return 0;
65 : }
66 0 : 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 0 : if (res >= count)
73 0 : 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 77071 : long strnlen_user(const char __user *str, long count)
96 : {
97 : unsigned long max_addr, src_addr;
98 :
99 77071 : if (unlikely(count <= 0))
100 : return 0;
101 :
102 77071 : max_addr = user_addr_max();
103 77071 : src_addr = (unsigned long)str;
104 77071 : if (likely(src_addr < max_addr)) {
105 77071 : unsigned long max = max_addr - src_addr;
106 154142 : 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 0 : long strlen_user(const char __user *str)
127 : {
128 : unsigned long max_addr, src_addr;
129 :
130 0 : max_addr = user_addr_max();
131 0 : src_addr = (unsigned long)str;
132 0 : if (likely(src_addr < max_addr)) {
133 0 : unsigned long max = max_addr - src_addr;
134 0 : return do_strnlen_user(str, ~0ul, max);
135 : }
136 : return 0;
137 : }
138 : EXPORT_SYMBOL(strlen_user);
|