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