aboutsummaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2017-07-09 09:11:00 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2017-07-15 20:46:44 -0400
commit45a4a64ab485d5c3e76ee79163a24303bf5077fd (patch)
tree2aa465fe39e8162604afb1435bdbb6731538270d /ipc
parent4693916846269d633a3664586650dbfac2c5562f (diff)
semctl(): separate all layout-dependent copyin/copyout
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'ipc')
-rw-r--r--ipc/sem.c192
1 files changed, 94 insertions, 98 deletions
diff --git a/ipc/sem.c b/ipc/sem.c
index 9e70cd7a17da..c8029c6bef72 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -1177,112 +1177,95 @@ static time_t get_semotime(struct sem_array *sma)
1177 return res; 1177 return res;
1178} 1178}
1179 1179
1180static int semctl_nolock(struct ipc_namespace *ns, int semid, 1180static int semctl_stat(struct ipc_namespace *ns, int semid,
1181 int cmd, int version, void __user *p) 1181 int cmd, struct semid64_ds *semid64)
1182{ 1182{
1183 int err;
1184 struct sem_array *sma; 1183 struct sem_array *sma;
1184 int id = 0;
1185 int err;
1185 1186
1186 switch (cmd) { 1187 memset(semid64, 0, sizeof(*semid64));
1187 case IPC_INFO:
1188 case SEM_INFO:
1189 {
1190 struct seminfo seminfo;
1191 int max_id;
1192
1193 err = security_sem_semctl(NULL, cmd);
1194 if (err)
1195 return err;
1196 1188
1197 memset(&seminfo, 0, sizeof(seminfo)); 1189 rcu_read_lock();
1198 seminfo.semmni = ns->sc_semmni; 1190 if (cmd == SEM_STAT) {
1199 seminfo.semmns = ns->sc_semmns; 1191 sma = sem_obtain_object(ns, semid);
1200 seminfo.semmsl = ns->sc_semmsl; 1192 if (IS_ERR(sma)) {
1201 seminfo.semopm = ns->sc_semopm; 1193 err = PTR_ERR(sma);
1202 seminfo.semvmx = SEMVMX; 1194 goto out_unlock;
1203 seminfo.semmnu = SEMMNU; 1195 }
1204 seminfo.semmap = SEMMAP; 1196 id = sma->sem_perm.id;
1205 seminfo.semume = SEMUME; 1197 } else {
1206 down_read(&sem_ids(ns).rwsem); 1198 sma = sem_obtain_object_check(ns, semid);
1207 if (cmd == SEM_INFO) { 1199 if (IS_ERR(sma)) {
1208 seminfo.semusz = sem_ids(ns).in_use; 1200 err = PTR_ERR(sma);
1209 seminfo.semaem = ns->used_sems; 1201 goto out_unlock;
1210 } else {
1211 seminfo.semusz = SEMUSZ;
1212 seminfo.semaem = SEMAEM;
1213 } 1202 }
1214 max_id = ipc_get_maxid(&sem_ids(ns));
1215 up_read(&sem_ids(ns).rwsem);
1216 if (copy_to_user(p, &seminfo, sizeof(struct seminfo)))
1217 return -EFAULT;
1218 return (max_id < 0) ? 0 : max_id;
1219 } 1203 }
1220 case IPC_STAT:
1221 case SEM_STAT:
1222 {
1223 struct semid64_ds tbuf;
1224 int id = 0;
1225
1226 memset(&tbuf, 0, sizeof(tbuf));
1227 1204
1228 rcu_read_lock(); 1205 err = -EACCES;
1229 if (cmd == SEM_STAT) { 1206 if (ipcperms(ns, &sma->sem_perm, S_IRUGO))
1230 sma = sem_obtain_object(ns, semid); 1207 goto out_unlock;
1231 if (IS_ERR(sma)) {
1232 err = PTR_ERR(sma);
1233 goto out_unlock;
1234 }
1235 id = sma->sem_perm.id;
1236 } else {
1237 sma = sem_obtain_object_check(ns, semid);
1238 if (IS_ERR(sma)) {
1239 err = PTR_ERR(sma);
1240 goto out_unlock;
1241 }
1242 }
1243 1208
1244 err = -EACCES; 1209 err = security_sem_semctl(sma, cmd);
1245 if (ipcperms(ns, &sma->sem_perm, S_IRUGO)) 1210 if (err)
1246 goto out_unlock; 1211 goto out_unlock;
1247 1212
1248 err = security_sem_semctl(sma, cmd); 1213 kernel_to_ipc64_perm(&sma->sem_perm, &semid64->sem_perm);
1249 if (err) 1214 semid64->sem_otime = get_semotime(sma);
1250 goto out_unlock; 1215 semid64->sem_ctime = sma->sem_ctime;
1216 semid64->sem_nsems = sma->sem_nsems;
1217 rcu_read_unlock();
1218 return id;
1251 1219
1252 kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm);
1253 tbuf.sem_otime = get_semotime(sma);
1254 tbuf.sem_ctime = sma->sem_ctime;
1255 tbuf.sem_nsems = sma->sem_nsems;
1256 rcu_read_unlock();
1257 if (copy_semid_to_user(p, &tbuf, version))
1258 return -EFAULT;
1259 return id;
1260 }
1261 default:
1262 return -EINVAL;
1263 }
1264out_unlock: 1220out_unlock:
1265 rcu_read_unlock(); 1221 rcu_read_unlock();
1266 return err; 1222 return err;
1267} 1223}
1268 1224
1225static int semctl_info(struct ipc_namespace *ns, int semid,
1226 int cmd, void __user *p)
1227{
1228 struct seminfo seminfo;
1229 int max_id;
1230 int err;
1231
1232 err = security_sem_semctl(NULL, cmd);
1233 if (err)
1234 return err;
1235
1236 memset(&seminfo, 0, sizeof(seminfo));
1237 seminfo.semmni = ns->sc_semmni;
1238 seminfo.semmns = ns->sc_semmns;
1239 seminfo.semmsl = ns->sc_semmsl;
1240 seminfo.semopm = ns->sc_semopm;
1241 seminfo.semvmx = SEMVMX;
1242 seminfo.semmnu = SEMMNU;
1243 seminfo.semmap = SEMMAP;
1244 seminfo.semume = SEMUME;
1245 down_read(&sem_ids(ns).rwsem);
1246 if (cmd == SEM_INFO) {
1247 seminfo.semusz = sem_ids(ns).in_use;
1248 seminfo.semaem = ns->used_sems;
1249 } else {
1250 seminfo.semusz = SEMUSZ;
1251 seminfo.semaem = SEMAEM;
1252 }
1253 max_id = ipc_get_maxid(&sem_ids(ns));
1254 up_read(&sem_ids(ns).rwsem);
1255 if (copy_to_user(p, &seminfo, sizeof(struct seminfo)))
1256 return -EFAULT;
1257 return (max_id < 0) ? 0 : max_id;
1258}
1259
1269static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum, 1260static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum,
1270 unsigned long arg) 1261 int val)
1271{ 1262{
1272 struct sem_undo *un; 1263 struct sem_undo *un;
1273 struct sem_array *sma; 1264 struct sem_array *sma;
1274 struct sem *curr; 1265 struct sem *curr;
1275 int err, val; 1266 int err;
1276 DEFINE_WAKE_Q(wake_q); 1267 DEFINE_WAKE_Q(wake_q);
1277 1268
1278#if defined(CONFIG_64BIT) && defined(__BIG_ENDIAN)
1279 /* big-endian 64bit */
1280 val = arg >> 32;
1281#else
1282 /* 32bit or little-endian 64bit */
1283 val = arg;
1284#endif
1285
1286 if (val > SEMVMX || val < 0) 1269 if (val > SEMVMX || val < 0)
1287 return -ERANGE; 1270 return -ERANGE;
1288 1271
@@ -1531,23 +1514,17 @@ copy_semid_from_user(struct semid64_ds *out, void __user *buf, int version)
1531 * NOTE: no locks must be held, the rwsem is taken inside this function. 1514 * NOTE: no locks must be held, the rwsem is taken inside this function.
1532 */ 1515 */
1533static int semctl_down(struct ipc_namespace *ns, int semid, 1516static int semctl_down(struct ipc_namespace *ns, int semid,
1534 int cmd, int version, void __user *p) 1517 int cmd, struct semid64_ds *semid64)
1535{ 1518{
1536 struct sem_array *sma; 1519 struct sem_array *sma;
1537 int err; 1520 int err;
1538 struct semid64_ds semid64;
1539 struct kern_ipc_perm *ipcp; 1521 struct kern_ipc_perm *ipcp;
1540 1522
1541 if (cmd == IPC_SET) {
1542 if (copy_semid_from_user(&semid64, p, version))
1543 return -EFAULT;
1544 }
1545
1546 down_write(&sem_ids(ns).rwsem); 1523 down_write(&sem_ids(ns).rwsem);
1547 rcu_read_lock(); 1524 rcu_read_lock();
1548 1525
1549 ipcp = ipcctl_pre_down_nolock(ns, &sem_ids(ns), semid, cmd, 1526 ipcp = ipcctl_pre_down_nolock(ns, &sem_ids(ns), semid, cmd,
1550 &semid64.sem_perm, 0); 1527 &semid64->sem_perm, 0);
1551 if (IS_ERR(ipcp)) { 1528 if (IS_ERR(ipcp)) {
1552 err = PTR_ERR(ipcp); 1529 err = PTR_ERR(ipcp);
1553 goto out_unlock1; 1530 goto out_unlock1;
@@ -1567,7 +1544,7 @@ static int semctl_down(struct ipc_namespace *ns, int semid,
1567 goto out_up; 1544 goto out_up;
1568 case IPC_SET: 1545 case IPC_SET:
1569 sem_lock(sma, NULL, -1); 1546 sem_lock(sma, NULL, -1);
1570 err = ipc_update_perm(&semid64.sem_perm, ipcp); 1547 err = ipc_update_perm(&semid64->sem_perm, ipcp);
1571 if (err) 1548 if (err)
1572 goto out_unlock0; 1549 goto out_unlock0;
1573 sma->sem_ctime = get_seconds(); 1550 sma->sem_ctime = get_seconds();
@@ -1591,6 +1568,8 @@ SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, unsigned long, arg)
1591 int version; 1568 int version;
1592 struct ipc_namespace *ns; 1569 struct ipc_namespace *ns;
1593 void __user *p = (void __user *)arg; 1570 void __user *p = (void __user *)arg;
1571 struct semid64_ds semid64;
1572 int err;
1594 1573
1595 if (semid < 0) 1574 if (semid < 0)
1596 return -EINVAL; 1575 return -EINVAL;
@@ -1601,9 +1580,15 @@ SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, unsigned long, arg)
1601 switch (cmd) { 1580 switch (cmd) {
1602 case IPC_INFO: 1581 case IPC_INFO:
1603 case SEM_INFO: 1582 case SEM_INFO:
1583 return semctl_info(ns, semid, cmd, p);
1604 case IPC_STAT: 1584 case IPC_STAT:
1605 case SEM_STAT: 1585 case SEM_STAT:
1606 return semctl_nolock(ns, semid, cmd, version, p); 1586 err = semctl_stat(ns, semid, cmd, &semid64);
1587 if (err < 0)
1588 return err;
1589 if (copy_semid_to_user(p, &semid64, version))
1590 err = -EFAULT;
1591 return err;
1607 case GETALL: 1592 case GETALL:
1608 case GETVAL: 1593 case GETVAL:
1609 case GETPID: 1594 case GETPID:
@@ -1611,11 +1596,22 @@ SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, unsigned long, arg)
1611 case GETZCNT: 1596 case GETZCNT:
1612 case SETALL: 1597 case SETALL:
1613 return semctl_main(ns, semid, semnum, cmd, p); 1598 return semctl_main(ns, semid, semnum, cmd, p);
1614 case SETVAL: 1599 case SETVAL: {
1615 return semctl_setval(ns, semid, semnum, arg); 1600 int val;
1616 case IPC_RMID: 1601#if defined(CONFIG_64BIT) && defined(__BIG_ENDIAN)
1602 /* big-endian 64bit */
1603 val = arg >> 32;
1604#else
1605 /* 32bit or little-endian 64bit */
1606 val = arg;
1607#endif
1608 return semctl_setval(ns, semid, semnum, val);
1609 }
1617 case IPC_SET: 1610 case IPC_SET:
1618 return semctl_down(ns, semid, cmd, version, p); 1611 if (copy_semid_from_user(&semid64, p, version))
1612 return -EFAULT;
1613 case IPC_RMID:
1614 return semctl_down(ns, semid, cmd, &semid64);
1619 default: 1615 default:
1620 return -EINVAL; 1616 return -EINVAL;
1621 } 1617 }