Skip to content

Commit

Permalink
x86/kasan: instrument user memory access API
Browse files Browse the repository at this point in the history
Exchange between user and kernel memory is coded in assembly language.
Which means that such accesses won't be spotted by KASAN as a compiler
instruments only C code.

Add explicit KASAN checks to user memory access API to ensure that
userspace writes to (or reads from) a valid kernel memory.

Note: Unlike others strncpy_from_user() is written mostly in C and KASAN
sees memory accesses in it.  However, it makes sense to add explicit
check for all @count bytes that *potentially* could be written to the
kernel.

[[email protected]: move kasan check under the condition]
  Link: http://lkml.kernel.org/r/[email protected]
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Andrey Ryabinin <[email protected]>
Cc: Alexander Potapenko <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: "H. Peter Anvin" <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
aryabinin authored and torvalds committed May 21, 2016
1 parent 64f8eba commit 1771c6e
Show file tree
Hide file tree
Showing 3 changed files with 14 additions and 0 deletions.
5 changes: 5 additions & 0 deletions arch/x86/include/asm/uaccess.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/
#include <linux/errno.h>
#include <linux/compiler.h>
#include <linux/kasan-checks.h>
#include <linux/thread_info.h>
#include <linux/string.h>
#include <asm/asm.h>
Expand Down Expand Up @@ -721,6 +722,8 @@ copy_from_user(void *to, const void __user *from, unsigned long n)

might_fault();

kasan_check_write(to, n);

/*
* While we would like to have the compiler do the checking for us
* even in the non-constant size case, any false positives there are
Expand Down Expand Up @@ -754,6 +757,8 @@ copy_to_user(void __user *to, const void *from, unsigned long n)
{
int sz = __compiletime_object_size(from);

kasan_check_read(from, n);

might_fault();

/* See the comment in copy_from_user() above. */
Expand Down
7 changes: 7 additions & 0 deletions arch/x86/include/asm/uaccess_64.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <linux/compiler.h>
#include <linux/errno.h>
#include <linux/lockdep.h>
#include <linux/kasan-checks.h>
#include <asm/alternative.h>
#include <asm/cpufeatures.h>
#include <asm/page.h>
Expand Down Expand Up @@ -109,6 +110,7 @@ static __always_inline __must_check
int __copy_from_user(void *dst, const void __user *src, unsigned size)
{
might_fault();
kasan_check_write(dst, size);
return __copy_from_user_nocheck(dst, src, size);
}

Expand Down Expand Up @@ -175,6 +177,7 @@ static __always_inline __must_check
int __copy_to_user(void __user *dst, const void *src, unsigned size)
{
might_fault();
kasan_check_read(src, size);
return __copy_to_user_nocheck(dst, src, size);
}

Expand Down Expand Up @@ -242,12 +245,14 @@ int __copy_in_user(void __user *dst, const void __user *src, unsigned size)
static __must_check __always_inline int
__copy_from_user_inatomic(void *dst, const void __user *src, unsigned size)
{
kasan_check_write(dst, size);
return __copy_from_user_nocheck(dst, src, size);
}

static __must_check __always_inline int
__copy_to_user_inatomic(void __user *dst, const void *src, unsigned size)
{
kasan_check_read(src, size);
return __copy_to_user_nocheck(dst, src, size);
}

Expand All @@ -258,13 +263,15 @@ static inline int
__copy_from_user_nocache(void *dst, const void __user *src, unsigned size)
{
might_fault();
kasan_check_write(dst, size);
return __copy_user_nocache(dst, src, size, 1);
}

static inline int
__copy_from_user_inatomic_nocache(void *dst, const void __user *src,
unsigned size)
{
kasan_check_write(dst, size);
return __copy_user_nocache(dst, src, size, 0);
}

Expand Down
2 changes: 2 additions & 0 deletions lib/strncpy_from_user.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <linux/compiler.h>
#include <linux/export.h>
#include <linux/kasan-checks.h>
#include <linux/uaccess.h>
#include <linux/kernel.h>
#include <linux/errno.h>
Expand Down Expand Up @@ -109,6 +110,7 @@ long strncpy_from_user(char *dst, const char __user *src, long count)
unsigned long max = max_addr - src_addr;
long retval;

kasan_check_write(dst, count);
user_access_begin();
retval = do_strncpy_from_user(dst, src, count, max);
user_access_end();
Expand Down

0 comments on commit 1771c6e

Please sign in to comment.