Merge branch 'uaccess-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 14 Sep 2016 16:35:05 +0000 (09:35 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 14 Sep 2016 16:35:05 +0000 (09:35 -0700)
Pull uaccess fixes from Al Viro:
 "Fixes for broken uaccess primitives - mostly lack of proper zeroing
  in copy_from_user()/get_user()/__get_user(), but for several
  architectures there's more (broken clear_user() on frv and
  strncpy_from_user() on hexagon)"

* 'uaccess-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (28 commits)
  avr32: fix copy_from_user()
  microblaze: fix __get_user()
  microblaze: fix copy_from_user()
  m32r: fix __get_user()
  blackfin: fix copy_from_user()
  sparc32: fix copy_from_user()
  sh: fix copy_from_user()
  sh64: failing __get_user() should zero
  score: fix copy_from_user() and friends
  score: fix __get_user/get_user
  s390: get_user() should zero on failure
  ppc32: fix copy_from_user()
  parisc: fix copy_from_user()
  openrisc: fix copy_from_user()
  nios2: fix __get_user()
  nios2: copy_from_user() should zero the tail of destination
  mn10300: copy_from_user() should zero on access_ok() failure...
  mn10300: failing __get_user() and get_user() should zero
  mips: copy_from_user() must zero the destination on access_ok() failure
  ARC: uaccess: get_user to zero out dest in cause of fault
  ...

1  2 
arch/ia64/include/asm/uaccess.h
arch/parisc/include/asm/uaccess.h
arch/powerpc/include/asm/uaccess.h
arch/s390/include/asm/uaccess.h
arch/sparc/include/asm/uaccess_32.h
include/asm-generic/uaccess.h

@@@ -269,19 -272,17 +269,16 @@@ __copy_from_user (void *to, const void 
        __cu_len;                                                                       \
  })
  
- #define copy_from_user(to, from, n)                                                   \
- ({                                                                                    \
-       void *__cu_to = (to);                                                           \
-       const void __user *__cu_from = (from);                                          \
-       long __cu_len = (n);                                                            \
-                                                                                       \
-       __chk_user_ptr(__cu_from);                                                      \
-       if (__access_ok(__cu_from, __cu_len, get_fs())) {                               \
-               check_object_size(__cu_to, __cu_len, false);                    \
-               __cu_len = __copy_user((__force void __user *) __cu_to, __cu_from, __cu_len);   \
-       }                                                                               \
-       __cu_len;                                                                       \
- })
+ static inline unsigned long
+ copy_from_user(void *to, const void __user *from, unsigned long n)
+ {
 -      if (!__builtin_constant_p(n))
 -              check_object_size(to, n, false);
++      check_object_size(to, n, false);
+       if (likely(__access_ok(from, n, get_fs())))
+               n = __copy_user((__force void __user *) to, from, n);
+       else
+               memset(to, 0, n);
+       return n;
+ }
  
  #define __copy_in_user(to, from, size)        __copy_user((to), (from), (size))
  
@@@ -221,15 -222,14 +222,17 @@@ static inline unsigned long __must_chec
                                            unsigned long n)
  {
          int sz = __compiletime_object_size(to);
-         int ret = -EFAULT;
+         unsigned long ret = n;
  
 -        if (likely(sz == -1 || !__builtin_constant_p(n) || sz >= n))
 +        if (likely(sz == -1 || sz >= n))
                  ret = __copy_from_user(to, from, n);
 -        else
 -                copy_from_user_overflow();
 +        else if (!__builtin_constant_p(n))
 +              copy_user_overflow(sz, n);
 +      else
 +                __bad_copy_user();
 +
+       if (unlikely(ret))
+               memset(to + (n - ret), 0, ret);
          return ret;
  }
  
@@@ -308,36 -308,23 +308,21 @@@ extern unsigned long __copy_tofrom_user
  static inline unsigned long copy_from_user(void *to,
                const void __user *from, unsigned long n)
  {
-       unsigned long over;
-       if (access_ok(VERIFY_READ, from, n)) {
+       if (likely(access_ok(VERIFY_READ, from, n))) {
 -              if (!__builtin_constant_p(n))
 -                      check_object_size(to, n, false);
 +              check_object_size(to, n, false);
                return __copy_tofrom_user((__force void __user *)to, from, n);
        }
-       if ((unsigned long)from < TASK_SIZE) {
-               over = (unsigned long)from + n - TASK_SIZE;
-               check_object_size(to, n - over, false);
-               return __copy_tofrom_user((__force void __user *)to, from,
-                               n - over) + over;
-       }
+       memset(to, 0, n);
        return n;
  }
  
  static inline unsigned long copy_to_user(void __user *to,
                const void *from, unsigned long n)
  {
-       unsigned long over;
        if (access_ok(VERIFY_WRITE, to, n)) {
 -              if (!__builtin_constant_p(n))
 -                      check_object_size(from, n, true);
 +              check_object_size(from, n, true);
                return __copy_tofrom_user(to, (__force void __user *)from, n);
        }
-       if ((unsigned long)to < TASK_SIZE) {
-               over = (unsigned long)to + n - TASK_SIZE;
-               check_object_size(from, n - over, true);
-               return __copy_tofrom_user(to, (__force void __user *)from,
-                               n - over) + over;
-       }
        return n;
  }
  
Simple merge
@@@ -264,10 -266,13 +264,12 @@@ static inline unsigned long __copy_to_u
  static inline unsigned long copy_from_user(void *to, const void __user *from, unsigned long n)
  {
        if (n && __access_ok((unsigned long) from, n)) {
 -              if (!__builtin_constant_p(n))
 -                      check_object_size(to, n, false);
 +              check_object_size(to, n, false);
                return __copy_user((__force void __user *) to, from, n);
-       } else
+       } else {
+               memset(to, 0, n);
                return n;
+       }
  }
  
  static inline unsigned long __copy_from_user(void *to, const void __user *from, unsigned long n)
Simple merge