aboutsummaryrefslogtreecommitdiffstats
path: root/ipc/sem.c
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/sem.c')
-rw-r--r--ipc/sem.c123
1 files changed, 76 insertions, 47 deletions
diff --git a/ipc/sem.c b/ipc/sem.c
index 58d31f1c1eb5..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,32 +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#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
1160asmlinkage long SyS_semctl(int semid, int semnum, int cmd, union semun arg)
1161{
1162 return SYSC_semctl((int) semid, (int) semnum, (int) cmd, arg);
1163}
1164SYSCALL_ALIAS(sys_semctl, SyS_semctl);
1165#endif
1166 1195
1167/* 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
1168 * 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,