Root/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/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/syscalls.h>
30#include <linux/ptrace.h>
31
32#include <linux/mutex.h>
33#include <asm/uaccess.h>
34
35#include "util.h"
36
37struct compat_msgbuf {
38    compat_long_t mtype;
39    char mtext[1];
40};
41
42struct 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
52struct 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
63struct 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
79struct 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
93struct compat_ipc_kludge {
94    compat_uptr_t msgp;
95    compat_long_t msgtyp;
96};
97
98struct 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
110struct 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
116static inline int compat_ipc_parse_version(int *cmd)
117{
118#ifdef CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION
119    int version = *cmd & IPC_64;
120
121    /* this is tricky: architectures that have support for the old
122     * ipc structures in 64 bit binaries need to have IPC_64 set
123     * in cmd, the others need to have it cleared */
124#ifndef ipc_parse_version
125    *cmd |= IPC_64;
126#else
127    *cmd &= ~IPC_64;
128#endif
129    return version;
130#else
131    /* With the asm-generic APIs, we always use the 64-bit versions. */
132    return IPC_64;
133#endif
134}
135
136static 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
147static 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
158static 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
173static 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
194static 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
202static 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
210static 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
224static 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        return -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
238static long do_compat_semctl(int first, int second, int third, u32 pad)
239{
240    unsigned long fourth;
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    memset(&s64, 0, sizeof(s64));
247
248    if ((third & (~IPC_64)) == SETVAL)
249#ifdef __BIG_ENDIAN
250        fourth = (unsigned long)pad << 32;
251#else
252        fourth = pad;
253#endif
254    else
255        fourth = (unsigned long)compat_ptr(pad);
256    switch (third & (~IPC_64)) {
257    case IPC_INFO:
258    case IPC_RMID:
259    case SEM_INFO:
260    case GETVAL:
261    case GETPID:
262    case GETNCNT:
263    case GETZCNT:
264    case GETALL:
265    case SETVAL:
266    case SETALL:
267        err = sys_semctl(first, second, third, fourth);
268        break;
269
270    case IPC_STAT:
271    case SEM_STAT:
272        up64 = compat_alloc_user_space(sizeof(s64));
273        fourth = (unsigned long)up64;
274        err = sys_semctl(first, second, third, fourth);
275        if (err < 0)
276            break;
277        if (copy_from_user(&s64, up64, sizeof(s64)))
278            err2 = -EFAULT;
279        else if (version == IPC_64)
280            err2 = put_compat_semid64_ds(&s64, compat_ptr(pad));
281        else
282            err2 = put_compat_semid_ds(&s64, compat_ptr(pad));
283        if (err2)
284            err = -EFAULT;
285        break;
286
287    case IPC_SET:
288        if (version == IPC_64)
289            err = get_compat_semid64_ds(&s64, compat_ptr(pad));
290        else
291            err = get_compat_semid_ds(&s64, compat_ptr(pad));
292
293        up64 = compat_alloc_user_space(sizeof(s64));
294        if (copy_to_user(up64, &s64, sizeof(s64)))
295            err = -EFAULT;
296        if (err)
297            break;
298
299        fourth = (unsigned long)up64;
300        err = sys_semctl(first, second, third, fourth);
301        break;
302
303    default:
304        err = -EINVAL;
305        break;
306    }
307    return err;
308}
309
310static long compat_do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz)
311{
312    struct compat_msgbuf __user *msgp = dest;
313    size_t msgsz;
314
315    if (put_user(msg->m_type, &msgp->mtype))
316        return -EFAULT;
317
318    msgsz = (bufsz > msg->m_ts) ? msg->m_ts : bufsz;
319    if (store_msg(msgp->mtext, msg, msgsz))
320        return -EFAULT;
321    return msgsz;
322}
323
324#ifndef COMPAT_SHMLBA
325#define COMPAT_SHMLBA SHMLBA
326#endif
327
328#ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC
329COMPAT_SYSCALL_DEFINE6(ipc, u32, call, int, first, int, second,
330    u32, third, compat_uptr_t, ptr, u32, fifth)
331{
332    int version;
333    u32 pad;
334
335    version = call >> 16; /* hack for backward compatibility */
336    call &= 0xffff;
337
338    switch (call) {
339    case SEMOP:
340        /* struct sembuf is the same on 32 and 64bit :)) */
341        return sys_semtimedop(first, compat_ptr(ptr), second, NULL);
342    case SEMTIMEDOP:
343        return compat_sys_semtimedop(first, compat_ptr(ptr), second,
344                        compat_ptr(fifth));
345    case SEMGET:
346        return sys_semget(first, second, third);
347    case SEMCTL:
348        if (!ptr)
349            return -EINVAL;
350        if (get_user(pad, (u32 __user *) compat_ptr(ptr)))
351            return -EFAULT;
352        return do_compat_semctl(first, second, third, pad);
353
354    case MSGSND: {
355        struct compat_msgbuf __user *up = compat_ptr(ptr);
356        compat_long_t type;
357
358        if (first < 0 || second < 0)
359            return -EINVAL;
360
361        if (get_user(type, &up->mtype))
362            return -EFAULT;
363
364        return do_msgsnd(first, type, up->mtext, second, third);
365    }
366    case MSGRCV: {
367        void __user *uptr = compat_ptr(ptr);
368
369        if (first < 0 || second < 0)
370            return -EINVAL;
371
372        if (!version) {
373            struct compat_ipc_kludge ipck;
374            if (!uptr)
375                return -EINVAL;
376            if (copy_from_user(&ipck, uptr, sizeof(ipck)))
377                return -EFAULT;
378            uptr = compat_ptr(ipck.msgp);
379            fifth = ipck.msgtyp;
380        }
381        return do_msgrcv(first, uptr, second, (s32)fifth, third,
382                 compat_do_msg_fill);
383    }
384    case MSGGET:
385        return sys_msgget(first, second);
386    case MSGCTL:
387        return compat_sys_msgctl(first, second, compat_ptr(ptr));
388
389    case SHMAT: {
390        int err;
391        unsigned long raddr;
392
393        if (version == 1)
394            return -EINVAL;
395        err = do_shmat(first, compat_ptr(ptr), second, &raddr,
396                   COMPAT_SHMLBA);
397        if (err < 0)
398            return err;
399        return put_user(raddr, (compat_ulong_t *)compat_ptr(third));
400    }
401    case SHMDT:
402        return sys_shmdt(compat_ptr(ptr));
403    case SHMGET:
404        return sys_shmget(first, (unsigned)second, third);
405    case SHMCTL:
406        return compat_sys_shmctl(first, second, compat_ptr(ptr));
407    }
408
409    return -ENOSYS;
410}
411#endif
412
413COMPAT_SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, int, arg)
414{
415    return do_compat_semctl(semid, semnum, cmd, arg);
416}
417
418COMPAT_SYSCALL_DEFINE4(msgsnd, int, msqid, compat_uptr_t, msgp,
419               compat_ssize_t, msgsz, int, msgflg)
420{
421    struct compat_msgbuf __user *up = compat_ptr(msgp);
422    compat_long_t mtype;
423
424    if (get_user(mtype, &up->mtype))
425        return -EFAULT;
426    return do_msgsnd(msqid, mtype, up->mtext, (ssize_t)msgsz, msgflg);
427}
428
429COMPAT_SYSCALL_DEFINE5(msgrcv, int, msqid, compat_uptr_t, msgp,
430               compat_ssize_t, msgsz, compat_long_t, msgtyp, int, msgflg)
431{
432    return do_msgrcv(msqid, compat_ptr(msgp), (ssize_t)msgsz, (long)msgtyp,
433             msgflg, compat_do_msg_fill);
434}
435
436static inline int get_compat_msqid64(struct msqid64_ds *m64,
437                     struct compat_msqid64_ds __user *up64)
438{
439    int err;
440
441    if (!access_ok(VERIFY_READ, up64, sizeof(*up64)))
442        return -EFAULT;
443    err = __get_compat_ipc64_perm(&m64->msg_perm, &up64->msg_perm);
444    err |= __get_user(m64->msg_qbytes, &up64->msg_qbytes);
445    return err;
446}
447
448static inline int get_compat_msqid(struct msqid64_ds *m,
449                   struct compat_msqid_ds __user *up)
450{
451    int err;
452
453    if (!access_ok(VERIFY_READ, up, sizeof(*up)))
454        return -EFAULT;
455    err = __get_compat_ipc_perm(&m->msg_perm, &up->msg_perm);
456    err |= __get_user(m->msg_qbytes, &up->msg_qbytes);
457    return err;
458}
459
460static inline int put_compat_msqid64_ds(struct msqid64_ds *m64,
461                 struct compat_msqid64_ds __user *up64)
462{
463    int err;
464
465    if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
466        return -EFAULT;
467    err = __put_compat_ipc64_perm(&m64->msg_perm, &up64->msg_perm);
468    err |= __put_user(m64->msg_stime, &up64->msg_stime);
469    err |= __put_user(m64->msg_rtime, &up64->msg_rtime);
470    err |= __put_user(m64->msg_ctime, &up64->msg_ctime);
471    err |= __put_user(m64->msg_cbytes, &up64->msg_cbytes);
472    err |= __put_user(m64->msg_qnum, &up64->msg_qnum);
473    err |= __put_user(m64->msg_qbytes, &up64->msg_qbytes);
474    err |= __put_user(m64->msg_lspid, &up64->msg_lspid);
475    err |= __put_user(m64->msg_lrpid, &up64->msg_lrpid);
476    return err;
477}
478
479static inline int put_compat_msqid_ds(struct msqid64_ds *m,
480                      struct compat_msqid_ds __user *up)
481{
482    int err;
483
484    if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
485        return -EFAULT;
486    err = __put_compat_ipc_perm(&m->msg_perm, &up->msg_perm);
487    err |= __put_user(m->msg_stime, &up->msg_stime);
488    err |= __put_user(m->msg_rtime, &up->msg_rtime);
489    err |= __put_user(m->msg_ctime, &up->msg_ctime);
490    err |= __put_user(m->msg_cbytes, &up->msg_cbytes);
491    err |= __put_user(m->msg_qnum, &up->msg_qnum);
492    err |= __put_user(m->msg_qbytes, &up->msg_qbytes);
493    err |= __put_user(m->msg_lspid, &up->msg_lspid);
494    err |= __put_user(m->msg_lrpid, &up->msg_lrpid);
495    return err;
496}
497
498COMPAT_SYSCALL_DEFINE3(msgctl, int, first, int, second, void __user *, uptr)
499{
500    int err, err2;
501    struct msqid64_ds m64;
502    int version = compat_ipc_parse_version(&second);
503    void __user *p;
504
505    memset(&m64, 0, sizeof(m64));
506
507    switch (second & (~IPC_64)) {
508    case IPC_INFO:
509    case IPC_RMID:
510    case MSG_INFO:
511        err = sys_msgctl(first, second, uptr);
512        break;
513
514    case IPC_SET:
515        if (version == IPC_64)
516            err = get_compat_msqid64(&m64, uptr);
517        else
518            err = get_compat_msqid(&m64, uptr);
519
520        if (err)
521            break;
522        p = compat_alloc_user_space(sizeof(m64));
523        if (copy_to_user(p, &m64, sizeof(m64)))
524            err = -EFAULT;
525        else
526            err = sys_msgctl(first, second, p);
527        break;
528
529    case IPC_STAT:
530    case MSG_STAT:
531        p = compat_alloc_user_space(sizeof(m64));
532        err = sys_msgctl(first, second, p);
533        if (err < 0)
534            break;
535        if (copy_from_user(&m64, p, sizeof(m64)))
536            err2 = -EFAULT;
537        else if (version == IPC_64)
538            err2 = put_compat_msqid64_ds(&m64, uptr);
539        else
540            err2 = put_compat_msqid_ds(&m64, uptr);
541        if (err2)
542            err = -EFAULT;
543        break;
544
545    default:
546        err = -EINVAL;
547        break;
548    }
549    return err;
550}
551
552COMPAT_SYSCALL_DEFINE3(shmat, int, shmid, compat_uptr_t, shmaddr, int, shmflg)
553{
554    unsigned long ret;
555    long err;
556
557    err = do_shmat(shmid, compat_ptr(shmaddr), shmflg, &ret, COMPAT_SHMLBA);
558    if (err)
559        return err;
560    force_successful_syscall_return();
561    return (long)ret;
562}
563
564static inline int get_compat_shmid64_ds(struct shmid64_ds *s64,
565                    struct compat_shmid64_ds __user *up64)
566{
567    if (!access_ok(VERIFY_READ, up64, sizeof(*up64)))
568        return -EFAULT;
569    return __get_compat_ipc64_perm(&s64->shm_perm, &up64->shm_perm);
570}
571
572static inline int get_compat_shmid_ds(struct shmid64_ds *s,
573                      struct compat_shmid_ds __user *up)
574{
575    if (!access_ok(VERIFY_READ, up, sizeof(*up)))
576        return -EFAULT;
577    return __get_compat_ipc_perm(&s->shm_perm, &up->shm_perm);
578}
579
580static inline int put_compat_shmid64_ds(struct shmid64_ds *s64,
581                    struct compat_shmid64_ds __user *up64)
582{
583    int err;
584
585    if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
586        return -EFAULT;
587    err = __put_compat_ipc64_perm(&s64->shm_perm, &up64->shm_perm);
588    err |= __put_user(s64->shm_atime, &up64->shm_atime);
589    err |= __put_user(s64->shm_dtime, &up64->shm_dtime);
590    err |= __put_user(s64->shm_ctime, &up64->shm_ctime);
591    err |= __put_user(s64->shm_segsz, &up64->shm_segsz);
592    err |= __put_user(s64->shm_nattch, &up64->shm_nattch);
593    err |= __put_user(s64->shm_cpid, &up64->shm_cpid);
594    err |= __put_user(s64->shm_lpid, &up64->shm_lpid);
595    return err;
596}
597
598static inline int put_compat_shmid_ds(struct shmid64_ds *s,
599                      struct compat_shmid_ds __user *up)
600{
601    int err;
602
603    if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
604        return -EFAULT;
605    err = __put_compat_ipc_perm(&s->shm_perm, &up->shm_perm);
606    err |= __put_user(s->shm_atime, &up->shm_atime);
607    err |= __put_user(s->shm_dtime, &up->shm_dtime);
608    err |= __put_user(s->shm_ctime, &up->shm_ctime);
609    err |= __put_user(s->shm_segsz, &up->shm_segsz);
610    err |= __put_user(s->shm_nattch, &up->shm_nattch);
611    err |= __put_user(s->shm_cpid, &up->shm_cpid);
612    err |= __put_user(s->shm_lpid, &up->shm_lpid);
613    return err;
614}
615
616static inline int put_compat_shminfo64(struct shminfo64 *smi,
617                       struct compat_shminfo64 __user *up64)
618{
619    int err;
620
621    if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
622        return -EFAULT;
623    if (smi->shmmax > INT_MAX)
624        smi->shmmax = INT_MAX;
625    err = __put_user(smi->shmmax, &up64->shmmax);
626    err |= __put_user(smi->shmmin, &up64->shmmin);
627    err |= __put_user(smi->shmmni, &up64->shmmni);
628    err |= __put_user(smi->shmseg, &up64->shmseg);
629    err |= __put_user(smi->shmall, &up64->shmall);
630    return err;
631}
632
633static inline int put_compat_shminfo(struct shminfo64 *smi,
634                     struct shminfo __user *up)
635{
636    int err;
637
638    if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
639        return -EFAULT;
640    if (smi->shmmax > INT_MAX)
641        smi->shmmax = INT_MAX;
642    err = __put_user(smi->shmmax, &up->shmmax);
643    err |= __put_user(smi->shmmin, &up->shmmin);
644    err |= __put_user(smi->shmmni, &up->shmmni);
645    err |= __put_user(smi->shmseg, &up->shmseg);
646    err |= __put_user(smi->shmall, &up->shmall);
647    return err;
648}
649
650static inline int put_compat_shm_info(struct shm_info __user *ip,
651                      struct compat_shm_info __user *uip)
652{
653    int err;
654    struct shm_info si;
655
656    if (!access_ok(VERIFY_WRITE, uip, sizeof(*uip)) ||
657        copy_from_user(&si, ip, sizeof(si)))
658        return -EFAULT;
659    err = __put_user(si.used_ids, &uip->used_ids);
660    err |= __put_user(si.shm_tot, &uip->shm_tot);
661    err |= __put_user(si.shm_rss, &uip->shm_rss);
662    err |= __put_user(si.shm_swp, &uip->shm_swp);
663    err |= __put_user(si.swap_attempts, &uip->swap_attempts);
664    err |= __put_user(si.swap_successes, &uip->swap_successes);
665    return err;
666}
667
668COMPAT_SYSCALL_DEFINE3(shmctl, int, first, int, second, void __user *, uptr)
669{
670    void __user *p;
671    struct shmid64_ds s64;
672    struct shminfo64 smi;
673    int err, err2;
674    int version = compat_ipc_parse_version(&second);
675
676    memset(&s64, 0, sizeof(s64));
677
678    switch (second & (~IPC_64)) {
679    case IPC_RMID:
680    case SHM_LOCK:
681    case SHM_UNLOCK:
682        err = sys_shmctl(first, second, uptr);
683        break;
684
685    case IPC_INFO:
686        p = compat_alloc_user_space(sizeof(smi));
687        err = sys_shmctl(first, second, p);
688        if (err < 0)
689            break;
690        if (copy_from_user(&smi, p, sizeof(smi)))
691            err2 = -EFAULT;
692        else if (version == IPC_64)
693            err2 = put_compat_shminfo64(&smi, uptr);
694        else
695            err2 = put_compat_shminfo(&smi, uptr);
696        if (err2)
697            err = -EFAULT;
698        break;
699
700
701    case IPC_SET:
702        if (version == IPC_64)
703            err = get_compat_shmid64_ds(&s64, uptr);
704        else
705            err = get_compat_shmid_ds(&s64, uptr);
706
707        if (err)
708            break;
709        p = compat_alloc_user_space(sizeof(s64));
710        if (copy_to_user(p, &s64, sizeof(s64)))
711            err = -EFAULT;
712        else
713            err = sys_shmctl(first, second, p);
714        break;
715
716    case IPC_STAT:
717    case SHM_STAT:
718        p = compat_alloc_user_space(sizeof(s64));
719        err = sys_shmctl(first, second, p);
720        if (err < 0)
721            break;
722        if (copy_from_user(&s64, p, sizeof(s64)))
723            err2 = -EFAULT;
724        else if (version == IPC_64)
725            err2 = put_compat_shmid64_ds(&s64, uptr);
726        else
727            err2 = put_compat_shmid_ds(&s64, uptr);
728        if (err2)
729            err = -EFAULT;
730        break;
731
732    case SHM_INFO:
733        p = compat_alloc_user_space(sizeof(struct shm_info));
734        err = sys_shmctl(first, second, p);
735        if (err < 0)
736            break;
737        err2 = put_compat_shm_info(p, uptr);
738        if (err2)
739            err = -EFAULT;
740        break;
741
742    default:
743        err = -EINVAL;
744        break;
745    }
746    return err;
747}
748
749COMPAT_SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsems,
750               unsigned, nsops,
751               const struct compat_timespec __user *, timeout)
752{
753    struct timespec __user *ts64;
754    if (compat_convert_timespec(&ts64, timeout))
755        return -EFAULT;
756    return sys_semtimedop(semid, tsems, nsops, ts64);
757}
758

Archive Download this file



interactive