]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - arch/x86/include/asm/uaccess.h
x86/uaccess: Don't leak the AC flag into __put_user() value evaluation
[linux.git] / arch / x86 / include / asm / uaccess.h
index b5e58cc0c5e75d29aed2cf45ecf52d86ebac1a37..28376aa2d05374ecec9c2659c272db373e118a16 100644 (file)
@@ -77,9 +77,6 @@ static inline bool __chk_range_not_ok(unsigned long addr, unsigned long size, un
 
 /**
  * access_ok: - Checks if a user space pointer is valid
- * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE.  Note that
- *        %VERIFY_WRITE is a superset of %VERIFY_READ - if it is safe
- *        to write to a block, it is always safe to read from it.
  * @addr: User space pointer to start of block to check
  * @size: Size of block to check
  *
@@ -95,7 +92,7 @@ static inline bool __chk_range_not_ok(unsigned long addr, unsigned long size, un
  * checks that the pointer is in the user space range - after calling
  * this function, memory access functions may still return -EFAULT.
  */
-#define access_ok(type, addr, size)                                    \
+#define access_ok(addr, size)                                  \
 ({                                                                     \
        WARN_ON_IN_IRQ();                                               \
        likely(!__range_not_ok(addr, size, user_addr_max()));           \
@@ -189,19 +186,14 @@ __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL))
 
 
 #ifdef CONFIG_X86_32
-#define __put_user_asm_u64(x, addr, err, errret)                       \
-       asm volatile("\n"                                               \
-                    "1:        movl %%eax,0(%2)\n"                     \
-                    "2:        movl %%edx,4(%2)\n"                     \
-                    "3:"                                               \
-                    ".section .fixup,\"ax\"\n"                         \
-                    "4:        movl %3,%0\n"                           \
-                    "  jmp 3b\n"                                       \
-                    ".previous\n"                                      \
-                    _ASM_EXTABLE_UA(1b, 4b)                            \
-                    _ASM_EXTABLE_UA(2b, 4b)                            \
-                    : "=r" (err)                                       \
-                    : "A" (x), "r" (addr), "i" (errret), "0" (err))
+#define __put_user_goto_u64(x, addr, label)                    \
+       asm_volatile_goto("\n"                                  \
+                    "1:        movl %%eax,0(%1)\n"             \
+                    "2:        movl %%edx,4(%1)\n"             \
+                    _ASM_EXTABLE_UA(1b, %l2)                   \
+                    _ASM_EXTABLE_UA(2b, %l2)                   \
+                    : : "A" (x), "r" (addr)                    \
+                    : : label)
 
 #define __put_user_asm_ex_u64(x, addr)                                 \
        asm volatile("\n"                                               \
@@ -216,8 +208,8 @@ __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL))
        asm volatile("call __put_user_8" : "=a" (__ret_pu)      \
                     : "A" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx")
 #else
-#define __put_user_asm_u64(x, ptr, retval, errret) \
-       __put_user_asm(x, ptr, retval, "q", "", "er", errret)
+#define __put_user_goto_u64(x, ptr, label) \
+       __put_user_goto(x, ptr, "q", "", "er", label)
 #define __put_user_asm_ex_u64(x, addr) \
        __put_user_asm_ex(x, addr, "q", "", "er")
 #define __put_user_x8(x, ptr, __ret_pu) __put_user_x(8, x, ptr, __ret_pu)
@@ -278,23 +270,21 @@ extern void __put_user_8(void);
        __builtin_expect(__ret_pu, 0);                          \
 })
 
-#define __put_user_size(x, ptr, size, retval, errret)                  \
+#define __put_user_size(x, ptr, size, label)                           \
 do {                                                                   \
-       retval = 0;                                                     \
        __chk_user_ptr(ptr);                                            \
        switch (size) {                                                 \
        case 1:                                                         \
-               __put_user_asm(x, ptr, retval, "b", "b", "iq", errret); \
+               __put_user_goto(x, ptr, "b", "b", "iq", label); \
                break;                                                  \
        case 2:                                                         \
-               __put_user_asm(x, ptr, retval, "w", "w", "ir", errret); \
+               __put_user_goto(x, ptr, "w", "w", "ir", label);         \
                break;                                                  \
        case 4:                                                         \
-               __put_user_asm(x, ptr, retval, "l", "k", "ir", errret); \
+               __put_user_goto(x, ptr, "l", "k", "ir", label);         \
                break;                                                  \
        case 8:                                                         \
-               __put_user_asm_u64((__typeof__(*ptr))(x), ptr, retval,  \
-                                  errret);                             \
+               __put_user_goto_u64(x, ptr, label);                     \
                break;                                                  \
        default:                                                        \
                __put_user_bad();                                       \
@@ -439,9 +429,14 @@ do {                                                                       \
 
 #define __put_user_nocheck(x, ptr, size)                       \
 ({                                                             \
-       int __pu_err;                                           \
+       __label__ __pu_label;                                   \
+       int __pu_err = -EFAULT;                                 \
+       __typeof__(*(ptr)) __pu_val;                            \
+       __pu_val = x;                                           \
        __uaccess_begin();                                      \
-       __put_user_size((x), (ptr), (size), __pu_err, -EFAULT); \
+       __put_user_size(__pu_val, (ptr), (size), __pu_label);   \
+       __pu_err = 0;                                           \
+__pu_label:                                                    \
        __uaccess_end();                                        \
        __builtin_expect(__pu_err, 0);                          \
 })
@@ -466,17 +461,23 @@ struct __large_struct { unsigned long buf[100]; };
  * we do not write to any memory gcc knows about, so there are no
  * aliasing issues.
  */
-#define __put_user_asm(x, addr, err, itype, rtype, ltype, errret)      \
-       asm volatile("\n"                                               \
-                    "1:        mov"itype" %"rtype"1,%2\n"              \
-                    "2:\n"                                             \
-                    ".section .fixup,\"ax\"\n"                         \
-                    "3:        mov %3,%0\n"                            \
-                    "  jmp 2b\n"                                       \
-                    ".previous\n"                                      \
-                    _ASM_EXTABLE_UA(1b, 3b)                            \
-                    : "=r"(err)                                        \
-                    : ltype(x), "m" (__m(addr)), "i" (errret), "0" (err))
+#define __put_user_goto(x, addr, itype, rtype, ltype, label)   \
+       asm_volatile_goto("\n"                                          \
+               "1:     mov"itype" %"rtype"0,%1\n"                      \
+               _ASM_EXTABLE_UA(1b, %l2)                                        \
+               : : ltype(x), "m" (__m(addr))                           \
+               : : label)
+
+#define __put_user_failed(x, addr, itype, rtype, ltype, errret)                \
+       ({      __label__ __puflab;                                     \
+               int __pufret = errret;                                  \
+               __put_user_goto(x,addr,itype,rtype,ltype,__puflab);     \
+               __pufret = 0;                                           \
+       __puflab: __pufret; })
+
+#define __put_user_asm(x, addr, retval, itype, rtype, ltype, errret)   do {    \
+       retval = __put_user_failed(x, addr, itype, rtype, ltype, errret);       \
+} while (0)
 
 #define __put_user_asm_ex(x, addr, itype, rtype, ltype)                        \
        asm volatile("1:        mov"itype" %"rtype"0,%1\n"              \
@@ -670,7 +671,7 @@ extern void __cmpxchg_wrong_size(void)
 
 #define user_atomic_cmpxchg_inatomic(uval, ptr, old, new)              \
 ({                                                                     \
-       access_ok(VERIFY_WRITE, (ptr), sizeof(*(ptr))) ?                \
+       access_ok((ptr), sizeof(*(ptr))) ?              \
                __user_atomic_cmpxchg_inatomic((uval), (ptr),           \
                                (old), (new), sizeof(*(ptr))) :         \
                -EFAULT;                                                \
@@ -708,16 +709,18 @@ extern struct movsl_mask {
  * checking before using them, but you have to surround them with the
  * user_access_begin/end() pair.
  */
-#define user_access_begin()    __uaccess_begin()
+static __must_check inline bool user_access_begin(const void __user *ptr, size_t len)
+{
+       if (unlikely(!access_ok(ptr,len)))
+               return 0;
+       __uaccess_begin();
+       return 1;
+}
+#define user_access_begin(a,b) user_access_begin(a,b)
 #define user_access_end()      __uaccess_end()
 
-#define unsafe_put_user(x, ptr, err_label)                                     \
-do {                                                                           \
-       int __pu_err;                                                           \
-       __typeof__(*(ptr)) __pu_val = (x);                                      \
-       __put_user_size(__pu_val, (ptr), sizeof(*(ptr)), __pu_err, -EFAULT);    \
-       if (unlikely(__pu_err)) goto err_label;                                 \
-} while (0)
+#define unsafe_put_user(x, ptr, label) \
+       __put_user_size((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)), label)
 
 #define unsafe_get_user(x, ptr, err_label)                                     \
 do {                                                                           \