compat_{get,put}_bitmap(): use unsafe_{get,put}_user()
authorAl Viro <viro@zeniv.linux.org.uk>
Tue, 30 May 2017 04:29:38 +0000 (00:29 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Sat, 10 Jun 2017 03:51:17 +0000 (23:51 -0400)
unroll the inner loops, while we are at it

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
include/linux/compat.h
kernel/compat.c

index 1c5f3152cbb57796caf1a587103ed3d092324a04..94ceb0348a2566204c7886900817e24f9c2c1360 100644 (file)
@@ -388,8 +388,7 @@ asmlinkage long compat_sys_wait4(compat_pid_t pid,
 
 #define BITS_PER_COMPAT_LONG    (8*sizeof(compat_long_t))
 
-#define BITS_TO_COMPAT_LONGS(bits) \
-       (((bits)+BITS_PER_COMPAT_LONG-1)/BITS_PER_COMPAT_LONG)
+#define BITS_TO_COMPAT_LONGS(bits) DIV_ROUND_UP(bits, BITS_PER_COMPAT_LONG)
 
 long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask,
                       unsigned long bitmap_size);
index 860f674fa556edb2342eb84832b2afa22d2a6389..9c2a8f3788d5e13e1de588c57040b4348419f05d 100644 (file)
@@ -871,84 +871,59 @@ int get_compat_sigevent(struct sigevent *event,
 long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask,
                       unsigned long bitmap_size)
 {
-       int i, j;
-       unsigned long m;
-       compat_ulong_t um;
        unsigned long nr_compat_longs;
 
        /* align bitmap up to nearest compat_long_t boundary */
        bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG);
+       nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
 
        if (!access_ok(VERIFY_READ, umask, bitmap_size / 8))
                return -EFAULT;
 
-       nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
-
-       for (i = 0; i < BITS_TO_LONGS(bitmap_size); i++) {
-               m = 0;
-
-               for (j = 0; j < sizeof(m)/sizeof(um); j++) {
-                       /*
-                        * We dont want to read past the end of the userspace
-                        * bitmap. We must however ensure the end of the
-                        * kernel bitmap is zeroed.
-                        */
-                       if (nr_compat_longs) {
-                               nr_compat_longs--;
-                               if (__get_user(um, umask))
-                                       return -EFAULT;
-                       } else {
-                               um = 0;
-                       }
-
-                       umask++;
-                       m |= (long)um << (j * BITS_PER_COMPAT_LONG);
-               }
-               *mask++ = m;
+       user_access_begin();
+       while (nr_compat_longs > 1) {
+               compat_ulong_t l1, l2;
+               unsafe_get_user(l1, umask++, Efault);
+               unsafe_get_user(l2, umask++, Efault);
+               *mask++ = ((unsigned long)l2 << BITS_PER_COMPAT_LONG) | l1;
+               nr_compat_longs -= 2;
        }
-
+       if (nr_compat_longs)
+               unsafe_get_user(*mask, umask++, Efault);
+       user_access_end();
        return 0;
+
+Efault:
+       user_access_end();
+       return -EFAULT;
 }
 
 long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask,
                       unsigned long bitmap_size)
 {
-       int i, j;
-       unsigned long m;
-       compat_ulong_t um;
        unsigned long nr_compat_longs;
 
        /* align bitmap up to nearest compat_long_t boundary */
        bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG);
+       nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
 
        if (!access_ok(VERIFY_WRITE, umask, bitmap_size / 8))
                return -EFAULT;
 
-       nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
-
-       for (i = 0; i < BITS_TO_LONGS(bitmap_size); i++) {
-               m = *mask++;
-
-               for (j = 0; j < sizeof(m)/sizeof(um); j++) {
-                       um = m;
-
-                       /*
-                        * We dont want to write past the end of the userspace
-                        * bitmap.
-                        */
-                       if (nr_compat_longs) {
-                               nr_compat_longs--;
-                               if (__put_user(um, umask))
-                                       return -EFAULT;
-                       }
-
-                       umask++;
-                       m >>= 4*sizeof(um);
-                       m >>= 4*sizeof(um);
-               }
+       user_access_begin();
+       while (nr_compat_longs > 1) {
+               unsigned long m = *mask++;
+               unsafe_put_user((compat_ulong_t)m, umask++, Efault);
+               unsafe_put_user(m >> BITS_PER_COMPAT_LONG, umask++, Efault);
+               nr_compat_longs -= 2;
        }
-
+       if (nr_compat_longs)
+               unsafe_put_user((compat_ulong_t)*mask, umask++, Efault);
+       user_access_end();
        return 0;
+Efault:
+       user_access_end();
+       return -EFAULT;
 }
 
 void