History

make 'user_access_begin()' do 'access_ok()'

Originally, the rule used to be that you'd have to do access_ok() separately, and then user_access_begin() before actually doing the direct (optimized) user access. But experience has shown that people then decide not to do access_ok() at all, and instead rely on it being implied by other operations or similar. Which makes it very hard to verify that the access has actually been range-checked. If you use the unsafe direct user accesses, hardware features (either SMAP - Supervisor Mode Access Protection - on x86, or PAN - Privileged Access Never - on ARM) do force you to use user_access_begin(). But nothing really forces the range check. By putting the range check into user_access_begin(), we actually force people to do the right thing (tm), and the range check vill be visible near the actual accesses. We have way too long a history of people trying to avoid them.

Linus Torvalds committed 7 years ago

Commit 594cc251 parent 0b2c8f87 files · +36 −20Browse files

Unified · Split

7 files
  1. arch/x86/include/asm/uaccess.h +8 −1
  2. drivers/gpu/drm/i915/i915_gem_execbuffer.c +13 −2
  3. include/linux/uaccess.h +1 −1
  4. kernel/compat.c +2 −4
  5. kernel/exit.c +2 −4
  6. lib/strncpy_from_user.c +5 −4
  7. lib/strnlen_user.c +5 −4
arch/x86/include/asm/uaccess.h+8−1
@@ -705,7 +705,14 @@ extern struct movsl_mask { · 704 unmodified lines
705705 * checking before using them, but you have to surround them with the
706706 * user_access_begin/end() pair.
707707 */
708−#define user_access_begin() __uaccess_begin()
708+static __must_check inline bool user_access_begin(const void __user *ptr, size_t len)
709+{
710+ if (unlikely(!access_ok(ptr,len)))
711+ return 0;
712+ __uaccess_begin();
713+ return 1;
714+}
715+#define user_access_begin(a,b) user_access_begin(a,b)
709716 #define user_access_end() __uaccess_end()
710717
711718 #define unsafe_put_user(x, ptr, err_label) \
drivers/gpu/drm/i915/i915_gem_execbuffer.c+13−2
@@ -1624,7 +1624,9 @@ end_user: · 1623 unmodified lines
16241624 * happened we would make the mistake of assuming that the
16251625 * relocations were valid.
16261626 */
1627− user_access_begin();
1627+ if (!user_access_begin(urelocs, size))
1628+ goto end_user;
1629+
16281630 for (copied = 0; copied < nreloc; copied++)
16291631 unsafe_put_user(-1,
16301632 &urelocs[copied].presumed_offset,
@@ -2606,7 +2608,16 @@ i915_gem_execbuffer2_ioctl(struct drm_device *dev, void *data, · 975 unmodified lines
26062608 unsigned int i;
26072609
26082610 /* Copy the new buffer offsets back to the user's exec list. */
2609− user_access_begin();
2611+ /*
2612+ * Note: count * sizeof(*user_exec_list) does not overflow,
2613+ * because we checked 'count' in check_buffer_count().
2614+ *
2615+ * And this range already got effectively checked earlier
2616+ * when we did the "copy_from_user()" above.
2617+ */
2618+ if (!user_access_begin(user_exec_list, count * sizeof(*user_exec_list)))
2619+ goto end_user;
2620+
26102621 for (i = 0; i < args->buffer_count; i++) {
26112622 if (!(exec2_list[i].offset & UPDATE))
26122623 continue;
include/linux/uaccess.h+1−1
@@ -264,7 +264,7 @@ extern long strncpy_from_unsafe(char *dst, const void *unsafe_addr, long count); · 263 unmodified lines
264264 probe_kernel_read(&retval, addr, sizeof(retval))
265265
266266 #ifndef user_access_begin
267−#define user_access_begin() do { } while (0)
267+#define user_access_begin(ptr,len) access_ok(ptr, len)
268268 #define user_access_end() do { } while (0)
269269 #define unsafe_get_user(x, ptr, err) do { if (unlikely(__get_user(x, ptr))) goto err; } while (0)
270270 #define unsafe_put_user(x, ptr, err) do { if (unlikely(__put_user(x, ptr))) goto err; } while (0)
kernel/compat.c+2−4
@@ -354,10 +354,9 @@ long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask, · 353 unmodified lines
354354 bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG);
355355 nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
356356
357− if (!access_ok(umask, bitmap_size / 8))
357+ if (!user_access_begin(umask, bitmap_size / 8))
358358 return -EFAULT;
359359
360− user_access_begin();
361360 while (nr_compat_longs > 1) {
362361 compat_ulong_t l1, l2;
363362 unsafe_get_user(l1, umask++, Efault);
@@ -384,10 +383,9 @@ long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask, · 20 unmodified lines
384383 bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG);
385384 nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
386385
387− if (!access_ok(umask, bitmap_size / 8))
386+ if (!user_access_begin(umask, bitmap_size / 8))
388387 return -EFAULT;
389388
390− user_access_begin();
391389 while (nr_compat_longs > 1) {
392390 unsigned long m = *mask++;
393391 unsafe_put_user((compat_ulong_t)m, umask++, Efault);
kernel/exit.c+2−4
@@ -1604,10 +1604,9 @@ SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *, · 1603 unmodified lines
16041604 if (!infop)
16051605 return err;
16061606
1607− if (!access_ok(infop, sizeof(*infop)))
1607+ if (!user_access_begin(infop, sizeof(*infop)))
16081608 return -EFAULT;
16091609
1610− user_access_begin();
16111610 unsafe_put_user(signo, &infop->si_signo, Efault);
16121611 unsafe_put_user(0, &infop->si_errno, Efault);
16131612 unsafe_put_user(info.cause, &infop->si_code, Efault);
@@ -1732,10 +1731,9 @@ COMPAT_SYSCALL_DEFINE5(waitid, · 118 unmodified lines
17321731 if (!infop)
17331732 return err;
17341733
1735− if (!access_ok(infop, sizeof(*infop)))
1734+ if (!user_access_begin(infop, sizeof(*infop)))
17361735 return -EFAULT;
17371736
1738− user_access_begin();
17391737 unsafe_put_user(signo, &infop->si_signo, Efault);
17401738 unsafe_put_user(0, &infop->si_errno, Efault);
17411739 unsafe_put_user(info.cause, &infop->si_code, Efault);
lib/strncpy_from_user.c+5−4
@@ -114,10 +114,11 @@ long strncpy_from_user(char *dst, const char __user *src, long count) · 113 unmodified lines
114114
115115 kasan_check_write(dst, count);
116116 check_object_size(dst, count, false);
117− user_access_begin();
118− retval = do_strncpy_from_user(dst, src, count, max);
119− user_access_end();
120− return retval;
117+ if (user_access_begin(src, max)) {
118+ retval = do_strncpy_from_user(dst, src, count, max);
119+ user_access_end();
120+ return retval;
121+ }
121122 }
122123 return -EFAULT;
123124 }
lib/strnlen_user.c+5−4
@@ -114,10 +114,11 @@ long strnlen_user(const char __user *str, long count) · 113 unmodified lines
114114 unsigned long max = max_addr - src_addr;
115115 long retval;
116116
117− user_access_begin();
118− retval = do_strnlen_user(str, count, max);
119− user_access_end();
120− return retval;
117+ if (user_access_begin(str, max)) {
118+ retval = do_strnlen_user(str, count, max);
119+ user_access_end();
120+ return retval;
121+ }
121122 }
122123 return 0;
123124 }