diff options
Diffstat (limited to 'ipc/sem.c')
-rw-r--r-- | ipc/sem.c | 344 |
1 files changed, 228 insertions, 116 deletions
@@ -512,7 +512,7 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params) | |||
512 | INIT_LIST_HEAD(&sma->pending_const); | 512 | INIT_LIST_HEAD(&sma->pending_const); |
513 | INIT_LIST_HEAD(&sma->list_id); | 513 | INIT_LIST_HEAD(&sma->list_id); |
514 | sma->sem_nsems = nsems; | 514 | sma->sem_nsems = nsems; |
515 | sma->sem_ctime = get_seconds(); | 515 | sma->sem_ctime = ktime_get_real_seconds(); |
516 | 516 | ||
517 | retval = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni); | 517 | retval = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni); |
518 | if (retval < 0) { | 518 | if (retval < 0) { |
@@ -1163,14 +1163,14 @@ static unsigned long copy_semid_to_user(void __user *buf, struct semid64_ds *in, | |||
1163 | } | 1163 | } |
1164 | } | 1164 | } |
1165 | 1165 | ||
1166 | static time_t get_semotime(struct sem_array *sma) | 1166 | static time64_t get_semotime(struct sem_array *sma) |
1167 | { | 1167 | { |
1168 | int i; | 1168 | int i; |
1169 | time_t res; | 1169 | time64_t res; |
1170 | 1170 | ||
1171 | res = sma->sems[0].sem_otime; | 1171 | res = sma->sems[0].sem_otime; |
1172 | for (i = 1; i < sma->sem_nsems; i++) { | 1172 | for (i = 1; i < sma->sem_nsems; i++) { |
1173 | time_t to = sma->sems[i].sem_otime; | 1173 | time64_t to = sma->sems[i].sem_otime; |
1174 | 1174 | ||
1175 | if (to > res) | 1175 | if (to > res) |
1176 | res = to; | 1176 | res = to; |
@@ -1178,112 +1178,95 @@ static time_t get_semotime(struct sem_array *sma) | |||
1178 | return res; | 1178 | return res; |
1179 | } | 1179 | } |
1180 | 1180 | ||
1181 | static int semctl_nolock(struct ipc_namespace *ns, int semid, | 1181 | static int semctl_stat(struct ipc_namespace *ns, int semid, |
1182 | int cmd, int version, void __user *p) | 1182 | int cmd, struct semid64_ds *semid64) |
1183 | { | 1183 | { |
1184 | int err; | ||
1185 | struct sem_array *sma; | 1184 | struct sem_array *sma; |
1185 | int id = 0; | ||
1186 | int err; | ||
1186 | 1187 | ||
1187 | switch (cmd) { | 1188 | memset(semid64, 0, sizeof(*semid64)); |
1188 | case IPC_INFO: | ||
1189 | case SEM_INFO: | ||
1190 | { | ||
1191 | struct seminfo seminfo; | ||
1192 | int max_id; | ||
1193 | |||
1194 | err = security_sem_semctl(NULL, cmd); | ||
1195 | if (err) | ||
1196 | return err; | ||
1197 | 1189 | ||
1198 | memset(&seminfo, 0, sizeof(seminfo)); | 1190 | rcu_read_lock(); |
1199 | seminfo.semmni = ns->sc_semmni; | 1191 | if (cmd == SEM_STAT) { |
1200 | seminfo.semmns = ns->sc_semmns; | 1192 | sma = sem_obtain_object(ns, semid); |
1201 | seminfo.semmsl = ns->sc_semmsl; | 1193 | if (IS_ERR(sma)) { |
1202 | seminfo.semopm = ns->sc_semopm; | 1194 | err = PTR_ERR(sma); |
1203 | seminfo.semvmx = SEMVMX; | 1195 | goto out_unlock; |
1204 | seminfo.semmnu = SEMMNU; | 1196 | } |
1205 | seminfo.semmap = SEMMAP; | 1197 | id = sma->sem_perm.id; |
1206 | seminfo.semume = SEMUME; | 1198 | } else { |
1207 | down_read(&sem_ids(ns).rwsem); | 1199 | sma = sem_obtain_object_check(ns, semid); |
1208 | if (cmd == SEM_INFO) { | 1200 | if (IS_ERR(sma)) { |
1209 | seminfo.semusz = sem_ids(ns).in_use; | 1201 | err = PTR_ERR(sma); |
1210 | seminfo.semaem = ns->used_sems; | 1202 | goto out_unlock; |
1211 | } else { | ||
1212 | seminfo.semusz = SEMUSZ; | ||
1213 | seminfo.semaem = SEMAEM; | ||
1214 | } | 1203 | } |
1215 | max_id = ipc_get_maxid(&sem_ids(ns)); | ||
1216 | up_read(&sem_ids(ns).rwsem); | ||
1217 | if (copy_to_user(p, &seminfo, sizeof(struct seminfo))) | ||
1218 | return -EFAULT; | ||
1219 | return (max_id < 0) ? 0 : max_id; | ||
1220 | } | 1204 | } |
1221 | case IPC_STAT: | ||
1222 | case SEM_STAT: | ||
1223 | { | ||
1224 | struct semid64_ds tbuf; | ||
1225 | int id = 0; | ||
1226 | |||
1227 | memset(&tbuf, 0, sizeof(tbuf)); | ||
1228 | 1205 | ||
1229 | rcu_read_lock(); | 1206 | err = -EACCES; |
1230 | if (cmd == SEM_STAT) { | 1207 | if (ipcperms(ns, &sma->sem_perm, S_IRUGO)) |
1231 | sma = sem_obtain_object(ns, semid); | 1208 | goto out_unlock; |
1232 | if (IS_ERR(sma)) { | ||
1233 | err = PTR_ERR(sma); | ||
1234 | goto out_unlock; | ||
1235 | } | ||
1236 | id = sma->sem_perm.id; | ||
1237 | } else { | ||
1238 | sma = sem_obtain_object_check(ns, semid); | ||
1239 | if (IS_ERR(sma)) { | ||
1240 | err = PTR_ERR(sma); | ||
1241 | goto out_unlock; | ||
1242 | } | ||
1243 | } | ||
1244 | 1209 | ||
1245 | err = -EACCES; | 1210 | err = security_sem_semctl(sma, cmd); |
1246 | if (ipcperms(ns, &sma->sem_perm, S_IRUGO)) | 1211 | if (err) |
1247 | goto out_unlock; | 1212 | goto out_unlock; |
1248 | 1213 | ||
1249 | err = security_sem_semctl(sma, cmd); | 1214 | kernel_to_ipc64_perm(&sma->sem_perm, &semid64->sem_perm); |
1250 | if (err) | 1215 | semid64->sem_otime = get_semotime(sma); |
1251 | goto out_unlock; | 1216 | semid64->sem_ctime = sma->sem_ctime; |
1217 | semid64->sem_nsems = sma->sem_nsems; | ||
1218 | rcu_read_unlock(); | ||
1219 | return id; | ||
1252 | 1220 | ||
1253 | kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm); | ||
1254 | tbuf.sem_otime = get_semotime(sma); | ||
1255 | tbuf.sem_ctime = sma->sem_ctime; | ||
1256 | tbuf.sem_nsems = sma->sem_nsems; | ||
1257 | rcu_read_unlock(); | ||
1258 | if (copy_semid_to_user(p, &tbuf, version)) | ||
1259 | return -EFAULT; | ||
1260 | return id; | ||
1261 | } | ||
1262 | default: | ||
1263 | return -EINVAL; | ||
1264 | } | ||
1265 | out_unlock: | 1221 | out_unlock: |
1266 | rcu_read_unlock(); | 1222 | rcu_read_unlock(); |
1267 | return err; | 1223 | return err; |
1268 | } | 1224 | } |
1269 | 1225 | ||
1226 | static int semctl_info(struct ipc_namespace *ns, int semid, | ||
1227 | int cmd, void __user *p) | ||
1228 | { | ||
1229 | struct seminfo seminfo; | ||
1230 | int max_id; | ||
1231 | int err; | ||
1232 | |||
1233 | err = security_sem_semctl(NULL, cmd); | ||
1234 | if (err) | ||
1235 | return err; | ||
1236 | |||
1237 | memset(&seminfo, 0, sizeof(seminfo)); | ||
1238 | seminfo.semmni = ns->sc_semmni; | ||
1239 | seminfo.semmns = ns->sc_semmns; | ||
1240 | seminfo.semmsl = ns->sc_semmsl; | ||
1241 | seminfo.semopm = ns->sc_semopm; | ||
1242 | seminfo.semvmx = SEMVMX; | ||
1243 | seminfo.semmnu = SEMMNU; | ||
1244 | seminfo.semmap = SEMMAP; | ||
1245 | seminfo.semume = SEMUME; | ||
1246 | down_read(&sem_ids(ns).rwsem); | ||
1247 | if (cmd == SEM_INFO) { | ||
1248 | seminfo.semusz = sem_ids(ns).in_use; | ||
1249 | seminfo.semaem = ns->used_sems; | ||
1250 | } else { | ||
1251 | seminfo.semusz = SEMUSZ; | ||
1252 | seminfo.semaem = SEMAEM; | ||
1253 | } | ||
1254 | max_id = ipc_get_maxid(&sem_ids(ns)); | ||
1255 | up_read(&sem_ids(ns).rwsem); | ||
1256 | if (copy_to_user(p, &seminfo, sizeof(struct seminfo))) | ||
1257 | return -EFAULT; | ||
1258 | return (max_id < 0) ? 0 : max_id; | ||
1259 | } | ||
1260 | |||
1270 | static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum, | 1261 | static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum, |
1271 | unsigned long arg) | 1262 | int val) |
1272 | { | 1263 | { |
1273 | struct sem_undo *un; | 1264 | struct sem_undo *un; |
1274 | struct sem_array *sma; | 1265 | struct sem_array *sma; |
1275 | struct sem *curr; | 1266 | struct sem *curr; |
1276 | int err, val; | 1267 | int err; |
1277 | DEFINE_WAKE_Q(wake_q); | 1268 | DEFINE_WAKE_Q(wake_q); |
1278 | 1269 | ||
1279 | #if defined(CONFIG_64BIT) && defined(__BIG_ENDIAN) | ||
1280 | /* big-endian 64bit */ | ||
1281 | val = arg >> 32; | ||
1282 | #else | ||
1283 | /* 32bit or little-endian 64bit */ | ||
1284 | val = arg; | ||
1285 | #endif | ||
1286 | |||
1287 | if (val > SEMVMX || val < 0) | 1270 | if (val > SEMVMX || val < 0) |
1288 | return -ERANGE; | 1271 | return -ERANGE; |
1289 | 1272 | ||
@@ -1327,7 +1310,7 @@ static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum, | |||
1327 | 1310 | ||
1328 | curr->semval = val; | 1311 | curr->semval = val; |
1329 | curr->sempid = task_tgid_vnr(current); | 1312 | curr->sempid = task_tgid_vnr(current); |
1330 | sma->sem_ctime = get_seconds(); | 1313 | sma->sem_ctime = ktime_get_real_seconds(); |
1331 | /* maybe some queued-up processes were waiting for this */ | 1314 | /* maybe some queued-up processes were waiting for this */ |
1332 | do_smart_update(sma, NULL, 0, 0, &wake_q); | 1315 | do_smart_update(sma, NULL, 0, 0, &wake_q); |
1333 | sem_unlock(sma, -1); | 1316 | sem_unlock(sma, -1); |
@@ -1455,7 +1438,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, | |||
1455 | for (i = 0; i < nsems; i++) | 1438 | for (i = 0; i < nsems; i++) |
1456 | un->semadj[i] = 0; | 1439 | un->semadj[i] = 0; |
1457 | } | 1440 | } |
1458 | sma->sem_ctime = get_seconds(); | 1441 | sma->sem_ctime = ktime_get_real_seconds(); |
1459 | /* maybe some queued-up processes were waiting for this */ | 1442 | /* maybe some queued-up processes were waiting for this */ |
1460 | do_smart_update(sma, NULL, 0, 0, &wake_q); | 1443 | do_smart_update(sma, NULL, 0, 0, &wake_q); |
1461 | err = 0; | 1444 | err = 0; |
@@ -1532,23 +1515,17 @@ copy_semid_from_user(struct semid64_ds *out, void __user *buf, int version) | |||
1532 | * NOTE: no locks must be held, the rwsem is taken inside this function. | 1515 | * NOTE: no locks must be held, the rwsem is taken inside this function. |
1533 | */ | 1516 | */ |
1534 | static int semctl_down(struct ipc_namespace *ns, int semid, | 1517 | static int semctl_down(struct ipc_namespace *ns, int semid, |
1535 | int cmd, int version, void __user *p) | 1518 | int cmd, struct semid64_ds *semid64) |
1536 | { | 1519 | { |
1537 | struct sem_array *sma; | 1520 | struct sem_array *sma; |
1538 | int err; | 1521 | int err; |
1539 | struct semid64_ds semid64; | ||
1540 | struct kern_ipc_perm *ipcp; | 1522 | struct kern_ipc_perm *ipcp; |
1541 | 1523 | ||
1542 | if (cmd == IPC_SET) { | ||
1543 | if (copy_semid_from_user(&semid64, p, version)) | ||
1544 | return -EFAULT; | ||
1545 | } | ||
1546 | |||
1547 | down_write(&sem_ids(ns).rwsem); | 1524 | down_write(&sem_ids(ns).rwsem); |
1548 | rcu_read_lock(); | 1525 | rcu_read_lock(); |
1549 | 1526 | ||
1550 | ipcp = ipcctl_pre_down_nolock(ns, &sem_ids(ns), semid, cmd, | 1527 | ipcp = ipcctl_pre_down_nolock(ns, &sem_ids(ns), semid, cmd, |
1551 | &semid64.sem_perm, 0); | 1528 | &semid64->sem_perm, 0); |
1552 | if (IS_ERR(ipcp)) { | 1529 | if (IS_ERR(ipcp)) { |
1553 | err = PTR_ERR(ipcp); | 1530 | err = PTR_ERR(ipcp); |
1554 | goto out_unlock1; | 1531 | goto out_unlock1; |
@@ -1568,10 +1545,10 @@ static int semctl_down(struct ipc_namespace *ns, int semid, | |||
1568 | goto out_up; | 1545 | goto out_up; |
1569 | case IPC_SET: | 1546 | case IPC_SET: |
1570 | sem_lock(sma, NULL, -1); | 1547 | sem_lock(sma, NULL, -1); |
1571 | err = ipc_update_perm(&semid64.sem_perm, ipcp); | 1548 | err = ipc_update_perm(&semid64->sem_perm, ipcp); |
1572 | if (err) | 1549 | if (err) |
1573 | goto out_unlock0; | 1550 | goto out_unlock0; |
1574 | sma->sem_ctime = get_seconds(); | 1551 | sma->sem_ctime = ktime_get_real_seconds(); |
1575 | break; | 1552 | break; |
1576 | default: | 1553 | default: |
1577 | err = -EINVAL; | 1554 | err = -EINVAL; |
@@ -1592,6 +1569,8 @@ SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, unsigned long, arg) | |||
1592 | int version; | 1569 | int version; |
1593 | struct ipc_namespace *ns; | 1570 | struct ipc_namespace *ns; |
1594 | void __user *p = (void __user *)arg; | 1571 | void __user *p = (void __user *)arg; |
1572 | struct semid64_ds semid64; | ||
1573 | int err; | ||
1595 | 1574 | ||
1596 | if (semid < 0) | 1575 | if (semid < 0) |
1597 | return -EINVAL; | 1576 | return -EINVAL; |
@@ -1602,9 +1581,15 @@ SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, unsigned long, arg) | |||
1602 | switch (cmd) { | 1581 | switch (cmd) { |
1603 | case IPC_INFO: | 1582 | case IPC_INFO: |
1604 | case SEM_INFO: | 1583 | case SEM_INFO: |
1584 | return semctl_info(ns, semid, cmd, p); | ||
1605 | case IPC_STAT: | 1585 | case IPC_STAT: |
1606 | case SEM_STAT: | 1586 | case SEM_STAT: |
1607 | return semctl_nolock(ns, semid, cmd, version, p); | 1587 | err = semctl_stat(ns, semid, cmd, &semid64); |
1588 | if (err < 0) | ||
1589 | return err; | ||
1590 | if (copy_semid_to_user(p, &semid64, version)) | ||
1591 | err = -EFAULT; | ||
1592 | return err; | ||
1608 | case GETALL: | 1593 | case GETALL: |
1609 | case GETVAL: | 1594 | case GETVAL: |
1610 | case GETPID: | 1595 | case GETPID: |
@@ -1612,15 +1597,120 @@ SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, unsigned long, arg) | |||
1612 | case GETZCNT: | 1597 | case GETZCNT: |
1613 | case SETALL: | 1598 | case SETALL: |
1614 | return semctl_main(ns, semid, semnum, cmd, p); | 1599 | return semctl_main(ns, semid, semnum, cmd, p); |
1600 | case SETVAL: { | ||
1601 | int val; | ||
1602 | #if defined(CONFIG_64BIT) && defined(__BIG_ENDIAN) | ||
1603 | /* big-endian 64bit */ | ||
1604 | val = arg >> 32; | ||
1605 | #else | ||
1606 | /* 32bit or little-endian 64bit */ | ||
1607 | val = arg; | ||
1608 | #endif | ||
1609 | return semctl_setval(ns, semid, semnum, val); | ||
1610 | } | ||
1611 | case IPC_SET: | ||
1612 | if (copy_semid_from_user(&semid64, p, version)) | ||
1613 | return -EFAULT; | ||
1614 | case IPC_RMID: | ||
1615 | return semctl_down(ns, semid, cmd, &semid64); | ||
1616 | default: | ||
1617 | return -EINVAL; | ||
1618 | } | ||
1619 | } | ||
1620 | |||
1621 | #ifdef CONFIG_COMPAT | ||
1622 | |||
1623 | struct compat_semid_ds { | ||
1624 | struct compat_ipc_perm sem_perm; | ||
1625 | compat_time_t sem_otime; | ||
1626 | compat_time_t sem_ctime; | ||
1627 | compat_uptr_t sem_base; | ||
1628 | compat_uptr_t sem_pending; | ||
1629 | compat_uptr_t sem_pending_last; | ||
1630 | compat_uptr_t undo; | ||
1631 | unsigned short sem_nsems; | ||
1632 | }; | ||
1633 | |||
1634 | static int copy_compat_semid_from_user(struct semid64_ds *out, void __user *buf, | ||
1635 | int version) | ||
1636 | { | ||
1637 | memset(out, 0, sizeof(*out)); | ||
1638 | if (version == IPC_64) { | ||
1639 | struct compat_semid64_ds *p = buf; | ||
1640 | return get_compat_ipc64_perm(&out->sem_perm, &p->sem_perm); | ||
1641 | } else { | ||
1642 | struct compat_semid_ds *p = buf; | ||
1643 | return get_compat_ipc_perm(&out->sem_perm, &p->sem_perm); | ||
1644 | } | ||
1645 | } | ||
1646 | |||
1647 | static int copy_compat_semid_to_user(void __user *buf, struct semid64_ds *in, | ||
1648 | int version) | ||
1649 | { | ||
1650 | if (version == IPC_64) { | ||
1651 | struct compat_semid64_ds v; | ||
1652 | memset(&v, 0, sizeof(v)); | ||
1653 | to_compat_ipc64_perm(&v.sem_perm, &in->sem_perm); | ||
1654 | v.sem_otime = in->sem_otime; | ||
1655 | v.sem_ctime = in->sem_ctime; | ||
1656 | v.sem_nsems = in->sem_nsems; | ||
1657 | return copy_to_user(buf, &v, sizeof(v)); | ||
1658 | } else { | ||
1659 | struct compat_semid_ds v; | ||
1660 | memset(&v, 0, sizeof(v)); | ||
1661 | to_compat_ipc_perm(&v.sem_perm, &in->sem_perm); | ||
1662 | v.sem_otime = in->sem_otime; | ||
1663 | v.sem_ctime = in->sem_ctime; | ||
1664 | v.sem_nsems = in->sem_nsems; | ||
1665 | return copy_to_user(buf, &v, sizeof(v)); | ||
1666 | } | ||
1667 | } | ||
1668 | |||
1669 | COMPAT_SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, int, arg) | ||
1670 | { | ||
1671 | void __user *p = compat_ptr(arg); | ||
1672 | struct ipc_namespace *ns; | ||
1673 | struct semid64_ds semid64; | ||
1674 | int version = compat_ipc_parse_version(&cmd); | ||
1675 | int err; | ||
1676 | |||
1677 | ns = current->nsproxy->ipc_ns; | ||
1678 | |||
1679 | if (semid < 0) | ||
1680 | return -EINVAL; | ||
1681 | |||
1682 | switch (cmd & (~IPC_64)) { | ||
1683 | case IPC_INFO: | ||
1684 | case SEM_INFO: | ||
1685 | return semctl_info(ns, semid, cmd, p); | ||
1686 | case IPC_STAT: | ||
1687 | case SEM_STAT: | ||
1688 | err = semctl_stat(ns, semid, cmd, &semid64); | ||
1689 | if (err < 0) | ||
1690 | return err; | ||
1691 | if (copy_compat_semid_to_user(p, &semid64, version)) | ||
1692 | err = -EFAULT; | ||
1693 | return err; | ||
1694 | case GETVAL: | ||
1695 | case GETPID: | ||
1696 | case GETNCNT: | ||
1697 | case GETZCNT: | ||
1698 | case GETALL: | ||
1699 | case SETALL: | ||
1700 | return semctl_main(ns, semid, semnum, cmd, p); | ||
1615 | case SETVAL: | 1701 | case SETVAL: |
1616 | return semctl_setval(ns, semid, semnum, arg); | 1702 | return semctl_setval(ns, semid, semnum, arg); |
1617 | case IPC_RMID: | ||
1618 | case IPC_SET: | 1703 | case IPC_SET: |
1619 | return semctl_down(ns, semid, cmd, version, p); | 1704 | if (copy_compat_semid_from_user(&semid64, p, version)) |
1705 | return -EFAULT; | ||
1706 | /* fallthru */ | ||
1707 | case IPC_RMID: | ||
1708 | return semctl_down(ns, semid, cmd, &semid64); | ||
1620 | default: | 1709 | default: |
1621 | return -EINVAL; | 1710 | return -EINVAL; |
1622 | } | 1711 | } |
1623 | } | 1712 | } |
1713 | #endif | ||
1624 | 1714 | ||
1625 | /* If the task doesn't already have a undo_list, then allocate one | 1715 | /* If the task doesn't already have a undo_list, then allocate one |
1626 | * here. We guarantee there is only one thread using this undo list, | 1716 | * here. We guarantee there is only one thread using this undo list, |
@@ -1766,8 +1856,8 @@ out: | |||
1766 | return un; | 1856 | return un; |
1767 | } | 1857 | } |
1768 | 1858 | ||
1769 | SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, | 1859 | static long do_semtimedop(int semid, struct sembuf __user *tsops, |
1770 | unsigned, nsops, const struct timespec __user *, timeout) | 1860 | unsigned nsops, const struct timespec64 *timeout) |
1771 | { | 1861 | { |
1772 | int error = -EINVAL; | 1862 | int error = -EINVAL; |
1773 | struct sem_array *sma; | 1863 | struct sem_array *sma; |
@@ -1798,17 +1888,12 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, | |||
1798 | } | 1888 | } |
1799 | 1889 | ||
1800 | if (timeout) { | 1890 | if (timeout) { |
1801 | struct timespec _timeout; | 1891 | if (timeout->tv_sec < 0 || timeout->tv_nsec < 0 || |
1802 | if (copy_from_user(&_timeout, timeout, sizeof(*timeout))) { | 1892 | timeout->tv_nsec >= 1000000000L) { |
1803 | error = -EFAULT; | ||
1804 | goto out_free; | ||
1805 | } | ||
1806 | if (_timeout.tv_sec < 0 || _timeout.tv_nsec < 0 || | ||
1807 | _timeout.tv_nsec >= 1000000000L) { | ||
1808 | error = -EINVAL; | 1893 | error = -EINVAL; |
1809 | goto out_free; | 1894 | goto out_free; |
1810 | } | 1895 | } |
1811 | jiffies_left = timespec_to_jiffies(&_timeout); | 1896 | jiffies_left = timespec64_to_jiffies(timeout); |
1812 | } | 1897 | } |
1813 | 1898 | ||
1814 | max = 0; | 1899 | max = 0; |
@@ -2023,10 +2108,37 @@ out_free: | |||
2023 | return error; | 2108 | return error; |
2024 | } | 2109 | } |
2025 | 2110 | ||
2111 | SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, | ||
2112 | unsigned, nsops, const struct timespec __user *, timeout) | ||
2113 | { | ||
2114 | if (timeout) { | ||
2115 | struct timespec64 ts; | ||
2116 | if (get_timespec64(&ts, timeout)) | ||
2117 | return -EFAULT; | ||
2118 | return do_semtimedop(semid, tsops, nsops, &ts); | ||
2119 | } | ||
2120 | return do_semtimedop(semid, tsops, nsops, NULL); | ||
2121 | } | ||
2122 | |||
2123 | #ifdef CONFIG_COMPAT | ||
2124 | COMPAT_SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsems, | ||
2125 | unsigned, nsops, | ||
2126 | const struct compat_timespec __user *, timeout) | ||
2127 | { | ||
2128 | if (timeout) { | ||
2129 | struct timespec64 ts; | ||
2130 | if (compat_get_timespec64(&ts, timeout)) | ||
2131 | return -EFAULT; | ||
2132 | return do_semtimedop(semid, tsems, nsops, &ts); | ||
2133 | } | ||
2134 | return do_semtimedop(semid, tsems, nsops, NULL); | ||
2135 | } | ||
2136 | #endif | ||
2137 | |||
2026 | SYSCALL_DEFINE3(semop, int, semid, struct sembuf __user *, tsops, | 2138 | SYSCALL_DEFINE3(semop, int, semid, struct sembuf __user *, tsops, |
2027 | unsigned, nsops) | 2139 | unsigned, nsops) |
2028 | { | 2140 | { |
2029 | return sys_semtimedop(semid, tsops, nsops, NULL); | 2141 | return do_semtimedop(semid, tsops, nsops, NULL); |
2030 | } | 2142 | } |
2031 | 2143 | ||
2032 | /* If CLONE_SYSVSEM is set, establish sharing of SEM_UNDO state between | 2144 | /* If CLONE_SYSVSEM is set, establish sharing of SEM_UNDO state between |
@@ -2183,7 +2295,7 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it) | |||
2183 | struct user_namespace *user_ns = seq_user_ns(s); | 2295 | struct user_namespace *user_ns = seq_user_ns(s); |
2184 | struct kern_ipc_perm *ipcp = it; | 2296 | struct kern_ipc_perm *ipcp = it; |
2185 | struct sem_array *sma = container_of(ipcp, struct sem_array, sem_perm); | 2297 | struct sem_array *sma = container_of(ipcp, struct sem_array, sem_perm); |
2186 | time_t sem_otime; | 2298 | time64_t sem_otime; |
2187 | 2299 | ||
2188 | /* | 2300 | /* |
2189 | * The proc interface isn't aware of sem_lock(), it calls | 2301 | * The proc interface isn't aware of sem_lock(), it calls |
@@ -2196,7 +2308,7 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it) | |||
2196 | sem_otime = get_semotime(sma); | 2308 | sem_otime = get_semotime(sma); |
2197 | 2309 | ||
2198 | seq_printf(s, | 2310 | seq_printf(s, |
2199 | "%10d %10d %4o %10u %5u %5u %5u %5u %10lu %10lu\n", | 2311 | "%10d %10d %4o %10u %5u %5u %5u %5u %10llu %10llu\n", |
2200 | sma->sem_perm.key, | 2312 | sma->sem_perm.key, |
2201 | sma->sem_perm.id, | 2313 | sma->sem_perm.id, |
2202 | sma->sem_perm.mode, | 2314 | sma->sem_perm.mode, |