diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2013-03-05 15:04:55 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2013-03-05 15:14:16 -0500 |
commit | e1fd1f490fa4213bd3060efa823a39d299538f72 (patch) | |
tree | 8bed18bdf003822ef1a4946e734418cf88546c24 | |
parent | 4b377bab29e6a241db42f27541e7fb63713ee178 (diff) |
get rid of union semop in sys_semctl(2) arguments
just have the bugger take unsigned long and deal with SETVAL
case (when we use an int member in the union) explicitly.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | arch/parisc/kernel/sys_parisc32.c | 15 | ||||
-rw-r--r-- | arch/parisc/kernel/syscall_table.S | 2 | ||||
-rw-r--r-- | arch/sparc/kernel/sys_sparc_64.c | 2 | ||||
-rw-r--r-- | include/linux/syscalls.h | 2 | ||||
-rw-r--r-- | ipc/compat.c | 14 | ||||
-rw-r--r-- | ipc/sem.c | 121 | ||||
-rw-r--r-- | ipc/syscall.c | 6 |
7 files changed, 91 insertions, 71 deletions
diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c index 46bdf6080fe4..f517e08e7f0d 100644 --- a/arch/parisc/kernel/sys_parisc32.c +++ b/arch/parisc/kernel/sys_parisc32.c | |||
@@ -60,21 +60,6 @@ asmlinkage long sys32_unimplemented(int r26, int r25, int r24, int r23, | |||
60 | return -ENOSYS; | 60 | return -ENOSYS; |
61 | } | 61 | } |
62 | 62 | ||
63 | asmlinkage long sys32_semctl(int semid, int semnum, int cmd, union semun arg) | ||
64 | { | ||
65 | union semun u; | ||
66 | |||
67 | if (cmd == SETVAL) { | ||
68 | /* Ugh. arg is a union of int,ptr,ptr,ptr, so is 8 bytes. | ||
69 | * The int should be in the first 4, but our argument | ||
70 | * frobbing has left it in the last 4. | ||
71 | */ | ||
72 | u.val = *((int *)&arg + 1); | ||
73 | return sys_semctl (semid, semnum, cmd, u); | ||
74 | } | ||
75 | return sys_semctl (semid, semnum, cmd, arg); | ||
76 | } | ||
77 | |||
78 | asmlinkage long compat_sys_fanotify_mark(int fan_fd, int flags, u32 mask_hi, | 63 | asmlinkage long compat_sys_fanotify_mark(int fan_fd, int flags, u32 mask_hi, |
79 | u32 mask_lo, int fd, | 64 | u32 mask_lo, int fd, |
80 | const char __user *pathname) | 65 | const char __user *pathname) |
diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S index 30c9a3bba1cc..0c9107285e66 100644 --- a/arch/parisc/kernel/syscall_table.S +++ b/arch/parisc/kernel/syscall_table.S | |||
@@ -282,7 +282,7 @@ | |||
282 | ENTRY_COMP(recvmsg) | 282 | ENTRY_COMP(recvmsg) |
283 | ENTRY_SAME(semop) /* 185 */ | 283 | ENTRY_SAME(semop) /* 185 */ |
284 | ENTRY_SAME(semget) | 284 | ENTRY_SAME(semget) |
285 | ENTRY_DIFF(semctl) | 285 | ENTRY_COMP(semctl) |
286 | ENTRY_COMP(msgsnd) | 286 | ENTRY_COMP(msgsnd) |
287 | ENTRY_COMP(msgrcv) | 287 | ENTRY_COMP(msgrcv) |
288 | ENTRY_SAME(msgget) /* 190 */ | 288 | ENTRY_SAME(msgget) /* 190 */ |
diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c index 42beb6fc4ad8..2daaaa6eda23 100644 --- a/arch/sparc/kernel/sys_sparc_64.c +++ b/arch/sparc/kernel/sys_sparc_64.c | |||
@@ -353,7 +353,7 @@ SYSCALL_DEFINE6(sparc_ipc, unsigned int, call, int, first, unsigned long, second | |||
353 | case SEMCTL: { | 353 | case SEMCTL: { |
354 | err = sys_semctl(first, second, | 354 | err = sys_semctl(first, second, |
355 | (int)third | IPC_64, | 355 | (int)third | IPC_64, |
356 | (union semun) ptr); | 356 | (unsigned long) ptr); |
357 | goto out; | 357 | goto out; |
358 | } | 358 | } |
359 | default: | 359 | default: |
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 9660a8bdcbbe..65c001f7fa0b 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h | |||
@@ -657,7 +657,7 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf); | |||
657 | asmlinkage long sys_semget(key_t key, int nsems, int semflg); | 657 | asmlinkage long sys_semget(key_t key, int nsems, int semflg); |
658 | asmlinkage long sys_semop(int semid, struct sembuf __user *sops, | 658 | asmlinkage long sys_semop(int semid, struct sembuf __user *sops, |
659 | unsigned nsops); | 659 | unsigned nsops); |
660 | asmlinkage long sys_semctl(int semid, int semnum, int cmd, union semun arg); | 660 | asmlinkage long sys_semctl(int semid, int semnum, int cmd, unsigned long arg); |
661 | asmlinkage long sys_semtimedop(int semid, struct sembuf __user *sops, | 661 | asmlinkage long sys_semtimedop(int semid, struct sembuf __user *sops, |
662 | unsigned nsops, | 662 | unsigned nsops, |
663 | const struct timespec __user *timeout); | 663 | const struct timespec __user *timeout); |
diff --git a/ipc/compat.c b/ipc/compat.c index 6cb6a4df86e4..892f6585dd60 100644 --- a/ipc/compat.c +++ b/ipc/compat.c | |||
@@ -240,7 +240,7 @@ static inline int put_compat_semid_ds(struct semid64_ds *s, | |||
240 | 240 | ||
241 | static long do_compat_semctl(int first, int second, int third, u32 pad) | 241 | static long do_compat_semctl(int first, int second, int third, u32 pad) |
242 | { | 242 | { |
243 | union semun fourth; | 243 | unsigned long fourth; |
244 | int err, err2; | 244 | int err, err2; |
245 | struct semid64_ds s64; | 245 | struct semid64_ds s64; |
246 | struct semid64_ds __user *up64; | 246 | struct semid64_ds __user *up64; |
@@ -249,9 +249,13 @@ static long do_compat_semctl(int first, int second, int third, u32 pad) | |||
249 | memset(&s64, 0, sizeof(s64)); | 249 | memset(&s64, 0, sizeof(s64)); |
250 | 250 | ||
251 | if ((third & (~IPC_64)) == SETVAL) | 251 | if ((third & (~IPC_64)) == SETVAL) |
252 | fourth.val = (int) pad; | 252 | #ifdef __BIG_ENDIAN |
253 | fourth = (unsigned long)pad << 32; | ||
254 | #else | ||
255 | fourth = pad; | ||
256 | #endif | ||
253 | else | 257 | else |
254 | fourth.__pad = compat_ptr(pad); | 258 | fourth = (unsigned long)compat_ptr(pad); |
255 | switch (third & (~IPC_64)) { | 259 | switch (third & (~IPC_64)) { |
256 | case IPC_INFO: | 260 | case IPC_INFO: |
257 | case IPC_RMID: | 261 | case IPC_RMID: |
@@ -269,7 +273,7 @@ static long do_compat_semctl(int first, int second, int third, u32 pad) | |||
269 | case IPC_STAT: | 273 | case IPC_STAT: |
270 | case SEM_STAT: | 274 | case SEM_STAT: |
271 | up64 = compat_alloc_user_space(sizeof(s64)); | 275 | up64 = compat_alloc_user_space(sizeof(s64)); |
272 | fourth.__pad = up64; | 276 | fourth = (unsigned long)up64; |
273 | err = sys_semctl(first, second, third, fourth); | 277 | err = sys_semctl(first, second, third, fourth); |
274 | if (err < 0) | 278 | if (err < 0) |
275 | break; | 279 | break; |
@@ -295,7 +299,7 @@ static long do_compat_semctl(int first, int second, int third, u32 pad) | |||
295 | if (err) | 299 | if (err) |
296 | break; | 300 | break; |
297 | 301 | ||
298 | fourth.__pad = up64; | 302 | fourth = (unsigned long)up64; |
299 | err = sys_semctl(first, second, third, fourth); | 303 | err = sys_semctl(first, second, third, fourth); |
300 | break; | 304 | break; |
301 | 305 | ||
@@ -799,7 +799,7 @@ static unsigned long copy_semid_to_user(void __user *buf, struct semid64_ds *in, | |||
799 | } | 799 | } |
800 | 800 | ||
801 | static int semctl_nolock(struct ipc_namespace *ns, int semid, | 801 | static int semctl_nolock(struct ipc_namespace *ns, int semid, |
802 | int cmd, int version, union semun arg) | 802 | int cmd, int version, void __user *p) |
803 | { | 803 | { |
804 | int err; | 804 | int err; |
805 | struct sem_array *sma; | 805 | struct sem_array *sma; |
@@ -834,7 +834,7 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid, | |||
834 | } | 834 | } |
835 | max_id = ipc_get_maxid(&sem_ids(ns)); | 835 | max_id = ipc_get_maxid(&sem_ids(ns)); |
836 | up_read(&sem_ids(ns).rw_mutex); | 836 | up_read(&sem_ids(ns).rw_mutex); |
837 | if (copy_to_user (arg.__buf, &seminfo, sizeof(struct seminfo))) | 837 | if (copy_to_user(p, &seminfo, sizeof(struct seminfo))) |
838 | return -EFAULT; | 838 | return -EFAULT; |
839 | return (max_id < 0) ? 0: max_id; | 839 | return (max_id < 0) ? 0: max_id; |
840 | } | 840 | } |
@@ -871,7 +871,7 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid, | |||
871 | tbuf.sem_ctime = sma->sem_ctime; | 871 | tbuf.sem_ctime = sma->sem_ctime; |
872 | tbuf.sem_nsems = sma->sem_nsems; | 872 | tbuf.sem_nsems = sma->sem_nsems; |
873 | sem_unlock(sma); | 873 | sem_unlock(sma); |
874 | if (copy_semid_to_user (arg.buf, &tbuf, version)) | 874 | if (copy_semid_to_user(p, &tbuf, version)) |
875 | return -EFAULT; | 875 | return -EFAULT; |
876 | return id; | 876 | return id; |
877 | } | 877 | } |
@@ -883,8 +883,67 @@ out_unlock: | |||
883 | return err; | 883 | return err; |
884 | } | 884 | } |
885 | 885 | ||
886 | static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum, | ||
887 | unsigned long arg) | ||
888 | { | ||
889 | struct sem_undo *un; | ||
890 | struct sem_array *sma; | ||
891 | struct sem* curr; | ||
892 | int err; | ||
893 | int nsems; | ||
894 | struct list_head tasks; | ||
895 | int val; | ||
896 | #if defined(CONFIG_64BIT) && defined(__BIG_ENDIAN) | ||
897 | /* big-endian 64bit */ | ||
898 | val = arg >> 32; | ||
899 | #else | ||
900 | /* 32bit or little-endian 64bit */ | ||
901 | val = arg; | ||
902 | #endif | ||
903 | |||
904 | sma = sem_lock_check(ns, semid); | ||
905 | if (IS_ERR(sma)) | ||
906 | return PTR_ERR(sma); | ||
907 | |||
908 | INIT_LIST_HEAD(&tasks); | ||
909 | nsems = sma->sem_nsems; | ||
910 | |||
911 | err = -EACCES; | ||
912 | if (ipcperms(ns, &sma->sem_perm, S_IWUGO)) | ||
913 | goto out_unlock; | ||
914 | |||
915 | err = security_sem_semctl(sma, SETVAL); | ||
916 | if (err) | ||
917 | goto out_unlock; | ||
918 | |||
919 | err = -EINVAL; | ||
920 | if(semnum < 0 || semnum >= nsems) | ||
921 | goto out_unlock; | ||
922 | |||
923 | curr = &sma->sem_base[semnum]; | ||
924 | |||
925 | err = -ERANGE; | ||
926 | if (val > SEMVMX || val < 0) | ||
927 | goto out_unlock; | ||
928 | |||
929 | assert_spin_locked(&sma->sem_perm.lock); | ||
930 | list_for_each_entry(un, &sma->list_id, list_id) | ||
931 | un->semadj[semnum] = 0; | ||
932 | |||
933 | curr->semval = val; | ||
934 | curr->sempid = task_tgid_vnr(current); | ||
935 | sma->sem_ctime = get_seconds(); | ||
936 | /* maybe some queued-up processes were waiting for this */ | ||
937 | do_smart_update(sma, NULL, 0, 0, &tasks); | ||
938 | err = 0; | ||
939 | out_unlock: | ||
940 | sem_unlock(sma); | ||
941 | wake_up_sem_queue_do(&tasks); | ||
942 | return err; | ||
943 | } | ||
944 | |||
886 | static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, | 945 | static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, |
887 | int cmd, int version, union semun arg) | 946 | int cmd, void __user *p) |
888 | { | 947 | { |
889 | struct sem_array *sma; | 948 | struct sem_array *sma; |
890 | struct sem* curr; | 949 | struct sem* curr; |
@@ -903,7 +962,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, | |||
903 | 962 | ||
904 | err = -EACCES; | 963 | err = -EACCES; |
905 | if (ipcperms(ns, &sma->sem_perm, | 964 | if (ipcperms(ns, &sma->sem_perm, |
906 | (cmd == SETVAL || cmd == SETALL) ? S_IWUGO : S_IRUGO)) | 965 | cmd == SETALL ? S_IWUGO : S_IRUGO)) |
907 | goto out_unlock; | 966 | goto out_unlock; |
908 | 967 | ||
909 | err = security_sem_semctl(sma, cmd); | 968 | err = security_sem_semctl(sma, cmd); |
@@ -914,7 +973,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, | |||
914 | switch (cmd) { | 973 | switch (cmd) { |
915 | case GETALL: | 974 | case GETALL: |
916 | { | 975 | { |
917 | ushort __user *array = arg.array; | 976 | ushort __user *array = p; |
918 | int i; | 977 | int i; |
919 | 978 | ||
920 | if(nsems > SEMMSL_FAST) { | 979 | if(nsems > SEMMSL_FAST) { |
@@ -957,7 +1016,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, | |||
957 | } | 1016 | } |
958 | } | 1017 | } |
959 | 1018 | ||
960 | if (copy_from_user (sem_io, arg.array, nsems*sizeof(ushort))) { | 1019 | if (copy_from_user (sem_io, p, nsems*sizeof(ushort))) { |
961 | sem_putref(sma); | 1020 | sem_putref(sma); |
962 | err = -EFAULT; | 1021 | err = -EFAULT; |
963 | goto out_free; | 1022 | goto out_free; |
@@ -991,7 +1050,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, | |||
991 | err = 0; | 1050 | err = 0; |
992 | goto out_unlock; | 1051 | goto out_unlock; |
993 | } | 1052 | } |
994 | /* GETVAL, GETPID, GETNCTN, GETZCNT, SETVAL: fall-through */ | 1053 | /* GETVAL, GETPID, GETNCTN, GETZCNT: fall-through */ |
995 | } | 1054 | } |
996 | err = -EINVAL; | 1055 | err = -EINVAL; |
997 | if(semnum < 0 || semnum >= nsems) | 1056 | if(semnum < 0 || semnum >= nsems) |
@@ -1012,27 +1071,6 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, | |||
1012 | case GETZCNT: | 1071 | case GETZCNT: |
1013 | err = count_semzcnt(sma,semnum); | 1072 | err = count_semzcnt(sma,semnum); |
1014 | goto out_unlock; | 1073 | goto out_unlock; |
1015 | case SETVAL: | ||
1016 | { | ||
1017 | int val = arg.val; | ||
1018 | struct sem_undo *un; | ||
1019 | |||
1020 | err = -ERANGE; | ||
1021 | if (val > SEMVMX || val < 0) | ||
1022 | goto out_unlock; | ||
1023 | |||
1024 | assert_spin_locked(&sma->sem_perm.lock); | ||
1025 | list_for_each_entry(un, &sma->list_id, list_id) | ||
1026 | un->semadj[semnum] = 0; | ||
1027 | |||
1028 | curr->semval = val; | ||
1029 | curr->sempid = task_tgid_vnr(current); | ||
1030 | sma->sem_ctime = get_seconds(); | ||
1031 | /* maybe some queued-up processes were waiting for this */ | ||
1032 | do_smart_update(sma, NULL, 0, 0, &tasks); | ||
1033 | err = 0; | ||
1034 | goto out_unlock; | ||
1035 | } | ||
1036 | } | 1074 | } |
1037 | out_unlock: | 1075 | out_unlock: |
1038 | sem_unlock(sma); | 1076 | sem_unlock(sma); |
@@ -1076,7 +1114,7 @@ copy_semid_from_user(struct semid64_ds *out, void __user *buf, int version) | |||
1076 | * NOTE: no locks must be held, the rw_mutex is taken inside this function. | 1114 | * NOTE: no locks must be held, the rw_mutex is taken inside this function. |
1077 | */ | 1115 | */ |
1078 | static int semctl_down(struct ipc_namespace *ns, int semid, | 1116 | static int semctl_down(struct ipc_namespace *ns, int semid, |
1079 | int cmd, int version, union semun arg) | 1117 | int cmd, int version, void __user *p) |
1080 | { | 1118 | { |
1081 | struct sem_array *sma; | 1119 | struct sem_array *sma; |
1082 | int err; | 1120 | int err; |
@@ -1084,7 +1122,7 @@ static int semctl_down(struct ipc_namespace *ns, int semid, | |||
1084 | struct kern_ipc_perm *ipcp; | 1122 | struct kern_ipc_perm *ipcp; |
1085 | 1123 | ||
1086 | if(cmd == IPC_SET) { | 1124 | if(cmd == IPC_SET) { |
1087 | if (copy_semid_from_user(&semid64, arg.buf, version)) | 1125 | if (copy_semid_from_user(&semid64, p, version)) |
1088 | return -EFAULT; | 1126 | return -EFAULT; |
1089 | } | 1127 | } |
1090 | 1128 | ||
@@ -1120,11 +1158,11 @@ out_up: | |||
1120 | return err; | 1158 | return err; |
1121 | } | 1159 | } |
1122 | 1160 | ||
1123 | SYSCALL_DEFINE(semctl)(int semid, int semnum, int cmd, union semun arg) | 1161 | SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, unsigned long, arg) |
1124 | { | 1162 | { |
1125 | int err = -EINVAL; | ||
1126 | int version; | 1163 | int version; |
1127 | struct ipc_namespace *ns; | 1164 | struct ipc_namespace *ns; |
1165 | void __user *p = (void __user *)arg; | ||
1128 | 1166 | ||
1129 | if (semid < 0) | 1167 | if (semid < 0) |
1130 | return -EINVAL; | 1168 | return -EINVAL; |
@@ -1137,30 +1175,23 @@ SYSCALL_DEFINE(semctl)(int semid, int semnum, int cmd, union semun arg) | |||
1137 | case SEM_INFO: | 1175 | case SEM_INFO: |
1138 | case IPC_STAT: | 1176 | case IPC_STAT: |
1139 | case SEM_STAT: | 1177 | case SEM_STAT: |
1140 | err = semctl_nolock(ns, semid, cmd, version, arg); | 1178 | return semctl_nolock(ns, semid, cmd, version, p); |
1141 | return err; | ||
1142 | case GETALL: | 1179 | case GETALL: |
1143 | case GETVAL: | 1180 | case GETVAL: |
1144 | case GETPID: | 1181 | case GETPID: |
1145 | case GETNCNT: | 1182 | case GETNCNT: |
1146 | case GETZCNT: | 1183 | case GETZCNT: |
1147 | case SETVAL: | ||
1148 | case SETALL: | 1184 | case SETALL: |
1149 | err = semctl_main(ns,semid,semnum,cmd,version,arg); | 1185 | return semctl_main(ns, semid, semnum, cmd, p); |
1150 | return err; | 1186 | case SETVAL: |
1187 | return semctl_setval(ns, semid, semnum, arg); | ||
1151 | case IPC_RMID: | 1188 | case IPC_RMID: |
1152 | case IPC_SET: | 1189 | case IPC_SET: |
1153 | err = semctl_down(ns, semid, cmd, version, arg); | 1190 | return semctl_down(ns, semid, cmd, version, p); |
1154 | return err; | ||
1155 | default: | 1191 | default: |
1156 | return -EINVAL; | 1192 | return -EINVAL; |
1157 | } | 1193 | } |
1158 | } | 1194 | } |
1159 | asmlinkage long SyS_semctl(int semid, int semnum, int cmd, union semun arg) | ||
1160 | { | ||
1161 | return SYSC_semctl((int) semid, (int) semnum, (int) cmd, arg); | ||
1162 | } | ||
1163 | SYSCALL_ALIAS(sys_semctl, SyS_semctl); | ||
1164 | 1195 | ||
1165 | /* If the task doesn't already have a undo_list, then allocate one | 1196 | /* If the task doesn't already have a undo_list, then allocate one |
1166 | * here. We guarantee there is only one thread using this undo list, | 1197 | * here. We guarantee there is only one thread using this undo list, |
diff --git a/ipc/syscall.c b/ipc/syscall.c index 0d1e32ce048e..52429489cde0 100644 --- a/ipc/syscall.c +++ b/ipc/syscall.c | |||
@@ -33,12 +33,12 @@ SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, unsigned long, second, | |||
33 | case SEMGET: | 33 | case SEMGET: |
34 | return sys_semget(first, second, third); | 34 | return sys_semget(first, second, third); |
35 | case SEMCTL: { | 35 | case SEMCTL: { |
36 | union semun fourth; | 36 | unsigned long arg; |
37 | if (!ptr) | 37 | if (!ptr) |
38 | return -EINVAL; | 38 | return -EINVAL; |
39 | if (get_user(fourth.__pad, (void __user * __user *) ptr)) | 39 | if (get_user(arg, (unsigned long __user *) ptr)) |
40 | return -EFAULT; | 40 | return -EFAULT; |
41 | return sys_semctl(first, second, third, fourth); | 41 | return sys_semctl(first, second, third, arg); |
42 | } | 42 | } |
43 | 43 | ||
44 | case MSGSND: | 44 | case MSGSND: |