hc
2023-12-08 01573e231f18eb2d99162747186f59511f56b64d
kernel/lib/strncpy_from_user.c
....@@ -1,6 +1,7 @@
11 // SPDX-License-Identifier: GPL-2.0
22 #include <linux/compiler.h>
33 #include <linux/export.h>
4
+#include <linux/fault-inject-usercopy.h>
45 #include <linux/kasan-checks.h>
56 #include <linux/thread_info.h>
67 #include <linux/uaccess.h>
....@@ -34,17 +35,32 @@
3435 goto byte_at_a_time;
3536
3637 while (max >= sizeof(unsigned long)) {
37
- unsigned long c, data;
38
+ unsigned long c, data, mask;
3839
3940 /* Fall back to byte-at-a-time if we get a page fault */
4041 unsafe_get_user(c, (unsigned long __user *)(src+res), byte_at_a_time);
4142
42
- *(unsigned long *)(dst+res) = c;
43
+ /*
44
+ * Note that we mask out the bytes following the NUL. This is
45
+ * important to do because string oblivious code may read past
46
+ * the NUL. For those routines, we don't want to give them
47
+ * potentially random bytes after the NUL in `src`.
48
+ *
49
+ * One example of such code is BPF map keys. BPF treats map keys
50
+ * as an opaque set of bytes. Without the post-NUL mask, any BPF
51
+ * maps keyed by strings returned from strncpy_from_user() may
52
+ * have multiple entries for semantically identical strings.
53
+ */
4354 if (has_zero(c, &data, &constants)) {
4455 data = prep_zero_mask(c, data, &constants);
4556 data = create_zero_mask(data);
57
+ mask = zero_bytemask(data);
58
+ *(unsigned long *)(dst+res) = c & mask;
4659 return res + find_zero(data);
4760 }
61
+
62
+ *(unsigned long *)(dst+res) = c;
63
+
4864 res += sizeof(unsigned long);
4965 max -= sizeof(unsigned long);
5066 }
....@@ -98,6 +114,9 @@
98114 {
99115 unsigned long max_addr, src_addr;
100116
117
+ might_fault();
118
+ if (should_fail_usercopy())
119
+ return -EFAULT;
101120 if (unlikely(count <= 0))
102121 return 0;
103122
....@@ -116,9 +135,9 @@
116135
117136 kasan_check_write(dst, count);
118137 check_object_size(dst, count, false);
119
- if (user_access_begin(VERIFY_READ, src, max)) {
138
+ if (user_read_access_begin(src, max)) {
120139 retval = do_strncpy_from_user(dst, src, count, max);
121
- user_access_end();
140
+ user_read_access_end();
122141 return retval;
123142 }
124143 }