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
705 * checking before using them, but you have to surround them with the705 * checking before using them, but you have to surround them with the
706 * user_access_begin/end() pair.706 * user_access_begin/end() pair.
707 */707 */
708#define user_access_begin() __uaccess_begin()708static __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)
709#define user_access_end() __uaccess_end()716#define user_access_end() __uaccess_end()
710 717
711#define unsafe_put_user(x, ptr, err_label) \718#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
1624 * happened we would make the mistake of assuming that the1624 * happened we would make the mistake of assuming that the
1625 * relocations were valid.1625 * relocations were valid.
1626 */1626 */
1627 user_access_begin();1627 if (!user_access_begin(urelocs, size))
1628 goto end_user;
1629
1628 for (copied = 0; copied < nreloc; copied++)1630 for (copied = 0; copied < nreloc; copied++)
1629 unsafe_put_user(-1,1631 unsafe_put_user(-1,
1630 &urelocs[copied].presumed_offset,1632 &urelocs[copied].presumed_offset,
@@ -2606,7 +2608,16 @@ i915_gem_execbuffer2_ioctl(struct drm_device *dev, void *data, · 975 unmodified lines
2606 unsigned int i;2608 unsigned int i;
2607 2609
2608 /* Copy the new buffer offsets back to the user's exec list. */2610 /* 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
2610 for (i = 0; i < args->buffer_count; i++) {2621 for (i = 0; i < args->buffer_count; i++) {
2611 if (!(exec2_list[i].offset & UPDATE))2622 if (!(exec2_list[i].offset & UPDATE))
2612 continue;2623 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
264 probe_kernel_read(&retval, addr, sizeof(retval))264 probe_kernel_read(&retval, addr, sizeof(retval))
265 265
266#ifndef user_access_begin266#ifndef user_access_begin
267#define user_access_begin() do { } while (0)267#define user_access_begin(ptr,len) access_ok(ptr, len)
268#define user_access_end() do { } while (0)268#define user_access_end() do { } while (0)
269#define unsafe_get_user(x, ptr, err) do { if (unlikely(__get_user(x, ptr))) goto err; } while (0)269#define unsafe_get_user(x, ptr, err) do { if (unlikely(__get_user(x, ptr))) goto err; } while (0)
270#define unsafe_put_user(x, ptr, err) do { if (unlikely(__put_user(x, ptr))) goto err; } while (0)270#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
354 bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG);354 bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG);
355 nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);355 nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
356 356
357 if (!access_ok(umask, bitmap_size / 8))357 if (!user_access_begin(umask, bitmap_size / 8))
358 return -EFAULT;358 return -EFAULT;
359 359
360 user_access_begin();
361 while (nr_compat_longs > 1) {360 while (nr_compat_longs > 1) {
362 compat_ulong_t l1, l2;361 compat_ulong_t l1, l2;
363 unsafe_get_user(l1, umask++, Efault);362 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
384 bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG);383 bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG);
385 nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);384 nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
386 385
387 if (!access_ok(umask, bitmap_size / 8))386 if (!user_access_begin(umask, bitmap_size / 8))
388 return -EFAULT;387 return -EFAULT;
389 388
390 user_access_begin();
391 while (nr_compat_longs > 1) {389 while (nr_compat_longs > 1) {
392 unsigned long m = *mask++;390 unsigned long m = *mask++;
393 unsafe_put_user((compat_ulong_t)m, umask++, Efault);391 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
1604 if (!infop)1604 if (!infop)
1605 return err;1605 return err;
1606 1606
1607 if (!access_ok(infop, sizeof(*infop)))1607 if (!user_access_begin(infop, sizeof(*infop)))
1608 return -EFAULT;1608 return -EFAULT;
1609 1609
1610 user_access_begin();
1611 unsafe_put_user(signo, &infop->si_signo, Efault);1610 unsafe_put_user(signo, &infop->si_signo, Efault);
1612 unsafe_put_user(0, &infop->si_errno, Efault);1611 unsafe_put_user(0, &infop->si_errno, Efault);
1613 unsafe_put_user(info.cause, &infop->si_code, Efault);1612 unsafe_put_user(info.cause, &infop->si_code, Efault);
@@ -1732,10 +1731,9 @@ COMPAT_SYSCALL_DEFINE5(waitid, · 118 unmodified lines
1732 if (!infop)1731 if (!infop)
1733 return err;1732 return err;
1734 1733
1735 if (!access_ok(infop, sizeof(*infop)))1734 if (!user_access_begin(infop, sizeof(*infop)))
1736 return -EFAULT;1735 return -EFAULT;
1737 1736
1738 user_access_begin();
1739 unsafe_put_user(signo, &infop->si_signo, Efault);1737 unsafe_put_user(signo, &infop->si_signo, Efault);
1740 unsafe_put_user(0, &infop->si_errno, Efault);1738 unsafe_put_user(0, &infop->si_errno, Efault);
1741 unsafe_put_user(info.cause, &infop->si_code, Efault);1739 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
114 114
115 kasan_check_write(dst, count);115 kasan_check_write(dst, count);
116 check_object_size(dst, count, false);116 check_object_size(dst, count, false);
117 user_access_begin();117 if (user_access_begin(src, max)) {
118 retval = do_strncpy_from_user(dst, src, count, max);118 retval = do_strncpy_from_user(dst, src, count, max);
119 user_access_end();119 user_access_end();
120 return retval;120 return retval;
121 }
121 }122 }
122 return -EFAULT;123 return -EFAULT;
123}124}
lib/strnlen_user.c+5−4
@@ -114,10 +114,11 @@ long strnlen_user(const char __user *str, long count) · 113 unmodified lines
114 unsigned long max = max_addr - src_addr;114 unsigned long max = max_addr - src_addr;
115 long retval;115 long retval;
116 116
117 user_access_begin();117 if (user_access_begin(str, max)) {
118 retval = do_strnlen_user(str, count, max);118 retval = do_strnlen_user(str, count, max);
119 user_access_end();119 user_access_end();
120 return retval;120 return retval;
121 }
121 }122 }
122 return 0;123 return 0;
123}124}