x86: Add missing might_fault() checks to copy_{to,from}_user()
[safe/jmp/linux-2.6] / arch / x86 / include / asm / uaccess_64.h
index f8cfd00..46324c6 100644 (file)
@@ -19,16 +19,43 @@ __must_check unsigned long
 copy_user_generic(void *to, const void *from, unsigned len);
 
 __must_check unsigned long
-copy_to_user(void __user *to, const void *from, unsigned len);
+_copy_to_user(void __user *to, const void *from, unsigned len);
 __must_check unsigned long
-copy_from_user(void *to, const void __user *from, unsigned len);
+_copy_from_user(void *to, const void __user *from, unsigned len);
 __must_check unsigned long
 copy_in_user(void __user *to, const void __user *from, unsigned len);
 
+static inline unsigned long __must_check copy_from_user(void *to,
+                                         const void __user *from,
+                                         unsigned long n)
+{
+       int sz = __compiletime_object_size(to);
+       int ret = -EFAULT;
+
+       might_fault();
+       if (likely(sz == -1 || sz >= n))
+               ret = _copy_from_user(to, from, n);
+#ifdef CONFIG_DEBUG_VM
+       else
+               WARN(1, "Buffer overflow detected!\n");
+#endif
+       return ret;
+}
+
+static __always_inline __must_check
+int copy_to_user(void __user *dst, const void *src, unsigned size)
+{
+       might_fault();
+
+       return _copy_to_user(dst, src, size);
+}
+
 static __always_inline __must_check
 int __copy_from_user(void *dst, const void __user *src, unsigned size)
 {
        int ret = 0;
+
+       might_fault();
        if (!__builtin_constant_p(size))
                return copy_user_generic(dst, (__force void *)src, size);
        switch (size) {
@@ -71,6 +98,8 @@ static __always_inline __must_check
 int __copy_to_user(void __user *dst, const void *src, unsigned size)
 {
        int ret = 0;
+
+       might_fault();
        if (!__builtin_constant_p(size))
                return copy_user_generic((__force void *)dst, src, size);
        switch (size) {
@@ -84,11 +113,11 @@ int __copy_to_user(void __user *dst, const void *src, unsigned size)
                              ret, "l", "k", "ir", 4);
                return ret;
        case 8:__put_user_asm(*(u64 *)src, (u64 __user *)dst,
-                             ret, "q", "", "ir", 8);
+                             ret, "q", "", "er", 8);
                return ret;
        case 10:
                __put_user_asm(*(u64 *)src, (u64 __user *)dst,
-                              ret, "q", "", "ir", 10);
+                              ret, "q", "", "er", 10);
                if (unlikely(ret))
                        return ret;
                asm("":::"memory");
@@ -97,12 +126,12 @@ int __copy_to_user(void __user *dst, const void *src, unsigned size)
                return ret;
        case 16:
                __put_user_asm(*(u64 *)src, (u64 __user *)dst,
-                              ret, "q", "", "ir", 16);
+                              ret, "q", "", "er", 16);
                if (unlikely(ret))
                        return ret;
                asm("":::"memory");
                __put_user_asm(1[(u64 *)src], 1 + (u64 __user *)dst,
-                              ret, "q", "", "ir", 8);
+                              ret, "q", "", "er", 8);
                return ret;
        default:
                return copy_user_generic((__force void *)dst, src, size);
@@ -113,6 +142,8 @@ static __always_inline __must_check
 int __copy_in_user(void __user *dst, const void __user *src, unsigned size)
 {
        int ret = 0;
+
+       might_fault();
        if (!__builtin_constant_p(size))
                return copy_user_generic((__force void *)dst,
                                         (__force void *)src, size);
@@ -151,7 +182,7 @@ int __copy_in_user(void __user *dst, const void __user *src, unsigned size)
                               ret, "q", "", "=r", 8);
                if (likely(!ret))
                        __put_user_asm(tmp, (u64 __user *)dst,
-                                      ret, "q", "", "ir", 8);
+                                      ret, "q", "", "er", 8);
                return ret;
        }
        default:
@@ -170,8 +201,11 @@ __must_check long strlen_user(const char __user *str);
 __must_check unsigned long clear_user(void __user *mem, unsigned long len);
 __must_check unsigned long __clear_user(void __user *mem, unsigned long len);
 
-__must_check long __copy_from_user_inatomic(void *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)
+{
+       return copy_user_generic(dst, (__force const void *)src, size);
+}
 
 static __must_check __always_inline int
 __copy_to_user_inatomic(void __user *dst, const void *src, unsigned size)
@@ -182,16 +216,16 @@ __copy_to_user_inatomic(void __user *dst, const void *src, unsigned size)
 extern long __copy_user_nocache(void *dst, const void __user *src,
                                unsigned size, int zerorest);
 
-static inline int __copy_from_user_nocache(void *dst, const void __user *src,
-                                          unsigned size)
+static inline int
+__copy_from_user_nocache(void *dst, const void __user *src, unsigned size)
 {
        might_sleep();
        return __copy_user_nocache(dst, src, size, 1);
 }
 
-static inline int __copy_from_user_inatomic_nocache(void *dst,
-                                                   const void __user *src,
-                                                   unsigned size)
+static inline int
+__copy_from_user_inatomic_nocache(void *dst, const void __user *src,
+                                 unsigned size)
 {
        return __copy_user_nocache(dst, src, size, 0);
 }