semctl(): move compat to native

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

Al Viro c0ebccb6 45a4a64a

+133 -197
+33 -197
ipc/compat.c
··· 39 39 char mtext[1]; 40 40 }; 41 41 42 - struct compat_semid_ds { 43 - struct compat_ipc_perm sem_perm; 44 - compat_time_t sem_otime; 45 - compat_time_t sem_ctime; 46 - compat_uptr_t sem_base; 47 - compat_uptr_t sem_pending; 48 - compat_uptr_t sem_pending_last; 49 - compat_uptr_t undo; 50 - unsigned short sem_nsems; 51 - }; 52 - 53 42 struct compat_ipc_kludge { 54 43 compat_uptr_t msgp; 55 44 compat_long_t msgtyp; 56 45 }; 57 46 58 - static inline int __compat_ipc_parse_version(int *cmd) 47 + int get_compat_ipc64_perm(struct ipc64_perm *to, 48 + struct compat_ipc64_perm __user *from) 59 49 { 60 - #ifdef CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION 61 - int version = *cmd & IPC_64; 62 - 63 - /* this is tricky: architectures that have support for the old 64 - * ipc structures in 64 bit binaries need to have IPC_64 set 65 - * in cmd, the others need to have it cleared */ 66 - #ifndef ipc_parse_version 67 - *cmd |= IPC_64; 68 - #else 69 - *cmd &= ~IPC_64; 70 - #endif 71 - return version; 72 - #else 73 - /* With the asm-generic APIs, we always use the 64-bit versions. */ 74 - return IPC_64; 75 - #endif 76 - } 77 - 78 - static inline int __get_compat_ipc64_perm(struct ipc64_perm *p64, 79 - struct compat_ipc64_perm __user *up64) 80 - { 81 - int err; 82 - 83 - err = __get_user(p64->uid, &up64->uid); 84 - err |= __get_user(p64->gid, &up64->gid); 85 - err |= __get_user(p64->mode, &up64->mode); 86 - return err; 87 - } 88 - 89 - static inline int __get_compat_ipc_perm(struct ipc64_perm *p, 90 - struct compat_ipc_perm __user *up) 91 - { 92 - int err; 93 - 94 - err = __get_user(p->uid, &up->uid); 95 - err |= __get_user(p->gid, &up->gid); 96 - err |= __get_user(p->mode, &up->mode); 97 - return err; 98 - } 99 - 100 - static inline int __put_compat_ipc64_perm(struct ipc64_perm *p64, 101 - struct compat_ipc64_perm __user *up64) 102 - { 103 - int err; 104 - 105 - err = __put_user(p64->key, &up64->key); 106 - err |= __put_user(p64->uid, &up64->uid); 107 - err |= __put_user(p64->gid, &up64->gid); 108 - err |= __put_user(p64->cuid, &up64->cuid); 109 - err |= __put_user(p64->cgid, &up64->cgid); 110 - err |= __put_user(p64->mode, &up64->mode); 111 - err |= __put_user(p64->seq, &up64->seq); 112 - return err; 113 - } 114 - 115 - static inline int __put_compat_ipc_perm(struct ipc64_perm *p, 116 - struct compat_ipc_perm __user *uip) 117 - { 118 - int err; 119 - __compat_uid_t u; 120 - __compat_gid_t g; 121 - 122 - err = __put_user(p->key, &uip->key); 123 - SET_UID(u, p->uid); 124 - err |= __put_user(u, &uip->uid); 125 - SET_GID(g, p->gid); 126 - err |= __put_user(g, &uip->gid); 127 - SET_UID(u, p->cuid); 128 - err |= __put_user(u, &uip->cuid); 129 - SET_GID(g, p->cgid); 130 - err |= __put_user(g, &uip->cgid); 131 - err |= __put_user(p->mode, &uip->mode); 132 - err |= __put_user(p->seq, &uip->seq); 133 - return err; 134 - } 135 - 136 - static inline int get_compat_semid64_ds(struct semid64_ds *sem64, 137 - struct compat_semid64_ds __user *up64) 138 - { 139 - if (!access_ok(VERIFY_READ, up64, sizeof(*up64))) 50 + struct compat_ipc64_perm v; 51 + if (copy_from_user(&v, from, sizeof(v))) 140 52 return -EFAULT; 141 - return __get_compat_ipc64_perm(&sem64->sem_perm, &up64->sem_perm); 53 + to->uid = v.uid; 54 + to->gid = v.gid; 55 + to->mode = v.mode; 56 + return 0; 142 57 } 143 58 144 - static inline int get_compat_semid_ds(struct semid64_ds *s, 145 - struct compat_semid_ds __user *up) 59 + int get_compat_ipc_perm(struct ipc64_perm *to, 60 + struct compat_ipc_perm __user *from) 146 61 { 147 - if (!access_ok(VERIFY_READ, up, sizeof(*up))) 62 + struct compat_ipc_perm v; 63 + if (copy_from_user(&v, from, sizeof(v))) 148 64 return -EFAULT; 149 - return __get_compat_ipc_perm(&s->sem_perm, &up->sem_perm); 65 + to->uid = v.uid; 66 + to->gid = v.gid; 67 + to->mode = v.mode; 68 + return 0; 150 69 } 151 70 152 - static inline int put_compat_semid64_ds(struct semid64_ds *sem64, 153 - struct compat_semid64_ds __user *up64) 71 + void to_compat_ipc64_perm(struct compat_ipc64_perm *to, struct ipc64_perm *from) 154 72 { 155 - int err; 156 - 157 - if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) 158 - return -EFAULT; 159 - err = __put_compat_ipc64_perm(&sem64->sem_perm, &up64->sem_perm); 160 - err |= __put_user(sem64->sem_otime, &up64->sem_otime); 161 - err |= __put_user(sem64->sem_ctime, &up64->sem_ctime); 162 - err |= __put_user(sem64->sem_nsems, &up64->sem_nsems); 163 - return err; 73 + to->key = from->key; 74 + to->uid = from->uid; 75 + to->gid = from->gid; 76 + to->cuid = from->cuid; 77 + to->cgid = from->cgid; 78 + to->mode = from->mode; 79 + to->seq = from->seq; 164 80 } 165 81 166 - static inline int put_compat_semid_ds(struct semid64_ds *s, 167 - struct compat_semid_ds __user *up) 82 + void to_compat_ipc_perm(struct compat_ipc_perm *to, struct ipc64_perm *from) 168 83 { 169 - int err; 170 - 171 - if (!access_ok(VERIFY_WRITE, up, sizeof(*up))) 172 - return -EFAULT; 173 - err = __put_compat_ipc_perm(&s->sem_perm, &up->sem_perm); 174 - err |= __put_user(s->sem_otime, &up->sem_otime); 175 - err |= __put_user(s->sem_ctime, &up->sem_ctime); 176 - err |= __put_user(s->sem_nsems, &up->sem_nsems); 177 - return err; 178 - } 179 - 180 - static long do_compat_semctl(int first, int second, int third, u32 pad) 181 - { 182 - unsigned long fourth; 183 - int err, err2; 184 - struct semid64_ds sem64; 185 - struct semid64_ds __user *up64; 186 - int version = __compat_ipc_parse_version(&third); 187 - 188 - memset(&sem64, 0, sizeof(sem64)); 189 - 190 - if ((third & (~IPC_64)) == SETVAL) 191 - #ifdef __BIG_ENDIAN 192 - fourth = (unsigned long)pad << 32; 193 - #else 194 - fourth = pad; 195 - #endif 196 - else 197 - fourth = (unsigned long)compat_ptr(pad); 198 - switch (third & (~IPC_64)) { 199 - case IPC_INFO: 200 - case IPC_RMID: 201 - case SEM_INFO: 202 - case GETVAL: 203 - case GETPID: 204 - case GETNCNT: 205 - case GETZCNT: 206 - case GETALL: 207 - case SETVAL: 208 - case SETALL: 209 - err = sys_semctl(first, second, third, fourth); 210 - break; 211 - 212 - case IPC_STAT: 213 - case SEM_STAT: 214 - up64 = compat_alloc_user_space(sizeof(sem64)); 215 - fourth = (unsigned long)up64; 216 - err = sys_semctl(first, second, third, fourth); 217 - if (err < 0) 218 - break; 219 - if (copy_from_user(&sem64, up64, sizeof(sem64))) 220 - err2 = -EFAULT; 221 - else if (version == IPC_64) 222 - err2 = put_compat_semid64_ds(&sem64, compat_ptr(pad)); 223 - else 224 - err2 = put_compat_semid_ds(&sem64, compat_ptr(pad)); 225 - if (err2) 226 - err = -EFAULT; 227 - break; 228 - 229 - case IPC_SET: 230 - if (version == IPC_64) 231 - err = get_compat_semid64_ds(&sem64, compat_ptr(pad)); 232 - else 233 - err = get_compat_semid_ds(&sem64, compat_ptr(pad)); 234 - 235 - up64 = compat_alloc_user_space(sizeof(sem64)); 236 - if (copy_to_user(up64, &sem64, sizeof(sem64))) 237 - err = -EFAULT; 238 - if (err) 239 - break; 240 - 241 - fourth = (unsigned long)up64; 242 - err = sys_semctl(first, second, third, fourth); 243 - break; 244 - 245 - default: 246 - err = -EINVAL; 247 - break; 248 - } 249 - return err; 84 + to->key = from->key; 85 + SET_UID(to->uid, from->uid); 86 + SET_GID(to->gid, from->gid); 87 + SET_UID(to->cuid, from->cuid); 88 + SET_GID(to->cgid, from->cgid); 89 + to->mode = from->mode; 90 + to->seq = from->seq; 250 91 } 251 92 252 93 static long compat_do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz) ··· 132 291 return -EINVAL; 133 292 if (get_user(pad, (u32 __user *) compat_ptr(ptr))) 134 293 return -EFAULT; 135 - return do_compat_semctl(first, second, third, pad); 294 + return compat_sys_semctl(first, second, third, pad); 136 295 137 296 case MSGSND: { 138 297 struct compat_msgbuf __user *up = compat_ptr(ptr); ··· 192 351 return -ENOSYS; 193 352 } 194 353 #endif 195 - 196 - COMPAT_SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, int, arg) 197 - { 198 - return do_compat_semctl(semid, semnum, cmd, arg); 199 - } 200 354 201 355 COMPAT_SYSCALL_DEFINE4(msgsnd, int, msqid, compat_uptr_t, msgp, 202 356 compat_ssize_t, msgsz, int, msgflg)
+94
ipc/sem.c
··· 1617 1617 } 1618 1618 } 1619 1619 1620 + #ifdef CONFIG_COMPAT 1621 + 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 + #endif 1713 + 1620 1714 /* If the task doesn't already have a undo_list, then allocate one 1621 1715 * here. We guarantee there is only one thread using this undo list, 1622 1716 * and current is THE ONE
+6
ipc/util.h
··· 204 204 unsigned short seq; 205 205 }; 206 206 207 + void to_compat_ipc_perm(struct compat_ipc_perm *, struct ipc64_perm *); 208 + void to_compat_ipc64_perm(struct compat_ipc64_perm *, struct ipc64_perm *); 209 + int get_compat_ipc_perm(struct ipc64_perm *, struct compat_ipc_perm __user *); 210 + int get_compat_ipc64_perm(struct ipc64_perm *, 211 + struct compat_ipc64_perm __user *); 212 + 207 213 static inline int compat_ipc_parse_version(int *cmd) 208 214 { 209 215 #ifdef CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION