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