aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2013-03-05 15:04:55 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2013-03-05 15:14:16 -0500
commite1fd1f490fa4213bd3060efa823a39d299538f72 (patch)
tree8bed18bdf003822ef1a4946e734418cf88546c24
parent4b377bab29e6a241db42f27541e7fb63713ee178 (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.c15
-rw-r--r--arch/parisc/kernel/syscall_table.S2
-rw-r--r--arch/sparc/kernel/sys_sparc_64.c2
-rw-r--r--include/linux/syscalls.h2
-rw-r--r--ipc/compat.c14
-rw-r--r--ipc/sem.c121
-rw-r--r--ipc/syscall.c6
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
63asmlinkage 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
78asmlinkage long compat_sys_fanotify_mark(int fan_fd, int flags, u32 mask_hi, 63asmlinkage 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);
657asmlinkage long sys_semget(key_t key, int nsems, int semflg); 657asmlinkage long sys_semget(key_t key, int nsems, int semflg);
658asmlinkage long sys_semop(int semid, struct sembuf __user *sops, 658asmlinkage long sys_semop(int semid, struct sembuf __user *sops,
659 unsigned nsops); 659 unsigned nsops);
660asmlinkage long sys_semctl(int semid, int semnum, int cmd, union semun arg); 660asmlinkage long sys_semctl(int semid, int semnum, int cmd, unsigned long arg);
661asmlinkage long sys_semtimedop(int semid, struct sembuf __user *sops, 661asmlinkage 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
241static long do_compat_semctl(int first, int second, int third, u32 pad) 241static 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
diff --git a/ipc/sem.c b/ipc/sem.c
index e7236df7a470..5b167d00efa6 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -799,7 +799,7 @@ static unsigned long copy_semid_to_user(void __user *buf, struct semid64_ds *in,
799} 799}
800 800
801static int semctl_nolock(struct ipc_namespace *ns, int semid, 801static 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
886static 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;
939out_unlock:
940 sem_unlock(sma);
941 wake_up_sem_queue_do(&tasks);
942 return err;
943}
944
886static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, 945static 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 }
1037out_unlock: 1075out_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 */
1078static int semctl_down(struct ipc_namespace *ns, int semid, 1116static 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
1123SYSCALL_DEFINE(semctl)(int semid, int semnum, int cmd, union semun arg) 1161SYSCALL_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}
1159asmlinkage 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}
1163SYSCALL_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: