linux/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/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 <linux/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 *uip)
 175{
 176        int err;
 177        __compat_uid_t u;
 178        __compat_gid_t g;
 179
 180        err  = __put_user(p->key, &uip->key);
 181        SET_UID(u, p->uid);
 182        err |= __put_user(u, &uip->uid);
 183        SET_GID(g, p->gid);
 184        err |= __put_user(g, &uip->gid);
 185        SET_UID(u, p->cuid);
 186        err |= __put_user(u, &uip->cuid);
 187        SET_GID(g, p->cgid);
 188        err |= __put_user(g, &uip->cgid);
 189        err |= __put_user(p->mode, &uip->mode);
 190        err |= __put_user(p->seq, &uip->seq);
 191        return err;
 192}
 193
 194static inline int get_compat_semid64_ds(struct semid64_ds *sem64,
 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(&sem64->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 *sem64,
 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(&sem64->sem_perm, &up64->sem_perm);
 218        err |= __put_user(sem64->sem_otime, &up64->sem_otime);
 219        err |= __put_user(sem64->sem_ctime, &up64->sem_ctime);
 220        err |= __put_user(sem64->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 sem64;
 243        struct semid64_ds __user *up64;
 244        int version = compat_ipc_parse_version(&third);
 245
 246        memset(&sem64, 0, sizeof(sem64));
 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(sem64));
 273                fourth = (unsigned long)up64;
 274                err = sys_semctl(first, second, third, fourth);
 275                if (err < 0)
 276                        break;
 277                if (copy_from_user(&sem64, up64, sizeof(sem64)))
 278                        err2 = -EFAULT;
 279                else if (version == IPC_64)
 280                        err2 = put_compat_semid64_ds(&sem64, compat_ptr(pad));
 281                else
 282                        err2 = put_compat_semid_ds(&sem64, 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(&sem64, compat_ptr(pad));
 290                else
 291                        err = get_compat_semid_ds(&sem64, compat_ptr(pad));
 292
 293                up64 = compat_alloc_user_space(sizeof(sem64));
 294                if (copy_to_user(up64, &sem64, sizeof(sem64)))
 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 *sem64,
 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(&sem64->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 *sem64,
 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(&sem64->shm_perm, &up64->shm_perm);
 588        err |= __put_user(sem64->shm_atime, &up64->shm_atime);
 589        err |= __put_user(sem64->shm_dtime, &up64->shm_dtime);
 590        err |= __put_user(sem64->shm_ctime, &up64->shm_ctime);
 591        err |= __put_user(sem64->shm_segsz, &up64->shm_segsz);
 592        err |= __put_user(sem64->shm_nattch, &up64->shm_nattch);
 593        err |= __put_user(sem64->shm_cpid, &up64->shm_cpid);
 594        err |= __put_user(sem64->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 sem64;
 672        struct shminfo64 smi;
 673        int err, err2;
 674        int version = compat_ipc_parse_version(&second);
 675
 676        memset(&sem64, 0, sizeof(sem64));
 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(&sem64, uptr);
 704                else
 705                        err = get_compat_shmid_ds(&sem64, uptr);
 706
 707                if (err)
 708                        break;
 709                p = compat_alloc_user_space(sizeof(sem64));
 710                if (copy_to_user(p, &sem64, sizeof(sem64)))
 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(sem64));
 719                err = sys_shmctl(first, second, p);
 720                if (err < 0)
 721                        break;
 722                if (copy_from_user(&sem64, p, sizeof(sem64)))
 723                        err2 = -EFAULT;
 724                else if (version == IPC_64)
 725                        err2 = put_compat_shmid64_ds(&sem64, uptr);
 726                else
 727                        err2 = put_compat_shmid_ds(&sem64, 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