Pull sn-features into release branch
[pandora-kernel.git] / ipc / compat.c
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         return err;
576 }
577
578 static inline int put_compat_shm_info(struct shm_info __user *ip,
579                                       struct compat_shm_info __user *uip)
580 {
581         int err;
582         struct shm_info si;
583
584         if (!access_ok(VERIFY_WRITE, uip, sizeof(*uip)) ||
585             copy_from_user(&si, ip, sizeof(si)))
586                 return -EFAULT;
587         err  = __put_user(si.used_ids, &uip->used_ids);
588         err |= __put_user(si.shm_tot, &uip->shm_tot);
589         err |= __put_user(si.shm_rss, &uip->shm_rss);
590         err |= __put_user(si.shm_swp, &uip->shm_swp);
591         err |= __put_user(si.swap_attempts, &uip->swap_attempts);
592         err |= __put_user(si.swap_successes, &uip->swap_successes);
593         return err;
594 }
595
596 long compat_sys_shmctl(int first, int second, void __user *uptr)
597 {
598         void __user *p;
599         struct shmid64_ds s64;
600         struct shminfo64 smi;
601         int err, err2;
602         int version = compat_ipc_parse_version(&second);
603
604         switch (second & (~IPC_64)) {
605         case IPC_RMID:
606         case SHM_LOCK:
607         case SHM_UNLOCK:
608                 err = sys_shmctl(first, second, uptr);
609                 break;
610
611         case IPC_INFO:
612                 p = compat_alloc_user_space(sizeof(smi));
613                 err = sys_shmctl(first, second, p);
614                 if (err < 0)
615                         break;
616                 if (copy_from_user(&smi, p, sizeof(smi)))
617                         err2 = -EFAULT;
618                 else if (version == IPC_64)
619                         err2 = put_compat_shminfo64(&smi, uptr);
620                 else
621                         err2 = put_compat_shminfo(&smi, uptr);
622                 if (err2)
623                         err = -EFAULT;
624                 break;
625
626
627         case IPC_SET:
628                 if (version == IPC_64) {
629                         err = get_compat_shmid64_ds(&s64, uptr);
630                 } else {
631                         err = get_compat_shmid_ds(&s64, uptr);
632                 }
633                 if (err)
634                         break;
635                 p = compat_alloc_user_space(sizeof(s64));
636                 if (copy_to_user(p, &s64, sizeof(s64)))
637                         err = -EFAULT;
638                 else
639                         err = sys_shmctl(first, second, p);
640                 break;
641
642         case IPC_STAT:
643         case SHM_STAT:
644                 p = compat_alloc_user_space(sizeof(s64));
645                 err = sys_shmctl(first, second, p);
646                 if (err < 0)
647                         break;
648                 if (copy_from_user(&s64, p, sizeof(s64)))
649                         err2 = -EFAULT;
650                 else if (version == IPC_64)
651                         err2 = put_compat_shmid64_ds(&s64, uptr);
652                 else
653                         err2 = put_compat_shmid_ds(&s64, uptr);
654                 if (err2)
655                         err = -EFAULT;
656                 break;
657
658         case SHM_INFO:
659                 p = compat_alloc_user_space(sizeof(struct shm_info));
660                 err = sys_shmctl(first, second, p);
661                 if (err < 0)
662                         break;
663                 err2 = put_compat_shm_info(p, uptr);
664                 if (err2)
665                         err = -EFAULT;
666                 break;
667
668         default:
669                 err = -EINVAL;
670                 break;
671         }
672         return err;
673 }
674
675 long compat_sys_semtimedop(int semid, struct sembuf __user *tsems,
676                 unsigned nsops, const struct compat_timespec __user *timeout)
677 {
678         struct timespec __user *ts64 = NULL;
679         if (timeout) {
680                 struct timespec ts;
681                 ts64 = compat_alloc_user_space(sizeof(*ts64));
682                 if (get_compat_timespec(&ts, timeout))
683                         return -EFAULT;
684                 if (copy_to_user(ts64, &ts, sizeof(ts)))
685                         return -EFAULT;
686         }
687         return sys_semtimedop(semid, tsems, nsops, ts64);
688 }