BACKPORT: 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. Bug 200630541 CVE-2018-20669 Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Change-Id: I1d25229cd41495b782e6f2bc67a4bb638dec4540 Reviewed-on: https://git-master.nvidia.com/r/c/linux-4.9/+/2374142 (cherry picked from commit e77a94059008f0f812474d05a9f75accecaeb583) Reviewed-on: https://git-master.nvidia.com/r/c/linux-4.9/+/2466485 Reviewed-by: Bibek Basu <bbasu@nvidia.com> Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> GVS: Gerrit_Virtual_Submit Tested-by: Amulya Yarlagadda <ayarlagadda@nvidia.com> Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
parent
3ee9a2b02a
commit
660716ee5f
3 changed files with 16 additions and 13 deletions
|
|
@ -141,7 +141,7 @@ extern long strnlen_unsafe_user(const void __user *unsafe_addr, long count);
|
|||
probe_kernel_read(&retval, addr, sizeof(retval))
|
||||
|
||||
#ifndef user_access_begin
|
||||
#define user_access_begin() do { } while (0)
|
||||
#define user_access_begin(ptr,len) access_ok(VERIFY_READ, ptr, len)
|
||||
#define user_access_end() do { } while (0)
|
||||
#define unsafe_get_user(x, ptr, err) do { if (unlikely(__get_user(x, ptr))) goto err; } while (0)
|
||||
#define unsafe_put_user(x, ptr, err) do { if (unlikely(__put_user(x, ptr))) goto err; } while (0)
|
||||
|
|
|
|||
|
|
@ -114,10 +114,11 @@ long strncpy_from_user(char *dst, const char __user *src, long count)
|
|||
|
||||
kasan_check_write(dst, count);
|
||||
check_object_size(dst, count, false);
|
||||
user_access_begin();
|
||||
retval = do_strncpy_from_user(dst, src, count, max);
|
||||
user_access_end();
|
||||
return retval;
|
||||
if (user_access_begin(src, max)) {
|
||||
retval = do_strncpy_from_user(dst, src, count, max);
|
||||
user_access_end();
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
return -EFAULT;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,10 +113,11 @@ long strnlen_user(const char __user *str, long count)
|
|||
unsigned long max = max_addr - src_addr;
|
||||
long retval;
|
||||
|
||||
user_access_begin();
|
||||
retval = do_strnlen_user(str, count, max);
|
||||
user_access_end();
|
||||
return retval;
|
||||
if (user_access_begin(str, max)) {
|
||||
retval = do_strnlen_user(str, count, max);
|
||||
user_access_end();
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -147,10 +148,11 @@ long strlen_user(const char __user *str)
|
|||
unsigned long max = max_addr - src_addr;
|
||||
long retval;
|
||||
|
||||
user_access_begin();
|
||||
retval = do_strnlen_user(str, ~0ul, max);
|
||||
user_access_end();
|
||||
return retval;
|
||||
if (user_access_begin(str, max)) {
|
||||
retval = do_strnlen_user(str, ~0ul, max);
|
||||
user_access_end();
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue