compat.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757
  1. /*
  2. * 32 bit compatibility code for System V IPC
  3. *
  4. * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  5. * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
  6. * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com>
  7. * Copyright (C) 2000 VA Linux Co
  8. * Copyright (C) 2000 Don Dugger <n0ano@valinux.com>
  9. * Copyright (C) 2000 Hewlett-Packard Co.
  10. * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
  11. * Copyright (C) 2000 Gerhard Tonn (ton@de.ibm.com)
  12. * Copyright (C) 2000-2002 Andi Kleen, SuSE Labs (x86-64 port)
  13. * Copyright (C) 2000 Silicon Graphics, Inc.
  14. * Copyright (C) 2001 IBM
  15. * Copyright (C) 2004 IBM Deutschland Entwicklung GmbH, IBM Corporation
  16. * Copyright (C) 2004 Arnd Bergmann (arnd@arndb.de)
  17. *
  18. * This code is collected from the versions for sparc64, mips64, s390x, ia64,
  19. * ppc64 and x86_64, all of which are based on the original sparc64 version
  20. * by Jakub Jelinek.
  21. *
  22. */
  23. #include <linux/compat.h>
  24. #include <linux/errno.h>
  25. #include <linux/highuid.h>
  26. #include <linux/init.h>
  27. #include <linux/msg.h>
  28. #include <linux/shm.h>
  29. #include <linux/syscalls.h>
  30. #include <linux/ptrace.h>
  31. #include <linux/mutex.h>
  32. #include <linux/uaccess.h>
  33. #include "util.h"
  34. struct compat_msgbuf {
  35. compat_long_t mtype;
  36. char mtext[1];
  37. };
  38. struct compat_ipc_perm {
  39. key_t key;
  40. __compat_uid_t uid;
  41. __compat_gid_t gid;
  42. __compat_uid_t cuid;
  43. __compat_gid_t cgid;
  44. compat_mode_t mode;
  45. unsigned short seq;
  46. };
  47. struct compat_semid_ds {
  48. struct compat_ipc_perm sem_perm;
  49. compat_time_t sem_otime;
  50. compat_time_t sem_ctime;
  51. compat_uptr_t sem_base;
  52. compat_uptr_t sem_pending;
  53. compat_uptr_t sem_pending_last;
  54. compat_uptr_t undo;
  55. unsigned short sem_nsems;
  56. };
  57. struct compat_msqid_ds {
  58. struct compat_ipc_perm msg_perm;
  59. compat_uptr_t msg_first;
  60. compat_uptr_t msg_last;
  61. compat_time_t msg_stime;
  62. compat_time_t msg_rtime;
  63. compat_time_t msg_ctime;
  64. compat_ulong_t msg_lcbytes;
  65. compat_ulong_t msg_lqbytes;
  66. unsigned short msg_cbytes;
  67. unsigned short msg_qnum;
  68. unsigned short msg_qbytes;
  69. compat_ipc_pid_t msg_lspid;
  70. compat_ipc_pid_t msg_lrpid;
  71. };
  72. struct compat_shmid_ds {
  73. struct compat_ipc_perm shm_perm;
  74. int shm_segsz;
  75. compat_time_t shm_atime;
  76. compat_time_t shm_dtime;
  77. compat_time_t shm_ctime;
  78. compat_ipc_pid_t shm_cpid;
  79. compat_ipc_pid_t shm_lpid;
  80. unsigned short shm_nattch;
  81. unsigned short shm_unused;
  82. compat_uptr_t shm_unused2;
  83. compat_uptr_t shm_unused3;
  84. };
  85. struct compat_ipc_kludge {
  86. compat_uptr_t msgp;
  87. compat_long_t msgtyp;
  88. };
  89. struct compat_shminfo64 {
  90. compat_ulong_t shmmax;
  91. compat_ulong_t shmmin;
  92. compat_ulong_t shmmni;
  93. compat_ulong_t shmseg;
  94. compat_ulong_t shmall;
  95. compat_ulong_t __unused1;
  96. compat_ulong_t __unused2;
  97. compat_ulong_t __unused3;
  98. compat_ulong_t __unused4;
  99. };
  100. struct compat_shm_info {
  101. compat_int_t used_ids;
  102. compat_ulong_t shm_tot, shm_rss, shm_swp;
  103. compat_ulong_t swap_attempts, swap_successes;
  104. };
  105. static inline int compat_ipc_parse_version(int *cmd)
  106. {
  107. #ifdef CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION
  108. int version = *cmd & IPC_64;
  109. /* this is tricky: architectures that have support for the old
  110. * ipc structures in 64 bit binaries need to have IPC_64 set
  111. * in cmd, the others need to have it cleared */
  112. #ifndef ipc_parse_version
  113. *cmd |= IPC_64;
  114. #else
  115. *cmd &= ~IPC_64;
  116. #endif
  117. return version;
  118. #else
  119. /* With the asm-generic APIs, we always use the 64-bit versions. */
  120. return IPC_64;
  121. #endif
  122. }
  123. static inline int __get_compat_ipc64_perm(struct ipc64_perm *p64,
  124. struct compat_ipc64_perm __user *up64)
  125. {
  126. int err;
  127. err = __get_user(p64->uid, &up64->uid);
  128. err |= __get_user(p64->gid, &up64->gid);
  129. err |= __get_user(p64->mode, &up64->mode);
  130. return err;
  131. }
  132. static inline int __get_compat_ipc_perm(struct ipc64_perm *p,
  133. struct compat_ipc_perm __user *up)
  134. {
  135. int err;
  136. err = __get_user(p->uid, &up->uid);
  137. err |= __get_user(p->gid, &up->gid);
  138. err |= __get_user(p->mode, &up->mode);
  139. return err;
  140. }
  141. static inline int __put_compat_ipc64_perm(struct ipc64_perm *p64,
  142. struct compat_ipc64_perm __user *up64)
  143. {
  144. int err;
  145. err = __put_user(p64->key, &up64->key);
  146. err |= __put_user(p64->uid, &up64->uid);
  147. err |= __put_user(p64->gid, &up64->gid);
  148. err |= __put_user(p64->cuid, &up64->cuid);
  149. err |= __put_user(p64->cgid, &up64->cgid);
  150. err |= __put_user(p64->mode, &up64->mode);
  151. err |= __put_user(p64->seq, &up64->seq);
  152. return err;
  153. }
  154. static inline int __put_compat_ipc_perm(struct ipc64_perm *p,
  155. struct compat_ipc_perm __user *uip)
  156. {
  157. int err;
  158. __compat_uid_t u;
  159. __compat_gid_t g;
  160. err = __put_user(p->key, &uip->key);
  161. SET_UID(u, p->uid);
  162. err |= __put_user(u, &uip->uid);
  163. SET_GID(g, p->gid);
  164. err |= __put_user(g, &uip->gid);
  165. SET_UID(u, p->cuid);
  166. err |= __put_user(u, &uip->cuid);
  167. SET_GID(g, p->cgid);
  168. err |= __put_user(g, &uip->cgid);
  169. err |= __put_user(p->mode, &uip->mode);
  170. err |= __put_user(p->seq, &uip->seq);
  171. return err;
  172. }
  173. static inline int get_compat_semid64_ds(struct semid64_ds *sem64,
  174. struct compat_semid64_ds __user *up64)
  175. {
  176. if (!access_ok(VERIFY_READ, up64, sizeof(*up64)))
  177. return -EFAULT;
  178. return __get_compat_ipc64_perm(&sem64->sem_perm, &up64->sem_perm);
  179. }
  180. static inline int get_compat_semid_ds(struct semid64_ds *s,
  181. struct compat_semid_ds __user *up)
  182. {
  183. if (!access_ok(VERIFY_READ, up, sizeof(*up)))
  184. return -EFAULT;
  185. return __get_compat_ipc_perm(&s->sem_perm, &up->sem_perm);
  186. }
  187. static inline int put_compat_semid64_ds(struct semid64_ds *sem64,
  188. struct compat_semid64_ds __user *up64)
  189. {
  190. int err;
  191. if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
  192. return -EFAULT;
  193. err = __put_compat_ipc64_perm(&sem64->sem_perm, &up64->sem_perm);
  194. err |= __put_user(sem64->sem_otime, &up64->sem_otime);
  195. err |= __put_user(sem64->sem_ctime, &up64->sem_ctime);
  196. err |= __put_user(sem64->sem_nsems, &up64->sem_nsems);
  197. return err;
  198. }
  199. static inline int put_compat_semid_ds(struct semid64_ds *s,
  200. struct compat_semid_ds __user *up)
  201. {
  202. int err;
  203. if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
  204. return -EFAULT;
  205. err = __put_compat_ipc_perm(&s->sem_perm, &up->sem_perm);
  206. err |= __put_user(s->sem_otime, &up->sem_otime);
  207. err |= __put_user(s->sem_ctime, &up->sem_ctime);
  208. err |= __put_user(s->sem_nsems, &up->sem_nsems);
  209. return err;
  210. }
  211. static long do_compat_semctl(int first, int second, int third, u32 pad)
  212. {
  213. unsigned long fourth;
  214. int err, err2;
  215. struct semid64_ds sem64;
  216. struct semid64_ds __user *up64;
  217. int version = compat_ipc_parse_version(&third);
  218. memset(&sem64, 0, sizeof(sem64));
  219. if ((third & (~IPC_64)) == SETVAL)
  220. #ifdef __BIG_ENDIAN
  221. fourth = (unsigned long)pad << 32;
  222. #else
  223. fourth = pad;
  224. #endif
  225. else
  226. fourth = (unsigned long)compat_ptr(pad);
  227. switch (third & (~IPC_64)) {
  228. case IPC_INFO:
  229. case IPC_RMID:
  230. case SEM_INFO:
  231. case GETVAL:
  232. case GETPID:
  233. case GETNCNT:
  234. case GETZCNT:
  235. case GETALL:
  236. case SETVAL:
  237. case SETALL:
  238. err = sys_semctl(first, second, third, fourth);
  239. break;
  240. case IPC_STAT:
  241. case SEM_STAT:
  242. up64 = compat_alloc_user_space(sizeof(sem64));
  243. fourth = (unsigned long)up64;
  244. err = sys_semctl(first, second, third, fourth);
  245. if (err < 0)
  246. break;
  247. if (copy_from_user(&sem64, up64, sizeof(sem64)))
  248. err2 = -EFAULT;
  249. else if (version == IPC_64)
  250. err2 = put_compat_semid64_ds(&sem64, compat_ptr(pad));
  251. else
  252. err2 = put_compat_semid_ds(&sem64, compat_ptr(pad));
  253. if (err2)
  254. err = -EFAULT;
  255. break;
  256. case IPC_SET:
  257. if (version == IPC_64)
  258. err = get_compat_semid64_ds(&sem64, compat_ptr(pad));
  259. else
  260. err = get_compat_semid_ds(&sem64, compat_ptr(pad));
  261. up64 = compat_alloc_user_space(sizeof(sem64));
  262. if (copy_to_user(up64, &sem64, sizeof(sem64)))
  263. err = -EFAULT;
  264. if (err)
  265. break;
  266. fourth = (unsigned long)up64;
  267. err = sys_semctl(first, second, third, fourth);
  268. break;
  269. default:
  270. err = -EINVAL;
  271. break;
  272. }
  273. return err;
  274. }
  275. static long compat_do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz)
  276. {
  277. struct compat_msgbuf __user *msgp = dest;
  278. size_t msgsz;
  279. if (put_user(msg->m_type, &msgp->mtype))
  280. return -EFAULT;
  281. msgsz = (bufsz > msg->m_ts) ? msg->m_ts : bufsz;
  282. if (store_msg(msgp->mtext, msg, msgsz))
  283. return -EFAULT;
  284. return msgsz;
  285. }
  286. #ifndef COMPAT_SHMLBA
  287. #define COMPAT_SHMLBA SHMLBA
  288. #endif
  289. #ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC
  290. COMPAT_SYSCALL_DEFINE6(ipc, u32, call, int, first, int, second,
  291. u32, third, compat_uptr_t, ptr, u32, fifth)
  292. {
  293. int version;
  294. u32 pad;
  295. version = call >> 16; /* hack for backward compatibility */
  296. call &= 0xffff;
  297. switch (call) {
  298. case SEMOP:
  299. /* struct sembuf is the same on 32 and 64bit :)) */
  300. return sys_semtimedop(first, compat_ptr(ptr), second, NULL);
  301. case SEMTIMEDOP:
  302. return compat_sys_semtimedop(first, compat_ptr(ptr), second,
  303. compat_ptr(fifth));
  304. case SEMGET:
  305. return sys_semget(first, second, third);
  306. case SEMCTL:
  307. if (!ptr)
  308. return -EINVAL;
  309. if (get_user(pad, (u32 __user *) compat_ptr(ptr)))
  310. return -EFAULT;
  311. return do_compat_semctl(first, second, third, pad);
  312. case MSGSND: {
  313. struct compat_msgbuf __user *up = compat_ptr(ptr);
  314. compat_long_t type;
  315. if (first < 0 || second < 0)
  316. return -EINVAL;
  317. if (get_user(type, &up->mtype))
  318. return -EFAULT;
  319. return do_msgsnd(first, type, up->mtext, second, third);
  320. }
  321. case MSGRCV: {
  322. void __user *uptr = compat_ptr(ptr);
  323. if (first < 0 || second < 0)
  324. return -EINVAL;
  325. if (!version) {
  326. struct compat_ipc_kludge ipck;
  327. if (!uptr)
  328. return -EINVAL;
  329. if (copy_from_user(&ipck, uptr, sizeof(ipck)))
  330. return -EFAULT;
  331. uptr = compat_ptr(ipck.msgp);
  332. fifth = ipck.msgtyp;
  333. }
  334. return do_msgrcv(first, uptr, second, (s32)fifth, third,
  335. compat_do_msg_fill);
  336. }
  337. case MSGGET:
  338. return sys_msgget(first, second);
  339. case MSGCTL:
  340. return compat_sys_msgctl(first, second, compat_ptr(ptr));
  341. case SHMAT: {
  342. int err;
  343. unsigned long raddr;
  344. if (version == 1)
  345. return -EINVAL;
  346. err = do_shmat(first, compat_ptr(ptr), second, &raddr,
  347. COMPAT_SHMLBA);
  348. if (err < 0)
  349. return err;
  350. return put_user(raddr, (compat_ulong_t *)compat_ptr(third));
  351. }
  352. case SHMDT:
  353. return sys_shmdt(compat_ptr(ptr));
  354. case SHMGET:
  355. return sys_shmget(first, (unsigned)second, third);
  356. case SHMCTL:
  357. return compat_sys_shmctl(first, second, compat_ptr(ptr));
  358. }
  359. return -ENOSYS;
  360. }
  361. #endif
  362. COMPAT_SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, int, arg)
  363. {
  364. return do_compat_semctl(semid, semnum, cmd, arg);
  365. }
  366. COMPAT_SYSCALL_DEFINE4(msgsnd, int, msqid, compat_uptr_t, msgp,
  367. compat_ssize_t, msgsz, int, msgflg)
  368. {
  369. struct compat_msgbuf __user *up = compat_ptr(msgp);
  370. compat_long_t mtype;
  371. if (get_user(mtype, &up->mtype))
  372. return -EFAULT;
  373. return do_msgsnd(msqid, mtype, up->mtext, (ssize_t)msgsz, msgflg);
  374. }
  375. COMPAT_SYSCALL_DEFINE5(msgrcv, int, msqid, compat_uptr_t, msgp,
  376. compat_ssize_t, msgsz, compat_long_t, msgtyp, int, msgflg)
  377. {
  378. return do_msgrcv(msqid, compat_ptr(msgp), (ssize_t)msgsz, (long)msgtyp,
  379. msgflg, compat_do_msg_fill);
  380. }
  381. static inline int get_compat_msqid64(struct msqid64_ds *m64,
  382. struct compat_msqid64_ds __user *up64)
  383. {
  384. int err;
  385. if (!access_ok(VERIFY_READ, up64, sizeof(*up64)))
  386. return -EFAULT;
  387. err = __get_compat_ipc64_perm(&m64->msg_perm, &up64->msg_perm);
  388. err |= __get_user(m64->msg_qbytes, &up64->msg_qbytes);
  389. return err;
  390. }
  391. static inline int get_compat_msqid(struct msqid64_ds *m,
  392. struct compat_msqid_ds __user *up)
  393. {
  394. int err;
  395. if (!access_ok(VERIFY_READ, up, sizeof(*up)))
  396. return -EFAULT;
  397. err = __get_compat_ipc_perm(&m->msg_perm, &up->msg_perm);
  398. err |= __get_user(m->msg_qbytes, &up->msg_qbytes);
  399. return err;
  400. }
  401. static inline int put_compat_msqid64_ds(struct msqid64_ds *m64,
  402. struct compat_msqid64_ds __user *up64)
  403. {
  404. int err;
  405. if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
  406. return -EFAULT;
  407. err = __put_compat_ipc64_perm(&m64->msg_perm, &up64->msg_perm);
  408. err |= __put_user(m64->msg_stime, &up64->msg_stime);
  409. err |= __put_user(m64->msg_rtime, &up64->msg_rtime);
  410. err |= __put_user(m64->msg_ctime, &up64->msg_ctime);
  411. err |= __put_user(m64->msg_cbytes, &up64->msg_cbytes);
  412. err |= __put_user(m64->msg_qnum, &up64->msg_qnum);
  413. err |= __put_user(m64->msg_qbytes, &up64->msg_qbytes);
  414. err |= __put_user(m64->msg_lspid, &up64->msg_lspid);
  415. err |= __put_user(m64->msg_lrpid, &up64->msg_lrpid);
  416. return err;
  417. }
  418. static inline int put_compat_msqid_ds(struct msqid64_ds *m,
  419. struct compat_msqid_ds __user *up)
  420. {
  421. int err;
  422. if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
  423. return -EFAULT;
  424. err = __put_compat_ipc_perm(&m->msg_perm, &up->msg_perm);
  425. err |= __put_user(m->msg_stime, &up->msg_stime);
  426. err |= __put_user(m->msg_rtime, &up->msg_rtime);
  427. err |= __put_user(m->msg_ctime, &up->msg_ctime);
  428. err |= __put_user(m->msg_cbytes, &up->msg_cbytes);
  429. err |= __put_user(m->msg_qnum, &up->msg_qnum);
  430. err |= __put_user(m->msg_qbytes, &up->msg_qbytes);
  431. err |= __put_user(m->msg_lspid, &up->msg_lspid);
  432. err |= __put_user(m->msg_lrpid, &up->msg_lrpid);
  433. return err;
  434. }
  435. COMPAT_SYSCALL_DEFINE3(msgctl, int, first, int, second, void __user *, uptr)
  436. {
  437. int err, err2;
  438. struct msqid64_ds m64;
  439. int version = compat_ipc_parse_version(&second);
  440. void __user *p;
  441. memset(&m64, 0, sizeof(m64));
  442. switch (second & (~IPC_64)) {
  443. case IPC_INFO:
  444. case IPC_RMID:
  445. case MSG_INFO:
  446. err = sys_msgctl(first, second, uptr);
  447. break;
  448. case IPC_SET:
  449. if (version == IPC_64)
  450. err = get_compat_msqid64(&m64, uptr);
  451. else
  452. err = get_compat_msqid(&m64, uptr);
  453. if (err)
  454. break;
  455. p = compat_alloc_user_space(sizeof(m64));
  456. if (copy_to_user(p, &m64, sizeof(m64)))
  457. err = -EFAULT;
  458. else
  459. err = sys_msgctl(first, second, p);
  460. break;
  461. case IPC_STAT:
  462. case MSG_STAT:
  463. p = compat_alloc_user_space(sizeof(m64));
  464. err = sys_msgctl(first, second, p);
  465. if (err < 0)
  466. break;
  467. if (copy_from_user(&m64, p, sizeof(m64)))
  468. err2 = -EFAULT;
  469. else if (version == IPC_64)
  470. err2 = put_compat_msqid64_ds(&m64, uptr);
  471. else
  472. err2 = put_compat_msqid_ds(&m64, uptr);
  473. if (err2)
  474. err = -EFAULT;
  475. break;
  476. default:
  477. err = -EINVAL;
  478. break;
  479. }
  480. return err;
  481. }
  482. COMPAT_SYSCALL_DEFINE3(shmat, int, shmid, compat_uptr_t, shmaddr, int, shmflg)
  483. {
  484. unsigned long ret;
  485. long err;
  486. err = do_shmat(shmid, compat_ptr(shmaddr), shmflg, &ret, COMPAT_SHMLBA);
  487. if (err)
  488. return err;
  489. force_successful_syscall_return();
  490. return (long)ret;
  491. }
  492. static inline int get_compat_shmid64_ds(struct shmid64_ds *sem64,
  493. struct compat_shmid64_ds __user *up64)
  494. {
  495. if (!access_ok(VERIFY_READ, up64, sizeof(*up64)))
  496. return -EFAULT;
  497. return __get_compat_ipc64_perm(&sem64->shm_perm, &up64->shm_perm);
  498. }
  499. static inline int get_compat_shmid_ds(struct shmid64_ds *s,
  500. struct compat_shmid_ds __user *up)
  501. {
  502. if (!access_ok(VERIFY_READ, up, sizeof(*up)))
  503. return -EFAULT;
  504. return __get_compat_ipc_perm(&s->shm_perm, &up->shm_perm);
  505. }
  506. static inline int put_compat_shmid64_ds(struct shmid64_ds *sem64,
  507. struct compat_shmid64_ds __user *up64)
  508. {
  509. int err;
  510. if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
  511. return -EFAULT;
  512. err = __put_compat_ipc64_perm(&sem64->shm_perm, &up64->shm_perm);
  513. err |= __put_user(sem64->shm_atime, &up64->shm_atime);
  514. err |= __put_user(sem64->shm_dtime, &up64->shm_dtime);
  515. err |= __put_user(sem64->shm_ctime, &up64->shm_ctime);
  516. err |= __put_user(sem64->shm_segsz, &up64->shm_segsz);
  517. err |= __put_user(sem64->shm_nattch, &up64->shm_nattch);
  518. err |= __put_user(sem64->shm_cpid, &up64->shm_cpid);
  519. err |= __put_user(sem64->shm_lpid, &up64->shm_lpid);
  520. return err;
  521. }
  522. static inline int put_compat_shmid_ds(struct shmid64_ds *s,
  523. struct compat_shmid_ds __user *up)
  524. {
  525. int err;
  526. if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
  527. return -EFAULT;
  528. err = __put_compat_ipc_perm(&s->shm_perm, &up->shm_perm);
  529. err |= __put_user(s->shm_atime, &up->shm_atime);
  530. err |= __put_user(s->shm_dtime, &up->shm_dtime);
  531. err |= __put_user(s->shm_ctime, &up->shm_ctime);
  532. err |= __put_user(s->shm_segsz, &up->shm_segsz);
  533. err |= __put_user(s->shm_nattch, &up->shm_nattch);
  534. err |= __put_user(s->shm_cpid, &up->shm_cpid);
  535. err |= __put_user(s->shm_lpid, &up->shm_lpid);
  536. return err;
  537. }
  538. static inline int put_compat_shminfo64(struct shminfo64 *smi,
  539. struct compat_shminfo64 __user *up64)
  540. {
  541. int err;
  542. if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
  543. return -EFAULT;
  544. if (smi->shmmax > INT_MAX)
  545. smi->shmmax = INT_MAX;
  546. err = __put_user(smi->shmmax, &up64->shmmax);
  547. err |= __put_user(smi->shmmin, &up64->shmmin);
  548. err |= __put_user(smi->shmmni, &up64->shmmni);
  549. err |= __put_user(smi->shmseg, &up64->shmseg);
  550. err |= __put_user(smi->shmall, &up64->shmall);
  551. return err;
  552. }
  553. static inline int put_compat_shminfo(struct shminfo64 *smi,
  554. struct shminfo __user *up)
  555. {
  556. int err;
  557. if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
  558. return -EFAULT;
  559. if (smi->shmmax > INT_MAX)
  560. smi->shmmax = INT_MAX;
  561. err = __put_user(smi->shmmax, &up->shmmax);
  562. err |= __put_user(smi->shmmin, &up->shmmin);
  563. err |= __put_user(smi->shmmni, &up->shmmni);
  564. err |= __put_user(smi->shmseg, &up->shmseg);
  565. err |= __put_user(smi->shmall, &up->shmall);
  566. return err;
  567. }
  568. static inline int put_compat_shm_info(struct shm_info __user *ip,
  569. struct compat_shm_info __user *uip)
  570. {
  571. int err;
  572. struct shm_info si;
  573. if (!access_ok(VERIFY_WRITE, uip, sizeof(*uip)) ||
  574. copy_from_user(&si, ip, sizeof(si)))
  575. return -EFAULT;
  576. err = __put_user(si.used_ids, &uip->used_ids);
  577. err |= __put_user(si.shm_tot, &uip->shm_tot);
  578. err |= __put_user(si.shm_rss, &uip->shm_rss);
  579. err |= __put_user(si.shm_swp, &uip->shm_swp);
  580. err |= __put_user(si.swap_attempts, &uip->swap_attempts);
  581. err |= __put_user(si.swap_successes, &uip->swap_successes);
  582. return err;
  583. }
  584. COMPAT_SYSCALL_DEFINE3(shmctl, int, first, int, second, void __user *, uptr)
  585. {
  586. void __user *p;
  587. struct shmid64_ds sem64;
  588. struct shminfo64 smi;
  589. int err, err2;
  590. int version = compat_ipc_parse_version(&second);
  591. memset(&sem64, 0, sizeof(sem64));
  592. switch (second & (~IPC_64)) {
  593. case IPC_RMID:
  594. case SHM_LOCK:
  595. case SHM_UNLOCK:
  596. err = sys_shmctl(first, second, uptr);
  597. break;
  598. case IPC_INFO:
  599. p = compat_alloc_user_space(sizeof(smi));
  600. err = sys_shmctl(first, second, p);
  601. if (err < 0)
  602. break;
  603. if (copy_from_user(&smi, p, sizeof(smi)))
  604. err2 = -EFAULT;
  605. else if (version == IPC_64)
  606. err2 = put_compat_shminfo64(&smi, uptr);
  607. else
  608. err2 = put_compat_shminfo(&smi, uptr);
  609. if (err2)
  610. err = -EFAULT;
  611. break;
  612. case IPC_SET:
  613. if (version == IPC_64)
  614. err = get_compat_shmid64_ds(&sem64, uptr);
  615. else
  616. err = get_compat_shmid_ds(&sem64, uptr);
  617. if (err)
  618. break;
  619. p = compat_alloc_user_space(sizeof(sem64));
  620. if (copy_to_user(p, &sem64, sizeof(sem64)))
  621. err = -EFAULT;
  622. else
  623. err = sys_shmctl(first, second, p);
  624. break;
  625. case IPC_STAT:
  626. case SHM_STAT:
  627. p = compat_alloc_user_space(sizeof(sem64));
  628. err = sys_shmctl(first, second, p);
  629. if (err < 0)
  630. break;
  631. if (copy_from_user(&sem64, p, sizeof(sem64)))
  632. err2 = -EFAULT;
  633. else if (version == IPC_64)
  634. err2 = put_compat_shmid64_ds(&sem64, uptr);
  635. else
  636. err2 = put_compat_shmid_ds(&sem64, uptr);
  637. if (err2)
  638. err = -EFAULT;
  639. break;
  640. case SHM_INFO:
  641. p = compat_alloc_user_space(sizeof(struct shm_info));
  642. err = sys_shmctl(first, second, p);
  643. if (err < 0)
  644. break;
  645. err2 = put_compat_shm_info(p, uptr);
  646. if (err2)
  647. err = -EFAULT;
  648. break;
  649. default:
  650. err = -EINVAL;
  651. break;
  652. }
  653. return err;
  654. }
  655. COMPAT_SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsems,
  656. unsigned, nsops,
  657. const struct compat_timespec __user *, timeout)
  658. {
  659. struct timespec __user *ts64;
  660. if (compat_convert_timespec(&ts64, timeout))
  661. return -EFAULT;
  662. return sys_semtimedop(semid, tsems, nsops, ts64);
  663. }