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