···1617 }1618}161900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001620/* If the task doesn't already have a undo_list, then allocate one1621 * here. We guarantee there is only one thread using this undo list,1622 * and current is THE ONE
···1617 }1618}16191620+#ifdef CONFIG_COMPAT1621+1622+struct compat_semid_ds {1623+ struct compat_ipc_perm sem_perm;1624+ compat_time_t sem_otime;1625+ compat_time_t sem_ctime;1626+ compat_uptr_t sem_base;1627+ compat_uptr_t sem_pending;1628+ compat_uptr_t sem_pending_last;1629+ compat_uptr_t undo;1630+ unsigned short sem_nsems;1631+};1632+1633+static int copy_compat_semid_from_user(struct semid64_ds *out, void __user *buf,1634+ int version)1635+{1636+ memset(out, 0, sizeof(*out));1637+ if (version == IPC_64) {1638+ struct compat_semid64_ds *p = buf;1639+ return get_compat_ipc64_perm(&out->sem_perm, &p->sem_perm);1640+ } else {1641+ struct compat_semid_ds *p = buf;1642+ return get_compat_ipc_perm(&out->sem_perm, &p->sem_perm);1643+ }1644+}1645+1646+static int copy_compat_semid_to_user(void __user *buf, struct semid64_ds *in,1647+ int version)1648+{1649+ if (version == IPC_64) {1650+ struct compat_semid64_ds v;1651+ memset(&v, 0, sizeof(v));1652+ to_compat_ipc64_perm(&v.sem_perm, &in->sem_perm);1653+ v.sem_otime = in->sem_otime;1654+ v.sem_ctime = in->sem_ctime;1655+ v.sem_nsems = in->sem_nsems;1656+ return copy_to_user(buf, &v, sizeof(v));1657+ } else {1658+ struct compat_semid_ds v;1659+ memset(&v, 0, sizeof(v));1660+ to_compat_ipc_perm(&v.sem_perm, &in->sem_perm);1661+ v.sem_otime = in->sem_otime;1662+ v.sem_ctime = in->sem_ctime;1663+ v.sem_nsems = in->sem_nsems;1664+ return copy_to_user(buf, &v, sizeof(v));1665+ }1666+}1667+1668+COMPAT_SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, int, arg)1669+{1670+ void __user *p = compat_ptr(arg);1671+ struct ipc_namespace *ns;1672+ struct semid64_ds semid64;1673+ int version = compat_ipc_parse_version(&cmd);1674+ int err;1675+1676+ ns = current->nsproxy->ipc_ns;1677+1678+ if (semid < 0)1679+ return -EINVAL;1680+1681+ switch (cmd & (~IPC_64)) {1682+ case IPC_INFO:1683+ case SEM_INFO:1684+ return semctl_info(ns, semid, cmd, p);1685+ case IPC_STAT:1686+ case SEM_STAT:1687+ err = semctl_stat(ns, semid, cmd, &semid64);1688+ if (err < 0)1689+ return err;1690+ if (copy_compat_semid_to_user(p, &semid64, version))1691+ err = -EFAULT;1692+ return err;1693+ case GETVAL:1694+ case GETPID:1695+ case GETNCNT:1696+ case GETZCNT:1697+ case GETALL:1698+ case SETALL:1699+ return semctl_main(ns, semid, semnum, cmd, p);1700+ case SETVAL:1701+ return semctl_setval(ns, semid, semnum, arg);1702+ case IPC_SET:1703+ if (copy_compat_semid_from_user(&semid64, p, version))1704+ return -EFAULT;1705+ /* fallthru */1706+ case IPC_RMID:1707+ return semctl_down(ns, semid, cmd, &semid64);1708+ default:1709+ return -EINVAL;1710+ }1711+}1712+#endif1713+1714/* If the task doesn't already have a undo_list, then allocate one1715 * here. We guarantee there is only one thread using this undo list,1716 * and current is THE ONE
+6
ipc/util.h
···204 unsigned short seq;205};206000000207static inline int compat_ipc_parse_version(int *cmd)208{209#ifdef CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION