diff options
| author | Al Viro <viro@zeniv.linux.org.uk> | 2017-05-30 00:29:38 -0400 |
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2017-06-09 23:51:17 -0400 |
| commit | 1e1fc133483ef3b56c20bf3cd9241146c41042f8 (patch) | |
| tree | 6f4df10c1fcb97d3cdaf4c006e55dd08f8e3b16f | |
| parent | 9a4690379206695b63a175e227877490beb2eeda (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.h | 3 | ||||
| -rw-r--r-- | kernel/compat.c | 81 |
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 | ||
| 394 | long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask, | 393 | long 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, | |||
| 871 | long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask, | 871 | long 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 | |||
| 896 | Efault: | ||
| 897 | user_access_end(); | ||
| 898 | return -EFAULT; | ||
| 911 | } | 899 | } |
| 912 | 900 | ||
| 913 | long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask, | 901 | long 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; |
| 924 | Efault: | ||
| 925 | user_access_end(); | ||
| 926 | return -EFAULT; | ||
| 952 | } | 927 | } |
| 953 | 928 | ||
| 954 | void | 929 | void |
