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