Skip to content

Commit 1e1fc13

Browse files
author
Al Viro
committed
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>
1 parent 9a46903 commit 1e1fc13

File tree

2 files changed

+29
-55
lines changed

2 files changed

+29
-55
lines changed

include/linux/compat.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -388,8 +388,7 @@ asmlinkage long compat_sys_wait4(compat_pid_t pid,
388388

389389
#define BITS_PER_COMPAT_LONG (8*sizeof(compat_long_t))
390390

391-
#define BITS_TO_COMPAT_LONGS(bits) \
392-
(((bits)+BITS_PER_COMPAT_LONG-1)/BITS_PER_COMPAT_LONG)
391+
#define BITS_TO_COMPAT_LONGS(bits) DIV_ROUND_UP(bits, BITS_PER_COMPAT_LONG)
393392

394393
long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask,
395394
unsigned long bitmap_size);

kernel/compat.c

Lines changed: 28 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -871,84 +871,59 @@ int get_compat_sigevent(struct sigevent *event,
871871
long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask,
872872
unsigned long bitmap_size)
873873
{
874-
int i, j;
875-
unsigned long m;
876-
compat_ulong_t um;
877874
unsigned long nr_compat_longs;
878875

879876
/* align bitmap up to nearest compat_long_t boundary */
880877
bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG);
878+
nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
881879

882880
if (!access_ok(VERIFY_READ, umask, bitmap_size / 8))
883881
return -EFAULT;
884882

885-
nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
886-
887-
for (i = 0; i < BITS_TO_LONGS(bitmap_size); i++) {
888-
m = 0;
889-
890-
for (j = 0; j < sizeof(m)/sizeof(um); j++) {
891-
/*
892-
* We dont want to read past the end of the userspace
893-
* bitmap. We must however ensure the end of the
894-
* kernel bitmap is zeroed.
895-
*/
896-
if (nr_compat_longs) {
897-
nr_compat_longs--;
898-
if (__get_user(um, umask))
899-
return -EFAULT;
900-
} else {
901-
um = 0;
902-
}
903-
904-
umask++;
905-
m |= (long)um << (j * BITS_PER_COMPAT_LONG);
906-
}
907-
*mask++ = m;
883+
user_access_begin();
884+
while (nr_compat_longs > 1) {
885+
compat_ulong_t l1, l2;
886+
unsafe_get_user(l1, umask++, Efault);
887+
unsafe_get_user(l2, umask++, Efault);
888+
*mask++ = ((unsigned long)l2 << BITS_PER_COMPAT_LONG) | l1;
889+
nr_compat_longs -= 2;
908890
}
909-
891+
if (nr_compat_longs)
892+
unsafe_get_user(*mask, umask++, Efault);
893+
user_access_end();
910894
return 0;
895+
896+
Efault:
897+
user_access_end();
898+
return -EFAULT;
911899
}
912900

913901
long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask,
914902
unsigned long bitmap_size)
915903
{
916-
int i, j;
917-
unsigned long m;
918-
compat_ulong_t um;
919904
unsigned long nr_compat_longs;
920905

921906
/* align bitmap up to nearest compat_long_t boundary */
922907
bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG);
908+
nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
923909

924910
if (!access_ok(VERIFY_WRITE, umask, bitmap_size / 8))
925911
return -EFAULT;
926912

927-
nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
928-
929-
for (i = 0; i < BITS_TO_LONGS(bitmap_size); i++) {
930-
m = *mask++;
931-
932-
for (j = 0; j < sizeof(m)/sizeof(um); j++) {
933-
um = m;
934-
935-
/*
936-
* We dont want to write past the end of the userspace
937-
* bitmap.
938-
*/
939-
if (nr_compat_longs) {
940-
nr_compat_longs--;
941-
if (__put_user(um, umask))
942-
return -EFAULT;
943-
}
944-
945-
umask++;
946-
m >>= 4*sizeof(um);
947-
m >>= 4*sizeof(um);
948-
}
913+
user_access_begin();
914+
while (nr_compat_longs > 1) {
915+
unsigned long m = *mask++;
916+
unsafe_put_user((compat_ulong_t)m, umask++, Efault);
917+
unsafe_put_user(m >> BITS_PER_COMPAT_LONG, umask++, Efault);
918+
nr_compat_longs -= 2;
949919
}
950-
920+
if (nr_compat_longs)
921+
unsafe_put_user((compat_ulong_t)*mask, umask++, Efault);
922+
user_access_end();
951923
return 0;
924+
Efault:
925+
user_access_end();
926+
return -EFAULT;
952927
}
953928

954929
void

0 commit comments

Comments
 (0)