aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2017-05-30 00:29:38 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2017-06-09 23:51:17 -0400
commit1e1fc133483ef3b56c20bf3cd9241146c41042f8 (patch)
tree6f4df10c1fcb97d3cdaf4c006e55dd08f8e3b16f
parent9a4690379206695b63a175e227877490beb2eeda (diff)
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>
-rw-r--r--include/linux/compat.h3
-rw-r--r--kernel/compat.c81
2 files changed, 29 insertions, 55 deletions
diff --git a/include/linux/compat.h b/include/linux/compat.h
index 1c5f3152cbb5..94ceb0348a25 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -388,8 +388,7 @@ asmlinkage long compat_sys_wait4(compat_pid_t pid,
388 388
389#define BITS_PER_COMPAT_LONG (8*sizeof(compat_long_t)) 389#define BITS_PER_COMPAT_LONG (8*sizeof(compat_long_t))
390 390
391#define BITS_TO_COMPAT_LONGS(bits) \ 391#define BITS_TO_COMPAT_LONGS(bits) DIV_ROUND_UP(bits, BITS_PER_COMPAT_LONG)
392 (((bits)+BITS_PER_COMPAT_LONG-1)/BITS_PER_COMPAT_LONG)
393 392
394long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask, 393long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask,
395 unsigned long bitmap_size); 394 unsigned long bitmap_size);
diff --git a/kernel/compat.c b/kernel/compat.c
index 860f674fa556..9c2a8f3788d5 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -871,84 +871,59 @@ int get_compat_sigevent(struct sigevent *event,
871long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask, 871long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask,
872 unsigned long bitmap_size) 872 unsigned long bitmap_size)
873{ 873{
874 int i, j;
875 unsigned long m;
876 compat_ulong_t um;
877 unsigned long nr_compat_longs; 874 unsigned long nr_compat_longs;
878 875
879 /* align bitmap up to nearest compat_long_t boundary */ 876 /* align bitmap up to nearest compat_long_t boundary */
880 bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG); 877 bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG);
878 nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
881 879
882 if (!access_ok(VERIFY_READ, umask, bitmap_size / 8)) 880 if (!access_ok(VERIFY_READ, umask, bitmap_size / 8))
883 return -EFAULT; 881 return -EFAULT;
884 882
885 nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size); 883 user_access_begin();
886 884 while (nr_compat_longs > 1) {
887 for (i = 0; i < BITS_TO_LONGS(bitmap_size); i++) { 885 compat_ulong_t l1, l2;
888 m = 0; 886 unsafe_get_user(l1, umask++, Efault);
889 887 unsafe_get_user(l2, umask++, Efault);
890 for (j = 0; j < sizeof(m)/sizeof(um); j++) { 888 *mask++ = ((unsigned long)l2 << BITS_PER_COMPAT_LONG) | l1;
891 /* 889 nr_compat_longs -= 2;
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;
908 } 890 }
909 891 if (nr_compat_longs)
892 unsafe_get_user(*mask, umask++, Efault);
893 user_access_end();
910 return 0; 894 return 0;
895
896Efault:
897 user_access_end();
898 return -EFAULT;
911} 899}
912 900
913long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask, 901long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask,
914 unsigned long bitmap_size) 902 unsigned long bitmap_size)
915{ 903{
916 int i, j;
917 unsigned long m;
918 compat_ulong_t um;
919 unsigned long nr_compat_longs; 904 unsigned long nr_compat_longs;
920 905
921 /* align bitmap up to nearest compat_long_t boundary */ 906 /* align bitmap up to nearest compat_long_t boundary */
922 bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG); 907 bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG);
908 nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
923 909
924 if (!access_ok(VERIFY_WRITE, umask, bitmap_size / 8)) 910 if (!access_ok(VERIFY_WRITE, umask, bitmap_size / 8))
925 return -EFAULT; 911 return -EFAULT;
926 912
927 nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size); 913 user_access_begin();
928 914 while (nr_compat_longs > 1) {
929 for (i = 0; i < BITS_TO_LONGS(bitmap_size); i++) { 915 unsigned long m = *mask++;
930 m = *mask++; 916 unsafe_put_user((compat_ulong_t)m, umask++, Efault);
931 917 unsafe_put_user(m >> BITS_PER_COMPAT_LONG, umask++, Efault);
932 for (j = 0; j < sizeof(m)/sizeof(um); j++) { 918 nr_compat_longs -= 2;
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 }
949 } 919 }
950 920 if (nr_compat_longs)
921 unsafe_put_user((compat_ulong_t)*mask, umask++, Efault);
922 user_access_end();
951 return 0; 923 return 0;
924Efault:
925 user_access_end();
926 return -EFAULT;
952} 927}
953 928
954void 929void