patch-2_6_7-vs1_9_1_12
[linux-2.6.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 static inline int do_semctl(int semid, int semnum, int cmd, union semun arg)
239 {
240         mm_segment_t old_fs;
241         int err;
242
243         old_fs = get_fs();
244         set_fs(KERNEL_DS);
245         err = sys_semctl(semid, semnum, cmd, arg);
246         set_fs(old_fs);
247
248         return err;
249 }
250 long compat_sys_semctl(int first, int second, int third, void __user *uptr)
251 {
252         union semun fourth;
253         u32 pad;
254         int err, err2;
255         struct semid64_ds s64;
256         int version = compat_ipc_parse_version(&third);
257
258         if (!uptr)
259                 return -EINVAL;
260         if (get_user(pad, (u32 __user *) uptr))
261                 return -EFAULT;
262         if ((third & (~IPC_64)) == SETVAL)
263                 fourth.val = (int) pad;
264         else
265                 fourth.__pad = compat_ptr(pad);
266         switch (third & (~IPC_64)) {
267         case IPC_INFO:
268         case IPC_RMID:
269         case SEM_INFO:
270         case GETVAL:
271         case GETPID:
272         case GETNCNT:
273         case GETZCNT:
274         case GETALL:
275         case SETVAL:
276         case SETALL:
277                 err = sys_semctl(first, second, third, fourth);
278                 break;
279
280         case IPC_STAT:
281         case SEM_STAT:
282                 fourth.__pad = &s64;
283                 err = do_semctl(first, second, third, fourth);
284                 if (err < 0)
285                         break;
286
287                 if (version == IPC_64) {
288                         err2 = put_compat_semid64_ds(&s64, compat_ptr(pad));
289                 } else {
290                         err2 = put_compat_semid_ds(&s64, compat_ptr(pad));
291                 }
292                 if (err2)
293                         err = -EFAULT;
294                 break;
295
296         case IPC_SET:
297                 if (version == IPC_64) {
298                         err = get_compat_semid64_ds(&s64, compat_ptr(pad));
299                 } else {
300                         err = get_compat_semid_ds(&s64, compat_ptr(pad));
301                 }
302                 if (err)
303                         break;
304
305                 fourth.__pad = &s64;
306                 err = do_semctl(first, second, third, fourth);
307                 break;
308
309         default:
310                 err = -EINVAL;
311                 break;
312         }
313         return err;
314 }
315
316 long compat_sys_msgsnd(int first, int second, int third, void __user *uptr)
317 {
318         struct msgbuf *p;
319         struct compat_msgbuf __user *up;
320         mm_segment_t old_fs;
321         int err;
322
323         if (first < 0)
324                 return -EINVAL;
325         if (second < 0 || (second >= MAXBUF - sizeof(struct msgbuf)))
326                 return -EINVAL;
327
328         p = kmalloc(second + sizeof(struct msgbuf), GFP_USER);
329         if (!p)
330                 return -ENOMEM;
331         err = -EFAULT;
332         up = uptr;
333         if (get_user(p->mtype, &up->mtype) ||
334             copy_from_user(p->mtext, &up->mtext, second))
335                 goto out;
336         old_fs = get_fs();
337         set_fs(KERNEL_DS);
338         err = sys_msgsnd(first, p, second, third);
339         set_fs(old_fs);
340 out:
341         kfree(p);
342         return err;
343 }
344
345 long compat_sys_msgrcv(int first, int second, int msgtyp, int third,
346                            int version, void __user *uptr)
347 {
348         struct msgbuf *p;
349         struct compat_msgbuf __user *up;
350         mm_segment_t old_fs;
351         int err;
352
353         if (first < 0)
354                 return -EINVAL;
355         if (second < 0 || (second >= MAXBUF - sizeof(struct msgbuf)))
356                 return -EINVAL;
357
358         if (!version) {
359                 struct compat_ipc_kludge __user *uipck = uptr;
360                 struct compat_ipc_kludge ipck;
361
362                 err = -EINVAL;
363                 if (!uptr)
364                         goto out;
365                 err = -EFAULT;
366                 if (copy_from_user (&ipck, uipck, sizeof(ipck)))
367                         goto out;
368                 uptr = compat_ptr(ipck.msgp);
369                 msgtyp = ipck.msgtyp;
370         }
371         err = -ENOMEM;
372         p = kmalloc(second + sizeof(struct msgbuf), GFP_USER);
373         if (!p)
374                 goto out;
375         old_fs = get_fs();
376         set_fs(KERNEL_DS);
377         err = sys_msgrcv(first, p, second, msgtyp, third);
378         set_fs(old_fs);
379         if (err < 0)
380                 goto free_then_out;
381         up = uptr;
382         if (put_user(p->mtype, &up->mtype) ||
383             __copy_to_user(&up->mtext, p->mtext, err))
384                 err = -EFAULT;
385 free_then_out:
386         kfree(p);
387 out:
388         return err;
389 }
390
391 static inline int get_compat_msqid64(struct msqid64_ds *m64,
392                                      struct compat_msqid64_ds __user *up64)
393 {
394         int err;
395
396         if (!access_ok(VERIFY_READ, up64, sizeof(*up64)))
397                 return -EFAULT;
398         err  = __get_compat_ipc64_perm(&m64->msg_perm, &up64->msg_perm);
399         err |= __get_user(m64->msg_qbytes, &up64->msg_qbytes);
400         return err;
401 }
402
403 static inline int get_compat_msqid(struct msqid64_ds *m,
404                                    struct compat_msqid_ds __user *up)
405 {
406         int err;
407
408         if (!access_ok(VERIFY_READ, up, sizeof(*up)))
409                 return -EFAULT;
410         err  = __get_compat_ipc_perm(&m->msg_perm, &up->msg_perm);
411         err |= __get_user(m->msg_qbytes, &up->msg_qbytes);
412         return err;
413 }
414
415 static inline int put_compat_msqid64_ds(struct msqid64_ds *m64,
416                                  struct compat_msqid64_ds __user *up64)
417 {
418         int err;
419
420         if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
421                 return -EFAULT;
422         err  = __put_compat_ipc64_perm(&m64->msg_perm, &up64->msg_perm);
423         err |= __put_user(m64->msg_stime, &up64->msg_stime);
424         err |= __put_user(m64->msg_rtime, &up64->msg_rtime);
425         err |= __put_user(m64->msg_ctime, &up64->msg_ctime);
426         err |= __put_user(m64->msg_cbytes, &up64->msg_cbytes);
427         err |= __put_user(m64->msg_qnum, &up64->msg_qnum);
428         err |= __put_user(m64->msg_qbytes, &up64->msg_qbytes);
429         err |= __put_user(m64->msg_lspid, &up64->msg_lspid);
430         err |= __put_user(m64->msg_lrpid, &up64->msg_lrpid);
431         return err;
432 }
433
434 static inline int put_compat_msqid_ds(struct msqid64_ds *m,
435                                       struct compat_msqid_ds __user *up)
436 {
437         int err;
438
439         if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
440                 return -EFAULT;
441         err  = __put_compat_ipc_perm(&m->msg_perm, &up->msg_perm);
442         err |= __put_user(m->msg_stime, &up->msg_stime);
443         err |= __put_user(m->msg_rtime, &up->msg_rtime);
444         err |= __put_user(m->msg_ctime, &up->msg_ctime);
445         err |= __put_user(m->msg_cbytes, &up->msg_cbytes);
446         err |= __put_user(m->msg_qnum, &up->msg_qnum);
447         err |= __put_user(m->msg_qbytes, &up->msg_qbytes);
448         err |= __put_user(m->msg_lspid, &up->msg_lspid);
449         err |= __put_user(m->msg_lrpid, &up->msg_lrpid);
450         return err;
451 }
452
453 static inline int do_msgctl(int first, int second, void *buf)
454 {
455         mm_segment_t old_fs;
456         int err;
457
458         old_fs = get_fs();
459         set_fs(KERNEL_DS);
460         err = sys_msgctl(first, second, buf);
461         set_fs(old_fs);
462
463         return err;
464 }
465
466 long compat_sys_msgctl(int first, int second, void __user *uptr)
467 {
468         int err, err2;
469         struct msqid64_ds m64;
470         int version = compat_ipc_parse_version(&second);
471
472         switch (second & (~IPC_64)) {
473         case IPC_INFO:
474         case IPC_RMID:
475         case MSG_INFO:
476                 err = sys_msgctl(first, second, uptr);
477                 break;
478
479         case IPC_SET:
480                 if (version == IPC_64) {
481                         err = get_compat_msqid64(&m64, uptr);
482                 } else {
483                         err = get_compat_msqid(&m64, uptr);
484                 }
485                 if (err)
486                         break;
487
488                 err = do_msgctl(first, second, &m64);
489                 break;
490
491         case IPC_STAT:
492         case MSG_STAT:
493                 err = do_msgctl(first, second, &m64);
494                 if (err < 0)
495                         break;
496
497                 if (version == IPC_64) {
498                         err2 = put_compat_msqid64_ds(&m64, uptr);
499                 } else {
500                         err2 = put_compat_msqid_ds(&m64, uptr);
501                 }
502                 if (err2)
503                         err = -EFAULT;
504                 break;
505
506         default:
507                 err = -EINVAL;
508                 break;
509         }
510         return err;
511 }
512
513 long compat_sys_shmat(int first, int second, compat_uptr_t third, int version,
514                         void __user *uptr)
515 {
516         int err;
517         unsigned long raddr;
518         compat_ulong_t __user *uaddr;
519
520         if (version == 1)
521                 return -EINVAL;
522         err = do_shmat(first, uptr, second, &raddr);
523         if (err < 0)
524                 return err;
525         uaddr = compat_ptr(third);
526         return put_user(raddr, uaddr);
527 }
528
529 static inline int get_compat_shmid64_ds(struct shmid64_ds *s64,
530                                         struct compat_shmid64_ds __user *up64)
531 {
532         if (!access_ok(VERIFY_READ, up64, sizeof(*up64)))
533                 return -EFAULT;
534         return __get_compat_ipc64_perm(&s64->shm_perm, &up64->shm_perm);
535 }
536
537 static inline int get_compat_shmid_ds(struct shmid64_ds *s,
538                                       struct compat_shmid_ds __user *up)
539 {
540         if (!access_ok(VERIFY_READ, up, sizeof(*up)))
541                 return -EFAULT;
542         return __get_compat_ipc_perm(&s->shm_perm, &up->shm_perm);
543 }
544
545 static inline int put_compat_shmid64_ds(struct shmid64_ds *s64,
546                                         struct compat_shmid64_ds __user *up64)
547 {
548         int err;
549
550         if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
551                 return -EFAULT;
552         err  = __put_compat_ipc64_perm(&s64->shm_perm, &up64->shm_perm);
553         err |= __put_user(s64->shm_atime, &up64->shm_atime);
554         err |= __put_user(s64->shm_dtime, &up64->shm_dtime);
555         err |= __put_user(s64->shm_ctime, &up64->shm_ctime);
556         err |= __put_user(s64->shm_segsz, &up64->shm_segsz);
557         err |= __put_user(s64->shm_nattch, &up64->shm_nattch);
558         err |= __put_user(s64->shm_cpid, &up64->shm_cpid);
559         err |= __put_user(s64->shm_lpid, &up64->shm_lpid);
560         return err;
561 }
562
563 static inline int put_compat_shmid_ds(struct shmid64_ds *s,
564                                       struct compat_shmid_ds __user *up)
565 {
566         int err;
567
568         if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
569                 return -EFAULT;
570         err  = __put_compat_ipc_perm(&s->shm_perm, &up->shm_perm);
571         err |= __put_user(s->shm_atime, &up->shm_atime);
572         err |= __put_user(s->shm_dtime, &up->shm_dtime);
573         err |= __put_user(s->shm_ctime, &up->shm_ctime);
574         err |= __put_user(s->shm_segsz, &up->shm_segsz);
575         err |= __put_user(s->shm_nattch, &up->shm_nattch);
576         err |= __put_user(s->shm_cpid, &up->shm_cpid);
577         err |= __put_user(s->shm_lpid, &up->shm_lpid);
578         return err;
579 }
580
581 static inline int put_compat_shminfo64(struct shminfo64 *smi,
582                                        struct compat_shminfo64 __user *up64)
583 {
584         int err;
585
586         if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
587                 return -EFAULT;
588         err  = __put_user(smi->shmmax, &up64->shmmax);
589         err |= __put_user(smi->shmmin, &up64->shmmin);
590         err |= __put_user(smi->shmmni, &up64->shmmni);
591         err |= __put_user(smi->shmseg, &up64->shmseg);
592         err |= __put_user(smi->shmall, &up64->shmall);
593         return err;
594 }
595
596 static inline int put_compat_shminfo(struct shminfo64 *smi,
597                                      struct shminfo __user *up)
598 {
599         int err;
600
601         if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
602                 return -EFAULT;
603         err  = __put_user(smi->shmmax, &up->shmmax);
604         err |= __put_user(smi->shmmin, &up->shmmin);
605         err |= __put_user(smi->shmmni, &up->shmmni);
606         err |= __put_user(smi->shmseg, &up->shmseg);
607         err |= __put_user(smi->shmall, &up->shmall);
608 }
609
610 static inline int put_compat_shm_info(struct shm_info *si,
611                                       struct compat_shm_info __user *uip)
612 {
613         int err;
614
615         if (!access_ok(VERIFY_WRITE, uip, sizeof(*uip)))
616                 return -EFAULT;
617         err  = __put_user(si->used_ids, &uip->used_ids);
618         err |= __put_user(si->shm_tot, &uip->shm_tot);
619         err |= __put_user(si->shm_rss, &uip->shm_rss);
620         err |= __put_user(si->shm_swp, &uip->shm_swp);
621         err |= __put_user(si->swap_attempts, &uip->swap_attempts);
622         err |= __put_user(si->swap_successes, &uip->swap_successes);
623         return err;
624 }
625
626 static inline int do_shmctl(int shmid, int cmd, void *buf)
627 {
628         mm_segment_t old_fs;
629         int err;
630
631         old_fs = get_fs();
632         set_fs(KERNEL_DS);
633         err = sys_shmctl(shmid, cmd, buf);
634         set_fs(old_fs);
635
636         return err;
637 }
638
639 long compat_sys_shmctl(int first, int second, void __user *uptr)
640 {
641         struct shmid64_ds s64;
642         struct shminfo64 smi;
643         struct shm_info si;
644         int err, err2;
645         int version = compat_ipc_parse_version(&second);
646
647         switch (second & (~IPC_64)) {
648         case IPC_RMID:
649         case SHM_LOCK:
650         case SHM_UNLOCK:
651                 err = sys_shmctl(first, second, uptr);
652                 break;
653
654         case IPC_INFO:
655                 err = do_shmctl(first, second, &smi);
656                 if (err < 0)
657                         break;
658
659                 if (version == IPC_64) {
660                         err2 = put_compat_shminfo64(&smi, uptr);
661                 } else {
662                         err2 = put_compat_shminfo(&smi, uptr);
663                 }
664                 if (err2)
665                         err = -EFAULT;
666                 break;
667
668
669         case IPC_SET:
670                 if (version == IPC_64) {
671                         err = get_compat_shmid64_ds(&s64, uptr);
672                 } else {
673                         err = get_compat_shmid_ds(&s64, uptr);
674                 }
675                 if (err)
676                         break;
677
678                 err = do_shmctl(first, second, &s64);
679                 break;
680
681         case IPC_STAT:
682         case SHM_STAT:
683                 err = do_shmctl(first, second, &s64);
684                 if (err < 0)
685                         break;
686
687                 if (version == IPC_64) {
688                         err2 = put_compat_shmid64_ds(&s64, uptr);
689                 } else {
690                         err2 = put_compat_shmid_ds(&s64, uptr);
691                 }
692                 if (err2)
693                         err = -EFAULT;
694                 break;
695
696         case SHM_INFO:
697                 err = do_shmctl(first, second, &si);
698                 if (err < 0)
699                         break;
700                 err2 = put_compat_shm_info(&si, uptr);
701                 if (err2)
702                         err = -EFAULT;
703                 break;
704
705         default:
706                 err = -EINVAL;
707                 break;
708         }
709         return err;
710 }
711
712 long compat_sys_semtimedop(int semid, struct sembuf __user *tsems,
713                 unsigned nsops, const struct compat_timespec __user *timeout)
714 {
715         struct timespec ts;
716         struct timespec __user *ts64;
717
718         /* parameter checking precedence should mirror sys_semtimedop() */
719         if (nsops < 1 || semid < 0)
720                 return -EINVAL;
721         if (nsops > sc_semopm)
722                 return -E2BIG;
723         if (!access_ok(VERIFY_READ, tsems, nsops * sizeof(struct sembuf)))
724                 return -EFAULT;
725         if (!timeout)
726                 return sys_semtimedop(semid, tsems, nsops, 0);
727
728         ts64 = compat_alloc_user_space(sizeof(*ts64));
729         if (get_compat_timespec(&ts, timeout))
730                 return -EFAULT;
731         if (copy_to_user(ts64, &ts, sizeof(ts)))
732                 return -EFAULT;
733
734         return sys_semtimedop(semid, tsems, nsops, ts64);
735 }