Add 'unsafe' user access functions for batched accesses
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 17 Dec 2015 17:57:27 +0000 (09:57 -0800)
committerAlex Shi <alex.shi@linaro.org>
Sat, 27 Aug 2016 03:23:38 +0000 (11:23 +0800)
The naming is meant to discourage random use: the helper functions are
not really any more "unsafe" than the traditional double-underscore
functions (which need the address range checking), but they do need even
more infrastructure around them, and should not be used willy-nilly.

In addition to checking the access range, these user access functions
require that you wrap the user access with a "user_acess_{begin,end}()"
around it.

That allows architectures that implement kernel user access control
(x86: SMAP, arm64: PAN) to do the user access control in the wrapping
user_access_begin/end part, and then batch up the actual user space
accesses using the new interfaces.

The main (and hopefully only) use for these are for core generic access
helpers, initially just the generic user string functions
(strnlen_user() and strncpy_from_user()).

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
(cherry picked from commit 5b24a7a2aa2040c8c50c3b71122901d01661ff78)
Signed-off-by: Alex Shi <alex.shi@linaro.org>
arch/x86/include/asm/uaccess.h
include/linux/uaccess.h

index cc228f4713da8153cb3f0322cd6fe6db87d08fae..ca59e4f9254eaef6e75484b86a3c7563bfb659e3 100644 (file)
@@ -762,5 +762,30 @@ copy_to_user(void __user *to, const void *from, unsigned long n)
 #undef __copy_from_user_overflow
 #undef __copy_to_user_overflow
 
+/*
+ * The "unsafe" user accesses aren't really "unsafe", but the naming
+ * is a big fat warning: you have to not only do the access_ok()
+ * checking before using them, but you have to surround them with the
+ * user_access_begin/end() pair.
+ */
+#define user_access_begin()    __uaccess_begin()
+#define user_access_end()      __uaccess_end()
+
+#define unsafe_put_user(x, ptr)                                                \
+({                                                                             \
+       int __pu_err;                                                           \
+       __put_user_size((x), (ptr), sizeof(*(ptr)), __pu_err, -EFAULT);         \
+       __builtin_expect(__pu_err, 0);                                          \
+})
+
+#define unsafe_get_user(x, ptr)                                                \
+({                                                                             \
+       int __gu_err;                                                           \
+       unsigned long __gu_val;                                                 \
+       __get_user_size(__gu_val, (ptr), sizeof(*(ptr)), __gu_err, -EFAULT);    \
+       (x) = (__force __typeof__(*(ptr)))__gu_val;                             \
+       __builtin_expect(__gu_err, 0);                                          \
+})
+
 #endif /* _ASM_X86_UACCESS_H */
 
index 558129af828a7eb97ad64b1531ac2a4e3f71174d..349557825428e9b3d815e0bc2781d5d79b172d47 100644 (file)
@@ -111,4 +111,11 @@ extern long strncpy_from_unsafe(char *dst, const void *unsafe_addr, long count);
 #define probe_kernel_address(addr, retval)             \
        probe_kernel_read(&retval, addr, sizeof(retval))
 
+#ifndef user_access_begin
+#define user_access_begin() do { } while (0)
+#define user_access_end() do { } while (0)
+#define unsafe_get_user(x, ptr) __get_user(x, ptr)
+#define unsafe_put_user(x, ptr) __put_user(x, ptr)
+#endif
+
 #endif         /* __LINUX_UACCESS_H__ */