These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / arch / arm / include / asm / uaccess.h
index 74b17d0..35c9db8 100644 (file)
@@ -49,6 +49,35 @@ struct exception_table_entry
 
 extern int fixup_exception(struct pt_regs *regs);
 
+/*
+ * These two functions allow hooking accesses to userspace to increase
+ * system integrity by ensuring that the kernel can not inadvertantly
+ * perform such accesses (eg, via list poison values) which could then
+ * be exploited for priviledge escalation.
+ */
+static inline unsigned int uaccess_save_and_enable(void)
+{
+#ifdef CONFIG_CPU_SW_DOMAIN_PAN
+       unsigned int old_domain = get_domain();
+
+       /* Set the current domain access to permit user accesses */
+       set_domain((old_domain & ~domain_mask(DOMAIN_USER)) |
+                  domain_val(DOMAIN_USER, DOMAIN_CLIENT));
+
+       return old_domain;
+#else
+       return 0;
+#endif
+}
+
+static inline void uaccess_restore(unsigned int flags)
+{
+#ifdef CONFIG_CPU_SW_DOMAIN_PAN
+       /* Restore the user access mask */
+       set_domain(flags);
+#endif
+}
+
 /*
  * These two are intentionally not defined anywhere - if the kernel
  * code generates any references to them, that's a bug.
@@ -165,6 +194,7 @@ extern int __get_user_64t_4(void *);
                register typeof(x) __r2 asm("r2");                      \
                register unsigned long __l asm("r1") = __limit;         \
                register int __e asm("r0");                             \
+               unsigned int __ua_flags = uaccess_save_and_enable();    \
                switch (sizeof(*(__p))) {                               \
                case 1:                                                 \
                        if (sizeof((x)) >= 8)                           \
@@ -192,6 +222,7 @@ extern int __get_user_64t_4(void *);
                        break;                                          \
                default: __e = __get_user_bad(); break;                 \
                }                                                       \
+               uaccess_restore(__ua_flags);                            \
                x = (typeof(*(p))) __r2;                                \
                __e;                                                    \
        })
@@ -224,6 +255,7 @@ extern int __put_user_8(void *, unsigned long long);
                register const typeof(*(p)) __user *__p asm("r0") = __tmp_p; \
                register unsigned long __l asm("r1") = __limit;         \
                register int __e asm("r0");                             \
+               unsigned int __ua_flags = uaccess_save_and_enable();    \
                switch (sizeof(*(__p))) {                               \
                case 1:                                                 \
                        __put_user_x(__r2, __p, __e, __l, 1);           \
@@ -239,6 +271,7 @@ extern int __put_user_8(void *, unsigned long long);
                        break;                                          \
                default: __e = __put_user_bad(); break;                 \
                }                                                       \
+               uaccess_restore(__ua_flags);                            \
                __e;                                                    \
        })
 
@@ -300,20 +333,23 @@ static inline void set_fs(mm_segment_t fs)
 do {                                                                   \
        unsigned long __gu_addr = (unsigned long)(ptr);                 \
        unsigned long __gu_val;                                         \
+       unsigned int __ua_flags;                                        \
        __chk_user_ptr(ptr);                                            \
        might_fault();                                                  \
+       __ua_flags = uaccess_save_and_enable();                         \
        switch (sizeof(*(ptr))) {                                       \
        case 1: __get_user_asm_byte(__gu_val, __gu_addr, err);  break;  \
        case 2: __get_user_asm_half(__gu_val, __gu_addr, err);  break;  \
        case 4: __get_user_asm_word(__gu_val, __gu_addr, err);  break;  \
        default: (__gu_val) = __get_user_bad();                         \
        }                                                               \
+       uaccess_restore(__ua_flags);                                    \
        (x) = (__typeof__(*(ptr)))__gu_val;                             \
 } while (0)
 
-#define __get_user_asm_byte(x, addr, err)                      \
+#define __get_user_asm(x, addr, err, instr)                    \
        __asm__ __volatile__(                                   \
-       "1:     " TUSER(ldrb) " %1,[%2],#0\n"                   \
+       "1:     " TUSER(instr) " %1, [%2], #0\n"                \
        "2:\n"                                                  \
        "       .pushsection .text.fixup,\"ax\"\n"              \
        "       .align  2\n"                                    \
@@ -329,6 +365,9 @@ do {                                                                        \
        : "r" (addr), "i" (-EFAULT)                             \
        : "cc")
 
+#define __get_user_asm_byte(x, addr, err)                      \
+       __get_user_asm(x, addr, err, ldrb)
+
 #ifndef __ARMEB__
 #define __get_user_asm_half(x, __gu_addr, err)                 \
 ({                                                             \
@@ -348,22 +387,7 @@ do {                                                                       \
 #endif
 
 #define __get_user_asm_word(x, addr, err)                      \
-       __asm__ __volatile__(                                   \
-       "1:     " TUSER(ldr) "  %1,[%2],#0\n"                   \
-       "2:\n"                                                  \
-       "       .pushsection .text.fixup,\"ax\"\n"              \
-       "       .align  2\n"                                    \
-       "3:     mov     %0, %3\n"                               \
-       "       mov     %1, #0\n"                               \
-       "       b       2b\n"                                   \
-       "       .popsection\n"                                  \
-       "       .pushsection __ex_table,\"a\"\n"                \
-       "       .align  3\n"                                    \
-       "       .long   1b, 3b\n"                               \
-       "       .popsection"                                    \
-       : "+r" (err), "=&r" (x)                                 \
-       : "r" (addr), "i" (-EFAULT)                             \
-       : "cc")
+       __get_user_asm(x, addr, err, ldr)
 
 #define __put_user(x, ptr)                                             \
 ({                                                                     \
@@ -381,9 +405,11 @@ do {                                                                       \
 #define __put_user_err(x, ptr, err)                                    \
 do {                                                                   \
        unsigned long __pu_addr = (unsigned long)(ptr);                 \
+       unsigned int __ua_flags;                                        \
        __typeof__(*(ptr)) __pu_val = (x);                              \
        __chk_user_ptr(ptr);                                            \
        might_fault();                                                  \
+       __ua_flags = uaccess_save_and_enable();                         \
        switch (sizeof(*(ptr))) {                                       \
        case 1: __put_user_asm_byte(__pu_val, __pu_addr, err);  break;  \
        case 2: __put_user_asm_half(__pu_val, __pu_addr, err);  break;  \
@@ -391,11 +417,12 @@ do {                                                                      \
        case 8: __put_user_asm_dword(__pu_val, __pu_addr, err); break;  \
        default: __put_user_bad();                                      \
        }                                                               \
+       uaccess_restore(__ua_flags);                                    \
 } while (0)
 
-#define __put_user_asm_byte(x, __pu_addr, err)                 \
+#define __put_user_asm(x, __pu_addr, err, instr)               \
        __asm__ __volatile__(                                   \
-       "1:     " TUSER(strb) " %1,[%2],#0\n"                   \
+       "1:     " TUSER(instr) " %1, [%2], #0\n"                \
        "2:\n"                                                  \
        "       .pushsection .text.fixup,\"ax\"\n"              \
        "       .align  2\n"                                    \
@@ -410,6 +437,9 @@ do {                                                                        \
        : "r" (x), "r" (__pu_addr), "i" (-EFAULT)               \
        : "cc")
 
+#define __put_user_asm_byte(x, __pu_addr, err)                 \
+       __put_user_asm(x, __pu_addr, err, strb)
+
 #ifndef __ARMEB__
 #define __put_user_asm_half(x, __pu_addr, err)                 \
 ({                                                             \
@@ -427,21 +457,7 @@ do {                                                                       \
 #endif
 
 #define __put_user_asm_word(x, __pu_addr, err)                 \
-       __asm__ __volatile__(                                   \
-       "1:     " TUSER(str) "  %1,[%2],#0\n"                   \
-       "2:\n"                                                  \
-       "       .pushsection .text.fixup,\"ax\"\n"              \
-       "       .align  2\n"                                    \
-       "3:     mov     %0, %3\n"                               \
-       "       b       2b\n"                                   \
-       "       .popsection\n"                                  \
-       "       .pushsection __ex_table,\"a\"\n"                \
-       "       .align  3\n"                                    \
-       "       .long   1b, 3b\n"                               \
-       "       .popsection"                                    \
-       : "+r" (err)                                            \
-       : "r" (x), "r" (__pu_addr), "i" (-EFAULT)               \
-       : "cc")
+       __put_user_asm(x, __pu_addr, err, str)
 
 #ifndef __ARMEB__
 #define        __reg_oper0     "%R2"
@@ -474,11 +490,50 @@ do {                                                                      \
 
 
 #ifdef CONFIG_MMU
-extern unsigned long __must_check __copy_from_user(void *to, const void __user *from, unsigned long n);
-extern unsigned long __must_check __copy_to_user(void __user *to, const void *from, unsigned long n);
-extern unsigned long __must_check __copy_to_user_std(void __user *to, const void *from, unsigned long n);
-extern unsigned long __must_check __clear_user(void __user *addr, unsigned long n);
-extern unsigned long __must_check __clear_user_std(void __user *addr, unsigned long n);
+extern unsigned long __must_check
+arm_copy_from_user(void *to, const void __user *from, unsigned long n);
+
+static inline unsigned long __must_check
+__copy_from_user(void *to, const void __user *from, unsigned long n)
+{
+       unsigned int __ua_flags = uaccess_save_and_enable();
+       n = arm_copy_from_user(to, from, n);
+       uaccess_restore(__ua_flags);
+       return n;
+}
+
+extern unsigned long __must_check
+arm_copy_to_user(void __user *to, const void *from, unsigned long n);
+extern unsigned long __must_check
+__copy_to_user_std(void __user *to, const void *from, unsigned long n);
+
+static inline unsigned long __must_check
+__copy_to_user(void __user *to, const void *from, unsigned long n)
+{
+#ifndef CONFIG_UACCESS_WITH_MEMCPY
+       unsigned int __ua_flags = uaccess_save_and_enable();
+       n = arm_copy_to_user(to, from, n);
+       uaccess_restore(__ua_flags);
+       return n;
+#else
+       return arm_copy_to_user(to, from, n);
+#endif
+}
+
+extern unsigned long __must_check
+arm_clear_user(void __user *addr, unsigned long n);
+extern unsigned long __must_check
+__clear_user_std(void __user *addr, unsigned long n);
+
+static inline unsigned long __must_check
+__clear_user(void __user *addr, unsigned long n)
+{
+       unsigned int __ua_flags = uaccess_save_and_enable();
+       n = arm_clear_user(addr, n);
+       uaccess_restore(__ua_flags);
+       return n;
+}
+
 #else
 #define __copy_from_user(to, from, n)  (memcpy(to, (void __force *)from, n), 0)
 #define __copy_to_user(to, from, n)    (memcpy((void __force *)to, from, n), 0)
@@ -511,6 +566,7 @@ static inline unsigned long __must_check clear_user(void __user *to, unsigned lo
        return n;
 }
 
+/* These are from lib/ code, and use __get_user() and friends */
 extern long strncpy_from_user(char *dest, const char __user *src, long count);
 
 extern __must_check long strlen_user(const char __user *str);