compat.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688
  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/config.h>
  25. #include <linux/errno.h>
  26. #include <linux/highuid.h>
  27. #include <linux/init.h>
  28. #include <linux/msg.h>
  29. #include <linux/shm.h>
  30. #include <linux/slab.h>
  31. #include <linux/syscalls.h>
  32. #include <asm/semaphore.h>
  33. #include <asm/uaccess.h>
  34. #include "util.h"
  35. struct compat_msgbuf {
  36. compat_long_t mtype;
  37. char mtext[1];
  38. };
  39. struct compat_ipc_perm {
  40. key_t key;
  41. __compat_uid_t uid;
  42. __compat_gid_t gid;
  43. __compat_uid_t cuid;
  44. __compat_gid_t cgid;
  45. compat_mode_t mode;
  46. unsigned short seq;
  47. };
  48. struct compat_semid_ds {
  49. struct compat_ipc_perm sem_perm;
  50. compat_time_t sem_otime;
  51. compat_time_t sem_ctime;
  52. compat_uptr_t sem_base;
  53. compat_uptr_t sem_pending;
  54. compat_uptr_t sem_pending_last;
  55. compat_uptr_t undo;
  56. unsigned short sem_nsems;
  57. };
  58. struct compat_msqid_ds {
  59. struct compat_ipc_perm msg_perm;
  60. compat_uptr_t msg_first;
  61. compat_uptr_t msg_last;
  62. compat_time_t msg_stime;
  63. compat_time_t msg_rtime;
  64. compat_time_t msg_ctime;
  65. compat_ulong_t msg_lcbytes;
  66. compat_ulong_t msg_lqbytes;
  67. unsigned short msg_cbytes;
  68. unsigned short msg_qnum;
  69. unsigned short msg_qbytes;
  70. compat_ipc_pid_t msg_lspid;
  71. compat_ipc_pid_t msg_lrpid;
  72. };
  73. struct compat_shmid_ds {
  74. struct compat_ipc_perm shm_perm;
  75. int shm_segsz;
  76. compat_time_t shm_atime;
  77. compat_time_t shm_dtime;
  78. compat_time_t shm_ctime;
  79. compat_ipc_pid_t shm_cpid;
  80. compat_ipc_pid_t shm_lpid;
  81. unsigned short shm_nattch;
  82. unsigned short shm_unused;
  83. compat_uptr_t shm_unused2;
  84. compat_uptr_t shm_unused3;
  85. };
  86. struct compat_ipc_kludge {
  87. compat_uptr_t msgp;
  88. compat_long_t msgtyp;
  89. };
  90. struct compat_shminfo64 {
  91. compat_ulong_t shmmax;
  92. compat_ulong_t shmmin;
  93. compat_ulong_t shmmni;
  94. compat_ulong_t shmseg;
  95. compat_ulong_t shmall;
  96. compat_ulong_t __unused1;
  97. compat_ulong_t __unused2;
  98. compat_ulong_t __unused3;
  99. compat_ulong_t __unused4;
  100. };
  101. struct compat_shm_info {
  102. compat_int_t used_ids;
  103. compat_ulong_t shm_tot, shm_rss, shm_swp;
  104. compat_ulong_t swap_attempts, swap_successes;
  105. };
  106. extern int sem_ctls[];
  107. #define sc_semopm (sem_ctls[2])
  108. #define MAXBUF (64*1024)
  109. static inline int compat_ipc_parse_version(int *cmd)
  110. {
  111. int version = *cmd & IPC_64;
  112. /* this is tricky: architectures that have support for the old
  113. * ipc structures in 64 bit binaries need to have IPC_64 set
  114. * in cmd, the others need to have it cleared */
  115. #ifndef ipc_parse_version
  116. *cmd |= IPC_64;
  117. #else
  118. *cmd &= ~IPC_64;
  119. #endif
  120. return version;
  121. }
  122. static inline int __get_compat_ipc64_perm(struct ipc64_perm *p64,
  123. struct compat_ipc64_perm __user *up64)
  124. {
  125. int err;
  126. err = __get_user(p64->uid, &up64->uid);
  127. err |= __get_user(p64->gid, &up64->gid);
  128. err |= __get_user(p64->mode, &up64->mode);
  129. return err;
  130. }
  131. static inline int __get_compat_ipc_perm(struct ipc64_perm *p,
  132. struct compat_ipc_perm __user *up)
  133. {
  134. int err;
  135. err = __get_user(p->uid, &up->uid);
  136. err |= __get_user(p->gid, &up->gid);
  137. err |= __get_user(p->mode, &up->mode);
  138. return err;
  139. }
  140. static inline int __put_compat_ipc64_perm(struct ipc64_perm *p64,
  141. struct compat_ipc64_perm __user *up64)
  142. {
  143. int err;
  144. err = __put_user(p64->key, &up64->key);
  145. err |= __put_user(p64->uid, &up64->uid);
  146. err |= __put_user(p64->gid, &up64->gid);
  147. err |= __put_user(p64->cuid, &up64->cuid);
  148. err |= __put_user(p64->cgid, &up64->cgid);
  149. err |= __put_user(p64->mode, &up64->mode);
  150. err |= __put_user(p64->seq, &up64->seq);
  151. return err;
  152. }
  153. static inline int __put_compat_ipc_perm(struct ipc64_perm *p,
  154. struct compat_ipc_perm __user *up)
  155. {
  156. int err;
  157. __compat_uid_t u;
  158. __compat_gid_t g;
  159. err = __put_user(p->key, &up->key);
  160. SET_UID(u, p->uid);
  161. err |= __put_user(u, &up->uid);
  162. SET_GID(g, p->gid);
  163. err |= __put_user(g, &up->gid);
  164. SET_UID(u, p->cuid);
  165. err |= __put_user(u, &up->cuid);
  166. SET_GID(g, p->cgid);
  167. err |= __put_user(g, &up->cgid);
  168. err |= __put_user(p->mode, &up->mode);
  169. err |= __put_user(p->seq, &up->seq);
  170. return err;
  171. }
  172. static inline int get_compat_semid64_ds(struct semid64_ds *s64,
  173. struct compat_semid64_ds __user *up64)
  174. {
  175. if (!access_ok (VERIFY_READ, up64, sizeof(*up64)))
  176. return -EFAULT;
  177. return __get_compat_ipc64_perm(&s64->sem_perm, &up64->sem_perm);
  178. }
  179. static inline int get_compat_semid_ds(struct semid64_ds *s,
  180. struct compat_semid_ds __user *up)
  181. {
  182. if (!access_ok (VERIFY_READ, up, sizeof(*up)))
  183. return -EFAULT;
  184. return __get_compat_ipc_perm(&s->sem_perm, &up->sem_perm);
  185. }
  186. static inline int put_compat_semid64_ds(struct semid64_ds *s64,
  187. struct compat_semid64_ds __user *up64)
  188. {
  189. int err;
  190. if (!access_ok (VERIFY_WRITE, up64, sizeof(*up64)))
  191. return -EFAULT;
  192. err = __put_compat_ipc64_perm(&s64->sem_perm, &up64->sem_perm);
  193. err |= __put_user(s64->sem_otime, &up64->sem_otime);
  194. err |= __put_user(s64->sem_ctime, &up64->sem_ctime);
  195. err |= __put_user(s64->sem_nsems, &up64->sem_nsems);
  196. return err;
  197. }
  198. static inline int put_compat_semid_ds(struct semid64_ds *s,
  199. struct compat_semid_ds __user *up)
  200. {
  201. int err;
  202. if (!access_ok (VERIFY_WRITE, up, sizeof(*up)))
  203. err = -EFAULT;
  204. err = __put_compat_ipc_perm(&s->sem_perm, &up->sem_perm);
  205. err |= __put_user(s->sem_otime, &up->sem_otime);
  206. err |= __put_user(s->sem_ctime, &up->sem_ctime);
  207. err |= __put_user(s->sem_nsems, &up->sem_nsems);
  208. return err;
  209. }
  210. long compat_sys_semctl(int first, int second, int third, void __user *uptr)
  211. {
  212. union semun fourth;
  213. u32 pad;
  214. int err, err2;
  215. struct semid64_ds s64;
  216. struct semid64_ds __user *up64;
  217. int version = compat_ipc_parse_version(&third);
  218. if (!uptr)
  219. return -EINVAL;
  220. if (get_user(pad, (u32 __user *) uptr))
  221. return -EFAULT;
  222. if ((third & (~IPC_64)) == SETVAL)
  223. fourth.val = (int) pad;
  224. else
  225. fourth.__pad = compat_ptr(pad);
  226. switch (third & (~IPC_64)) {
  227. case IPC_INFO:
  228. case IPC_RMID:
  229. case SEM_INFO:
  230. case GETVAL:
  231. case GETPID:
  232. case GETNCNT:
  233. case GETZCNT:
  234. case GETALL:
  235. case SETVAL:
  236. case SETALL:
  237. err = sys_semctl(first, second, third, fourth);
  238. break;
  239. case IPC_STAT:
  240. case SEM_STAT:
  241. up64 = compat_alloc_user_space(sizeof(s64));
  242. fourth.__pad = up64;
  243. err = sys_semctl(first, second, third, fourth);
  244. if (err < 0)
  245. break;
  246. if (copy_from_user(&s64, up64, sizeof(s64)))
  247. err2 = -EFAULT;
  248. else if (version == IPC_64)
  249. err2 = put_compat_semid64_ds(&s64, compat_ptr(pad));
  250. else
  251. err2 = put_compat_semid_ds(&s64, compat_ptr(pad));
  252. if (err2)
  253. err = -EFAULT;
  254. break;
  255. case IPC_SET:
  256. if (version == IPC_64) {
  257. err = get_compat_semid64_ds(&s64, compat_ptr(pad));
  258. } else {
  259. err = get_compat_semid_ds(&s64, compat_ptr(pad));
  260. }
  261. up64 = compat_alloc_user_space(sizeof(s64));
  262. if (copy_to_user(up64, &s64, sizeof(s64)))
  263. err = -EFAULT;
  264. if (err)
  265. break;
  266. fourth.__pad = up64;
  267. err = sys_semctl(first, second, third, fourth);
  268. break;
  269. default:
  270. err = -EINVAL;
  271. break;
  272. }
  273. return err;
  274. }
  275. long compat_sys_msgsnd(int first, int second, int third, void __user *uptr)
  276. {
  277. struct msgbuf __user *p;
  278. struct compat_msgbuf __user *up = uptr;
  279. long type;
  280. if (first < 0)
  281. return -EINVAL;
  282. if (second < 0 || (second >= MAXBUF - sizeof(struct msgbuf)))
  283. return -EINVAL;
  284. p = compat_alloc_user_space(second + sizeof(struct msgbuf));
  285. if (get_user(type, &up->mtype) ||
  286. put_user(type, &p->mtype) ||
  287. copy_in_user(p->mtext, up->mtext, second))
  288. return -EFAULT;
  289. return sys_msgsnd(first, p, second, third);
  290. }
  291. long compat_sys_msgrcv(int first, int second, int msgtyp, int third,
  292. int version, void __user *uptr)
  293. {
  294. struct msgbuf __user *p;
  295. struct compat_msgbuf __user *up;
  296. long type;
  297. int err;
  298. if (first < 0)
  299. return -EINVAL;
  300. if (second < 0 || (second >= MAXBUF - sizeof(struct msgbuf)))
  301. return -EINVAL;
  302. if (!version) {
  303. struct compat_ipc_kludge ipck;
  304. err = -EINVAL;
  305. if (!uptr)
  306. goto out;
  307. err = -EFAULT;
  308. if (copy_from_user (&ipck, uptr, sizeof(ipck)))
  309. goto out;
  310. uptr = compat_ptr(ipck.msgp);
  311. msgtyp = ipck.msgtyp;
  312. }
  313. p = compat_alloc_user_space(second + sizeof(struct msgbuf));
  314. err = sys_msgrcv(first, p, second, msgtyp, third);
  315. if (err < 0)
  316. goto out;
  317. up = uptr;
  318. if (get_user(type, &p->mtype) ||
  319. put_user(type, &up->mtype) ||
  320. copy_in_user(up->mtext, p->mtext, err))
  321. err = -EFAULT;
  322. out:
  323. return err;
  324. }
  325. static inline int get_compat_msqid64(struct msqid64_ds *m64,
  326. struct compat_msqid64_ds __user *up64)
  327. {
  328. int err;
  329. if (!access_ok(VERIFY_READ, up64, sizeof(*up64)))
  330. return -EFAULT;
  331. err = __get_compat_ipc64_perm(&m64->msg_perm, &up64->msg_perm);
  332. err |= __get_user(m64->msg_qbytes, &up64->msg_qbytes);
  333. return err;
  334. }
  335. static inline int get_compat_msqid(struct msqid64_ds *m,
  336. struct compat_msqid_ds __user *up)
  337. {
  338. int err;
  339. if (!access_ok(VERIFY_READ, up, sizeof(*up)))
  340. return -EFAULT;
  341. err = __get_compat_ipc_perm(&m->msg_perm, &up->msg_perm);
  342. err |= __get_user(m->msg_qbytes, &up->msg_qbytes);
  343. return err;
  344. }
  345. static inline int put_compat_msqid64_ds(struct msqid64_ds *m64,
  346. struct compat_msqid64_ds __user *up64)
  347. {
  348. int err;
  349. if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
  350. return -EFAULT;
  351. err = __put_compat_ipc64_perm(&m64->msg_perm, &up64->msg_perm);
  352. err |= __put_user(m64->msg_stime, &up64->msg_stime);
  353. err |= __put_user(m64->msg_rtime, &up64->msg_rtime);
  354. err |= __put_user(m64->msg_ctime, &up64->msg_ctime);
  355. err |= __put_user(m64->msg_cbytes, &up64->msg_cbytes);
  356. err |= __put_user(m64->msg_qnum, &up64->msg_qnum);
  357. err |= __put_user(m64->msg_qbytes, &up64->msg_qbytes);
  358. err |= __put_user(m64->msg_lspid, &up64->msg_lspid);
  359. err |= __put_user(m64->msg_lrpid, &up64->msg_lrpid);
  360. return err;
  361. }
  362. static inline int put_compat_msqid_ds(struct msqid64_ds *m,
  363. struct compat_msqid_ds __user *up)
  364. {
  365. int err;
  366. if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
  367. return -EFAULT;
  368. err = __put_compat_ipc_perm(&m->msg_perm, &up->msg_perm);
  369. err |= __put_user(m->msg_stime, &up->msg_stime);
  370. err |= __put_user(m->msg_rtime, &up->msg_rtime);
  371. err |= __put_user(m->msg_ctime, &up->msg_ctime);
  372. err |= __put_user(m->msg_cbytes, &up->msg_cbytes);
  373. err |= __put_user(m->msg_qnum, &up->msg_qnum);
  374. err |= __put_user(m->msg_qbytes, &up->msg_qbytes);
  375. err |= __put_user(m->msg_lspid, &up->msg_lspid);
  376. err |= __put_user(m->msg_lrpid, &up->msg_lrpid);
  377. return err;
  378. }
  379. long compat_sys_msgctl(int first, int second, void __user *uptr)
  380. {
  381. int err, err2;
  382. struct msqid64_ds m64;
  383. int version = compat_ipc_parse_version(&second);
  384. void __user *p;
  385. switch (second & (~IPC_64)) {
  386. case IPC_INFO:
  387. case IPC_RMID:
  388. case MSG_INFO:
  389. err = sys_msgctl(first, second, uptr);
  390. break;
  391. case IPC_SET:
  392. if (version == IPC_64) {
  393. err = get_compat_msqid64(&m64, uptr);
  394. } else {
  395. err = get_compat_msqid(&m64, uptr);
  396. }
  397. if (err)
  398. break;
  399. p = compat_alloc_user_space(sizeof(m64));
  400. if (copy_to_user(p, &m64, sizeof(m64)))
  401. err = -EFAULT;
  402. else
  403. err = sys_msgctl(first, second, p);
  404. break;
  405. case IPC_STAT:
  406. case MSG_STAT:
  407. p = compat_alloc_user_space(sizeof(m64));
  408. err = sys_msgctl(first, second, p);
  409. if (err < 0)
  410. break;
  411. if (copy_from_user(&m64, p, sizeof(m64)))
  412. err2 = -EFAULT;
  413. else if (version == IPC_64)
  414. err2 = put_compat_msqid64_ds(&m64, uptr);
  415. else
  416. err2 = put_compat_msqid_ds(&m64, uptr);
  417. if (err2)
  418. err = -EFAULT;
  419. break;
  420. default:
  421. err = -EINVAL;
  422. break;
  423. }
  424. return err;
  425. }
  426. long compat_sys_shmat(int first, int second, compat_uptr_t third, int version,
  427. void __user *uptr)
  428. {
  429. int err;
  430. unsigned long raddr;
  431. compat_ulong_t __user *uaddr;
  432. if (version == 1)
  433. return -EINVAL;
  434. err = do_shmat(first, uptr, second, &raddr);
  435. if (err < 0)
  436. return err;
  437. uaddr = compat_ptr(third);
  438. return put_user(raddr, uaddr);
  439. }
  440. static inline int get_compat_shmid64_ds(struct shmid64_ds *s64,
  441. struct compat_shmid64_ds __user *up64)
  442. {
  443. if (!access_ok(VERIFY_READ, up64, sizeof(*up64)))
  444. return -EFAULT;
  445. return __get_compat_ipc64_perm(&s64->shm_perm, &up64->shm_perm);
  446. }
  447. static inline int get_compat_shmid_ds(struct shmid64_ds *s,
  448. struct compat_shmid_ds __user *up)
  449. {
  450. if (!access_ok(VERIFY_READ, up, sizeof(*up)))
  451. return -EFAULT;
  452. return __get_compat_ipc_perm(&s->shm_perm, &up->shm_perm);
  453. }
  454. static inline int put_compat_shmid64_ds(struct shmid64_ds *s64,
  455. struct compat_shmid64_ds __user *up64)
  456. {
  457. int err;
  458. if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
  459. return -EFAULT;
  460. err = __put_compat_ipc64_perm(&s64->shm_perm, &up64->shm_perm);
  461. err |= __put_user(s64->shm_atime, &up64->shm_atime);
  462. err |= __put_user(s64->shm_dtime, &up64->shm_dtime);
  463. err |= __put_user(s64->shm_ctime, &up64->shm_ctime);
  464. err |= __put_user(s64->shm_segsz, &up64->shm_segsz);
  465. err |= __put_user(s64->shm_nattch, &up64->shm_nattch);
  466. err |= __put_user(s64->shm_cpid, &up64->shm_cpid);
  467. err |= __put_user(s64->shm_lpid, &up64->shm_lpid);
  468. return err;
  469. }
  470. static inline int put_compat_shmid_ds(struct shmid64_ds *s,
  471. struct compat_shmid_ds __user *up)
  472. {
  473. int err;
  474. if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
  475. return -EFAULT;
  476. err = __put_compat_ipc_perm(&s->shm_perm, &up->shm_perm);
  477. err |= __put_user(s->shm_atime, &up->shm_atime);
  478. err |= __put_user(s->shm_dtime, &up->shm_dtime);
  479. err |= __put_user(s->shm_ctime, &up->shm_ctime);
  480. err |= __put_user(s->shm_segsz, &up->shm_segsz);
  481. err |= __put_user(s->shm_nattch, &up->shm_nattch);
  482. err |= __put_user(s->shm_cpid, &up->shm_cpid);
  483. err |= __put_user(s->shm_lpid, &up->shm_lpid);
  484. return err;
  485. }
  486. static inline int put_compat_shminfo64(struct shminfo64 *smi,
  487. struct compat_shminfo64 __user *up64)
  488. {
  489. int err;
  490. if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
  491. return -EFAULT;
  492. err = __put_user(smi->shmmax, &up64->shmmax);
  493. err |= __put_user(smi->shmmin, &up64->shmmin);
  494. err |= __put_user(smi->shmmni, &up64->shmmni);
  495. err |= __put_user(smi->shmseg, &up64->shmseg);
  496. err |= __put_user(smi->shmall, &up64->shmall);
  497. return err;
  498. }
  499. static inline int put_compat_shminfo(struct shminfo64 *smi,
  500. struct shminfo __user *up)
  501. {
  502. int err;
  503. if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
  504. return -EFAULT;
  505. err = __put_user(smi->shmmax, &up->shmmax);
  506. err |= __put_user(smi->shmmin, &up->shmmin);
  507. err |= __put_user(smi->shmmni, &up->shmmni);
  508. err |= __put_user(smi->shmseg, &up->shmseg);
  509. err |= __put_user(smi->shmall, &up->shmall);
  510. return err;
  511. }
  512. static inline int put_compat_shm_info(struct shm_info __user *ip,
  513. struct compat_shm_info __user *uip)
  514. {
  515. int err;
  516. struct shm_info si;
  517. if (!access_ok(VERIFY_WRITE, uip, sizeof(*uip)) ||
  518. copy_from_user(&si, ip, sizeof(si)))
  519. return -EFAULT;
  520. err = __put_user(si.used_ids, &uip->used_ids);
  521. err |= __put_user(si.shm_tot, &uip->shm_tot);
  522. err |= __put_user(si.shm_rss, &uip->shm_rss);
  523. err |= __put_user(si.shm_swp, &uip->shm_swp);
  524. err |= __put_user(si.swap_attempts, &uip->swap_attempts);
  525. err |= __put_user(si.swap_successes, &uip->swap_successes);
  526. return err;
  527. }
  528. long compat_sys_shmctl(int first, int second, void __user *uptr)
  529. {
  530. void __user *p;
  531. struct shmid64_ds s64;
  532. struct shminfo64 smi;
  533. int err, err2;
  534. int version = compat_ipc_parse_version(&second);
  535. switch (second & (~IPC_64)) {
  536. case IPC_RMID:
  537. case SHM_LOCK:
  538. case SHM_UNLOCK:
  539. err = sys_shmctl(first, second, uptr);
  540. break;
  541. case IPC_INFO:
  542. p = compat_alloc_user_space(sizeof(smi));
  543. err = sys_shmctl(first, second, p);
  544. if (err < 0)
  545. break;
  546. if (copy_from_user(&smi, p, sizeof(smi)))
  547. err2 = -EFAULT;
  548. else if (version == IPC_64)
  549. err2 = put_compat_shminfo64(&smi, uptr);
  550. else
  551. err2 = put_compat_shminfo(&smi, uptr);
  552. if (err2)
  553. err = -EFAULT;
  554. break;
  555. case IPC_SET:
  556. if (version == IPC_64) {
  557. err = get_compat_shmid64_ds(&s64, uptr);
  558. } else {
  559. err = get_compat_shmid_ds(&s64, uptr);
  560. }
  561. if (err)
  562. break;
  563. p = compat_alloc_user_space(sizeof(s64));
  564. if (copy_to_user(p, &s64, sizeof(s64)))
  565. err = -EFAULT;
  566. else
  567. err = sys_shmctl(first, second, p);
  568. break;
  569. case IPC_STAT:
  570. case SHM_STAT:
  571. p = compat_alloc_user_space(sizeof(s64));
  572. err = sys_shmctl(first, second, p);
  573. if (err < 0)
  574. break;
  575. if (copy_from_user(&s64, p, sizeof(s64)))
  576. err2 = -EFAULT;
  577. else if (version == IPC_64)
  578. err2 = put_compat_shmid64_ds(&s64, uptr);
  579. else
  580. err2 = put_compat_shmid_ds(&s64, uptr);
  581. if (err2)
  582. err = -EFAULT;
  583. break;
  584. case SHM_INFO:
  585. p = compat_alloc_user_space(sizeof(struct shm_info));
  586. err = sys_shmctl(first, second, p);
  587. if (err < 0)
  588. break;
  589. err2 = put_compat_shm_info(p, uptr);
  590. if (err2)
  591. err = -EFAULT;
  592. break;
  593. default:
  594. err = -EINVAL;
  595. break;
  596. }
  597. return err;
  598. }
  599. long compat_sys_semtimedop(int semid, struct sembuf __user *tsems,
  600. unsigned nsops, const struct compat_timespec __user *timeout)
  601. {
  602. struct timespec __user *ts64 = NULL;
  603. if (timeout) {
  604. struct timespec ts;
  605. ts64 = compat_alloc_user_space(sizeof(*ts64));
  606. if (get_compat_timespec(&ts, timeout))
  607. return -EFAULT;
  608. if (copy_to_user(ts64, &ts, sizeof(ts)))
  609. return -EFAULT;
  610. }
  611. return sys_semtimedop(semid, tsems, nsops, ts64);
  612. }