compat_{get,put}_bitmap(): use unsafe_{get,put}_user()

unroll the inner loops, while we are at it

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Al Viro 2017-05-30 00:29:38 -04:00
parent 9a46903792
commit 1e1fc13348
2 changed files with 29 additions and 55 deletions

View 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_PER_COMPAT_LONG (8*sizeof(compat_long_t))
#define BITS_TO_COMPAT_LONGS(bits) \ #define BITS_TO_COMPAT_LONGS(bits) DIV_ROUND_UP(bits, BITS_PER_COMPAT_LONG)
(((bits)+BITS_PER_COMPAT_LONG-1)/BITS_PER_COMPAT_LONG)
long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask, long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask,
unsigned long bitmap_size); unsigned long bitmap_size);

View 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, long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask,
unsigned long bitmap_size) unsigned long bitmap_size)
{ {
int i, j;
unsigned long m;
compat_ulong_t um;
unsigned long nr_compat_longs; unsigned long nr_compat_longs;
/* align bitmap up to nearest compat_long_t boundary */ /* align bitmap up to nearest compat_long_t boundary */
bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG); 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)) if (!access_ok(VERIFY_READ, umask, bitmap_size / 8))
return -EFAULT; return -EFAULT;
nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size); user_access_begin();
while (nr_compat_longs > 1) {
for (i = 0; i < BITS_TO_LONGS(bitmap_size); i++) { compat_ulong_t l1, l2;
m = 0; unsafe_get_user(l1, umask++, Efault);
unsafe_get_user(l2, umask++, Efault);
for (j = 0; j < sizeof(m)/sizeof(um); j++) { *mask++ = ((unsigned long)l2 << BITS_PER_COMPAT_LONG) | l1;
/* nr_compat_longs -= 2;
* 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;
} }
if (nr_compat_longs)
unsafe_get_user(*mask, umask++, Efault);
user_access_end();
return 0; return 0;
Efault:
user_access_end();
return -EFAULT;
} }
long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask, long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask,
unsigned long bitmap_size) unsigned long bitmap_size)
{ {
int i, j;
unsigned long m;
compat_ulong_t um;
unsigned long nr_compat_longs; unsigned long nr_compat_longs;
/* align bitmap up to nearest compat_long_t boundary */ /* align bitmap up to nearest compat_long_t boundary */
bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG); 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)) if (!access_ok(VERIFY_WRITE, umask, bitmap_size / 8))
return -EFAULT; return -EFAULT;
nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size); user_access_begin();
while (nr_compat_longs > 1) {
for (i = 0; i < BITS_TO_LONGS(bitmap_size); i++) { unsigned long m = *mask++;
m = *mask++; unsafe_put_user((compat_ulong_t)m, umask++, Efault);
unsafe_put_user(m >> BITS_PER_COMPAT_LONG, umask++, Efault);
for (j = 0; j < sizeof(m)/sizeof(um); j++) { nr_compat_longs -= 2;
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);
}
} }
if (nr_compat_longs)
unsafe_put_user((compat_ulong_t)*mask, umask++, Efault);
user_access_end();
return 0; return 0;
Efault:
user_access_end();
return -EFAULT;
} }
void void