Back to home page

LXR

 
 

    


0001 /*
0002  * 32 bit compatibility code for System V IPC
0003  *
0004  * Copyright (C) 1997,1998  Jakub Jelinek (jj@sunsite.mff.cuni.cz)
0005  * Copyright (C) 1997       David S. Miller (davem@caip.rutgers.edu)
0006  * Copyright (C) 1999       Arun Sharma <arun.sharma@intel.com>
0007  * Copyright (C) 2000       VA Linux Co
0008  * Copyright (C) 2000       Don Dugger <n0ano@valinux.com>
0009  * Copyright (C) 2000           Hewlett-Packard Co.
0010  * Copyright (C) 2000           David Mosberger-Tang <davidm@hpl.hp.com>
0011  * Copyright (C) 2000           Gerhard Tonn (ton@de.ibm.com)
0012  * Copyright (C) 2000-2002      Andi Kleen, SuSE Labs (x86-64 port)
0013  * Copyright (C) 2000       Silicon Graphics, Inc.
0014  * Copyright (C) 2001       IBM
0015  * Copyright (C) 2004       IBM Deutschland Entwicklung GmbH, IBM Corporation
0016  * Copyright (C) 2004       Arnd Bergmann (arnd@arndb.de)
0017  *
0018  * This code is collected from the versions for sparc64, mips64, s390x, ia64,
0019  * ppc64 and x86_64, all of which are based on the original sparc64 version
0020  * by Jakub Jelinek.
0021  *
0022  */
0023 #include <linux/compat.h>
0024 #include <linux/errno.h>
0025 #include <linux/highuid.h>
0026 #include <linux/init.h>
0027 #include <linux/msg.h>
0028 #include <linux/shm.h>
0029 #include <linux/syscalls.h>
0030 #include <linux/ptrace.h>
0031 
0032 #include <linux/mutex.h>
0033 #include <linux/uaccess.h>
0034 
0035 #include "util.h"
0036 
0037 struct compat_msgbuf {
0038     compat_long_t mtype;
0039     char mtext[1];
0040 };
0041 
0042 struct compat_ipc_perm {
0043     key_t key;
0044     __compat_uid_t uid;
0045     __compat_gid_t gid;
0046     __compat_uid_t cuid;
0047     __compat_gid_t cgid;
0048     compat_mode_t mode;
0049     unsigned short seq;
0050 };
0051 
0052 struct compat_semid_ds {
0053     struct compat_ipc_perm sem_perm;
0054     compat_time_t sem_otime;
0055     compat_time_t sem_ctime;
0056     compat_uptr_t sem_base;
0057     compat_uptr_t sem_pending;
0058     compat_uptr_t sem_pending_last;
0059     compat_uptr_t undo;
0060     unsigned short sem_nsems;
0061 };
0062 
0063 struct compat_msqid_ds {
0064     struct compat_ipc_perm msg_perm;
0065     compat_uptr_t msg_first;
0066     compat_uptr_t msg_last;
0067     compat_time_t msg_stime;
0068     compat_time_t msg_rtime;
0069     compat_time_t msg_ctime;
0070     compat_ulong_t msg_lcbytes;
0071     compat_ulong_t msg_lqbytes;
0072     unsigned short msg_cbytes;
0073     unsigned short msg_qnum;
0074     unsigned short msg_qbytes;
0075     compat_ipc_pid_t msg_lspid;
0076     compat_ipc_pid_t msg_lrpid;
0077 };
0078 
0079 struct compat_shmid_ds {
0080     struct compat_ipc_perm shm_perm;
0081     int shm_segsz;
0082     compat_time_t shm_atime;
0083     compat_time_t shm_dtime;
0084     compat_time_t shm_ctime;
0085     compat_ipc_pid_t shm_cpid;
0086     compat_ipc_pid_t shm_lpid;
0087     unsigned short shm_nattch;
0088     unsigned short shm_unused;
0089     compat_uptr_t shm_unused2;
0090     compat_uptr_t shm_unused3;
0091 };
0092 
0093 struct compat_ipc_kludge {
0094     compat_uptr_t msgp;
0095     compat_long_t msgtyp;
0096 };
0097 
0098 struct compat_shminfo64 {
0099     compat_ulong_t shmmax;
0100     compat_ulong_t shmmin;
0101     compat_ulong_t shmmni;
0102     compat_ulong_t shmseg;
0103     compat_ulong_t shmall;
0104     compat_ulong_t __unused1;
0105     compat_ulong_t __unused2;
0106     compat_ulong_t __unused3;
0107     compat_ulong_t __unused4;
0108 };
0109 
0110 struct compat_shm_info {
0111     compat_int_t used_ids;
0112     compat_ulong_t shm_tot, shm_rss, shm_swp;
0113     compat_ulong_t swap_attempts, swap_successes;
0114 };
0115 
0116 static inline int compat_ipc_parse_version(int *cmd)
0117 {
0118 #ifdef  CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION
0119     int version = *cmd & IPC_64;
0120 
0121     /* this is tricky: architectures that have support for the old
0122      * ipc structures in 64 bit binaries need to have IPC_64 set
0123      * in cmd, the others need to have it cleared */
0124 #ifndef ipc_parse_version
0125     *cmd |= IPC_64;
0126 #else
0127     *cmd &= ~IPC_64;
0128 #endif
0129     return version;
0130 #else
0131     /* With the asm-generic APIs, we always use the 64-bit versions. */
0132     return IPC_64;
0133 #endif
0134 }
0135 
0136 static inline int __get_compat_ipc64_perm(struct ipc64_perm *p64,
0137                       struct compat_ipc64_perm __user *up64)
0138 {
0139     int err;
0140 
0141     err  = __get_user(p64->uid, &up64->uid);
0142     err |= __get_user(p64->gid, &up64->gid);
0143     err |= __get_user(p64->mode, &up64->mode);
0144     return err;
0145 }
0146 
0147 static inline int __get_compat_ipc_perm(struct ipc64_perm *p,
0148                     struct compat_ipc_perm __user *up)
0149 {
0150     int err;
0151 
0152     err  = __get_user(p->uid, &up->uid);
0153     err |= __get_user(p->gid, &up->gid);
0154     err |= __get_user(p->mode, &up->mode);
0155     return err;
0156 }
0157 
0158 static inline int __put_compat_ipc64_perm(struct ipc64_perm *p64,
0159                       struct compat_ipc64_perm __user *up64)
0160 {
0161     int err;
0162 
0163     err  = __put_user(p64->key, &up64->key);
0164     err |= __put_user(p64->uid, &up64->uid);
0165     err |= __put_user(p64->gid, &up64->gid);
0166     err |= __put_user(p64->cuid, &up64->cuid);
0167     err |= __put_user(p64->cgid, &up64->cgid);
0168     err |= __put_user(p64->mode, &up64->mode);
0169     err |= __put_user(p64->seq, &up64->seq);
0170     return err;
0171 }
0172 
0173 static inline int __put_compat_ipc_perm(struct ipc64_perm *p,
0174                     struct compat_ipc_perm __user *uip)
0175 {
0176     int err;
0177     __compat_uid_t u;
0178     __compat_gid_t g;
0179 
0180     err  = __put_user(p->key, &uip->key);
0181     SET_UID(u, p->uid);
0182     err |= __put_user(u, &uip->uid);
0183     SET_GID(g, p->gid);
0184     err |= __put_user(g, &uip->gid);
0185     SET_UID(u, p->cuid);
0186     err |= __put_user(u, &uip->cuid);
0187     SET_GID(g, p->cgid);
0188     err |= __put_user(g, &uip->cgid);
0189     err |= __put_user(p->mode, &uip->mode);
0190     err |= __put_user(p->seq, &uip->seq);
0191     return err;
0192 }
0193 
0194 static inline int get_compat_semid64_ds(struct semid64_ds *sem64,
0195                     struct compat_semid64_ds __user *up64)
0196 {
0197     if (!access_ok(VERIFY_READ, up64, sizeof(*up64)))
0198         return -EFAULT;
0199     return __get_compat_ipc64_perm(&sem64->sem_perm, &up64->sem_perm);
0200 }
0201 
0202 static inline int get_compat_semid_ds(struct semid64_ds *s,
0203                       struct compat_semid_ds __user *up)
0204 {
0205     if (!access_ok(VERIFY_READ, up, sizeof(*up)))
0206         return -EFAULT;
0207     return __get_compat_ipc_perm(&s->sem_perm, &up->sem_perm);
0208 }
0209 
0210 static inline int put_compat_semid64_ds(struct semid64_ds *sem64,
0211                     struct compat_semid64_ds __user *up64)
0212 {
0213     int err;
0214 
0215     if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
0216         return -EFAULT;
0217     err  = __put_compat_ipc64_perm(&sem64->sem_perm, &up64->sem_perm);
0218     err |= __put_user(sem64->sem_otime, &up64->sem_otime);
0219     err |= __put_user(sem64->sem_ctime, &up64->sem_ctime);
0220     err |= __put_user(sem64->sem_nsems, &up64->sem_nsems);
0221     return err;
0222 }
0223 
0224 static inline int put_compat_semid_ds(struct semid64_ds *s,
0225                       struct compat_semid_ds __user *up)
0226 {
0227     int err;
0228 
0229     if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
0230         return -EFAULT;
0231     err  = __put_compat_ipc_perm(&s->sem_perm, &up->sem_perm);
0232     err |= __put_user(s->sem_otime, &up->sem_otime);
0233     err |= __put_user(s->sem_ctime, &up->sem_ctime);
0234     err |= __put_user(s->sem_nsems, &up->sem_nsems);
0235     return err;
0236 }
0237 
0238 static long do_compat_semctl(int first, int second, int third, u32 pad)
0239 {
0240     unsigned long fourth;
0241     int err, err2;
0242     struct semid64_ds sem64;
0243     struct semid64_ds __user *up64;
0244     int version = compat_ipc_parse_version(&third);
0245 
0246     memset(&sem64, 0, sizeof(sem64));
0247 
0248     if ((third & (~IPC_64)) == SETVAL)
0249 #ifdef __BIG_ENDIAN
0250         fourth = (unsigned long)pad << 32;
0251 #else
0252         fourth = pad;
0253 #endif
0254     else
0255         fourth = (unsigned long)compat_ptr(pad);
0256     switch (third & (~IPC_64)) {
0257     case IPC_INFO:
0258     case IPC_RMID:
0259     case SEM_INFO:
0260     case GETVAL:
0261     case GETPID:
0262     case GETNCNT:
0263     case GETZCNT:
0264     case GETALL:
0265     case SETVAL:
0266     case SETALL:
0267         err = sys_semctl(first, second, third, fourth);
0268         break;
0269 
0270     case IPC_STAT:
0271     case SEM_STAT:
0272         up64 = compat_alloc_user_space(sizeof(sem64));
0273         fourth = (unsigned long)up64;
0274         err = sys_semctl(first, second, third, fourth);
0275         if (err < 0)
0276             break;
0277         if (copy_from_user(&sem64, up64, sizeof(sem64)))
0278             err2 = -EFAULT;
0279         else if (version == IPC_64)
0280             err2 = put_compat_semid64_ds(&sem64, compat_ptr(pad));
0281         else
0282             err2 = put_compat_semid_ds(&sem64, compat_ptr(pad));
0283         if (err2)
0284             err = -EFAULT;
0285         break;
0286 
0287     case IPC_SET:
0288         if (version == IPC_64)
0289             err = get_compat_semid64_ds(&sem64, compat_ptr(pad));
0290         else
0291             err = get_compat_semid_ds(&sem64, compat_ptr(pad));
0292 
0293         up64 = compat_alloc_user_space(sizeof(sem64));
0294         if (copy_to_user(up64, &sem64, sizeof(sem64)))
0295             err = -EFAULT;
0296         if (err)
0297             break;
0298 
0299         fourth = (unsigned long)up64;
0300         err = sys_semctl(first, second, third, fourth);
0301         break;
0302 
0303     default:
0304         err = -EINVAL;
0305         break;
0306     }
0307     return err;
0308 }
0309 
0310 static long compat_do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz)
0311 {
0312     struct compat_msgbuf __user *msgp = dest;
0313     size_t msgsz;
0314 
0315     if (put_user(msg->m_type, &msgp->mtype))
0316         return -EFAULT;
0317 
0318     msgsz = (bufsz > msg->m_ts) ? msg->m_ts : bufsz;
0319     if (store_msg(msgp->mtext, msg, msgsz))
0320         return -EFAULT;
0321     return msgsz;
0322 }
0323 
0324 #ifndef COMPAT_SHMLBA
0325 #define COMPAT_SHMLBA   SHMLBA
0326 #endif
0327 
0328 #ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC
0329 COMPAT_SYSCALL_DEFINE6(ipc, u32, call, int, first, int, second,
0330     u32, third, compat_uptr_t, ptr, u32, fifth)
0331 {
0332     int version;
0333     u32 pad;
0334 
0335     version = call >> 16; /* hack for backward compatibility */
0336     call &= 0xffff;
0337 
0338     switch (call) {
0339     case SEMOP:
0340         /* struct sembuf is the same on 32 and 64bit :)) */
0341         return sys_semtimedop(first, compat_ptr(ptr), second, NULL);
0342     case SEMTIMEDOP:
0343         return compat_sys_semtimedop(first, compat_ptr(ptr), second,
0344                         compat_ptr(fifth));
0345     case SEMGET:
0346         return sys_semget(first, second, third);
0347     case SEMCTL:
0348         if (!ptr)
0349             return -EINVAL;
0350         if (get_user(pad, (u32 __user *) compat_ptr(ptr)))
0351             return -EFAULT;
0352         return do_compat_semctl(first, second, third, pad);
0353 
0354     case MSGSND: {
0355         struct compat_msgbuf __user *up = compat_ptr(ptr);
0356         compat_long_t type;
0357 
0358         if (first < 0 || second < 0)
0359             return -EINVAL;
0360 
0361         if (get_user(type, &up->mtype))
0362             return -EFAULT;
0363 
0364         return do_msgsnd(first, type, up->mtext, second, third);
0365     }
0366     case MSGRCV: {
0367         void __user *uptr = compat_ptr(ptr);
0368 
0369         if (first < 0 || second < 0)
0370             return -EINVAL;
0371 
0372         if (!version) {
0373             struct compat_ipc_kludge ipck;
0374             if (!uptr)
0375                 return -EINVAL;
0376             if (copy_from_user(&ipck, uptr, sizeof(ipck)))
0377                 return -EFAULT;
0378             uptr = compat_ptr(ipck.msgp);
0379             fifth = ipck.msgtyp;
0380         }
0381         return do_msgrcv(first, uptr, second, (s32)fifth, third,
0382                  compat_do_msg_fill);
0383     }
0384     case MSGGET:
0385         return sys_msgget(first, second);
0386     case MSGCTL:
0387         return compat_sys_msgctl(first, second, compat_ptr(ptr));
0388 
0389     case SHMAT: {
0390         int err;
0391         unsigned long raddr;
0392 
0393         if (version == 1)
0394             return -EINVAL;
0395         err = do_shmat(first, compat_ptr(ptr), second, &raddr,
0396                    COMPAT_SHMLBA);
0397         if (err < 0)
0398             return err;
0399         return put_user(raddr, (compat_ulong_t *)compat_ptr(third));
0400     }
0401     case SHMDT:
0402         return sys_shmdt(compat_ptr(ptr));
0403     case SHMGET:
0404         return sys_shmget(first, (unsigned)second, third);
0405     case SHMCTL:
0406         return compat_sys_shmctl(first, second, compat_ptr(ptr));
0407     }
0408 
0409     return -ENOSYS;
0410 }
0411 #endif
0412 
0413 COMPAT_SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, int, arg)
0414 {
0415     return do_compat_semctl(semid, semnum, cmd, arg);
0416 }
0417 
0418 COMPAT_SYSCALL_DEFINE4(msgsnd, int, msqid, compat_uptr_t, msgp,
0419                compat_ssize_t, msgsz, int, msgflg)
0420 {
0421     struct compat_msgbuf __user *up = compat_ptr(msgp);
0422     compat_long_t mtype;
0423 
0424     if (get_user(mtype, &up->mtype))
0425         return -EFAULT;
0426     return do_msgsnd(msqid, mtype, up->mtext, (ssize_t)msgsz, msgflg);
0427 }
0428 
0429 COMPAT_SYSCALL_DEFINE5(msgrcv, int, msqid, compat_uptr_t, msgp,
0430                compat_ssize_t, msgsz, compat_long_t, msgtyp, int, msgflg)
0431 {
0432     return do_msgrcv(msqid, compat_ptr(msgp), (ssize_t)msgsz, (long)msgtyp,
0433              msgflg, compat_do_msg_fill);
0434 }
0435 
0436 static inline int get_compat_msqid64(struct msqid64_ds *m64,
0437                      struct compat_msqid64_ds __user *up64)
0438 {
0439     int err;
0440 
0441     if (!access_ok(VERIFY_READ, up64, sizeof(*up64)))
0442         return -EFAULT;
0443     err  = __get_compat_ipc64_perm(&m64->msg_perm, &up64->msg_perm);
0444     err |= __get_user(m64->msg_qbytes, &up64->msg_qbytes);
0445     return err;
0446 }
0447 
0448 static inline int get_compat_msqid(struct msqid64_ds *m,
0449                    struct compat_msqid_ds __user *up)
0450 {
0451     int err;
0452 
0453     if (!access_ok(VERIFY_READ, up, sizeof(*up)))
0454         return -EFAULT;
0455     err  = __get_compat_ipc_perm(&m->msg_perm, &up->msg_perm);
0456     err |= __get_user(m->msg_qbytes, &up->msg_qbytes);
0457     return err;
0458 }
0459 
0460 static inline int put_compat_msqid64_ds(struct msqid64_ds *m64,
0461                  struct compat_msqid64_ds __user *up64)
0462 {
0463     int err;
0464 
0465     if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
0466         return -EFAULT;
0467     err  = __put_compat_ipc64_perm(&m64->msg_perm, &up64->msg_perm);
0468     err |= __put_user(m64->msg_stime, &up64->msg_stime);
0469     err |= __put_user(m64->msg_rtime, &up64->msg_rtime);
0470     err |= __put_user(m64->msg_ctime, &up64->msg_ctime);
0471     err |= __put_user(m64->msg_cbytes, &up64->msg_cbytes);
0472     err |= __put_user(m64->msg_qnum, &up64->msg_qnum);
0473     err |= __put_user(m64->msg_qbytes, &up64->msg_qbytes);
0474     err |= __put_user(m64->msg_lspid, &up64->msg_lspid);
0475     err |= __put_user(m64->msg_lrpid, &up64->msg_lrpid);
0476     return err;
0477 }
0478 
0479 static inline int put_compat_msqid_ds(struct msqid64_ds *m,
0480                       struct compat_msqid_ds __user *up)
0481 {
0482     int err;
0483 
0484     if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
0485         return -EFAULT;
0486     err  = __put_compat_ipc_perm(&m->msg_perm, &up->msg_perm);
0487     err |= __put_user(m->msg_stime, &up->msg_stime);
0488     err |= __put_user(m->msg_rtime, &up->msg_rtime);
0489     err |= __put_user(m->msg_ctime, &up->msg_ctime);
0490     err |= __put_user(m->msg_cbytes, &up->msg_cbytes);
0491     err |= __put_user(m->msg_qnum, &up->msg_qnum);
0492     err |= __put_user(m->msg_qbytes, &up->msg_qbytes);
0493     err |= __put_user(m->msg_lspid, &up->msg_lspid);
0494     err |= __put_user(m->msg_lrpid, &up->msg_lrpid);
0495     return err;
0496 }
0497 
0498 COMPAT_SYSCALL_DEFINE3(msgctl, int, first, int, second, void __user *, uptr)
0499 {
0500     int err, err2;
0501     struct msqid64_ds m64;
0502     int version = compat_ipc_parse_version(&second);
0503     void __user *p;
0504 
0505     memset(&m64, 0, sizeof(m64));
0506 
0507     switch (second & (~IPC_64)) {
0508     case IPC_INFO:
0509     case IPC_RMID:
0510     case MSG_INFO:
0511         err = sys_msgctl(first, second, uptr);
0512         break;
0513 
0514     case IPC_SET:
0515         if (version == IPC_64)
0516             err = get_compat_msqid64(&m64, uptr);
0517         else
0518             err = get_compat_msqid(&m64, uptr);
0519 
0520         if (err)
0521             break;
0522         p = compat_alloc_user_space(sizeof(m64));
0523         if (copy_to_user(p, &m64, sizeof(m64)))
0524             err = -EFAULT;
0525         else
0526             err = sys_msgctl(first, second, p);
0527         break;
0528 
0529     case IPC_STAT:
0530     case MSG_STAT:
0531         p = compat_alloc_user_space(sizeof(m64));
0532         err = sys_msgctl(first, second, p);
0533         if (err < 0)
0534             break;
0535         if (copy_from_user(&m64, p, sizeof(m64)))
0536             err2 = -EFAULT;
0537         else if (version == IPC_64)
0538             err2 = put_compat_msqid64_ds(&m64, uptr);
0539         else
0540             err2 = put_compat_msqid_ds(&m64, uptr);
0541         if (err2)
0542             err = -EFAULT;
0543         break;
0544 
0545     default:
0546         err = -EINVAL;
0547         break;
0548     }
0549     return err;
0550 }
0551 
0552 COMPAT_SYSCALL_DEFINE3(shmat, int, shmid, compat_uptr_t, shmaddr, int, shmflg)
0553 {
0554     unsigned long ret;
0555     long err;
0556 
0557     err = do_shmat(shmid, compat_ptr(shmaddr), shmflg, &ret, COMPAT_SHMLBA);
0558     if (err)
0559         return err;
0560     force_successful_syscall_return();
0561     return (long)ret;
0562 }
0563 
0564 static inline int get_compat_shmid64_ds(struct shmid64_ds *sem64,
0565                     struct compat_shmid64_ds __user *up64)
0566 {
0567     if (!access_ok(VERIFY_READ, up64, sizeof(*up64)))
0568         return -EFAULT;
0569     return __get_compat_ipc64_perm(&sem64->shm_perm, &up64->shm_perm);
0570 }
0571 
0572 static inline int get_compat_shmid_ds(struct shmid64_ds *s,
0573                       struct compat_shmid_ds __user *up)
0574 {
0575     if (!access_ok(VERIFY_READ, up, sizeof(*up)))
0576         return -EFAULT;
0577     return __get_compat_ipc_perm(&s->shm_perm, &up->shm_perm);
0578 }
0579 
0580 static inline int put_compat_shmid64_ds(struct shmid64_ds *sem64,
0581                     struct compat_shmid64_ds __user *up64)
0582 {
0583     int err;
0584 
0585     if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
0586         return -EFAULT;
0587     err  = __put_compat_ipc64_perm(&sem64->shm_perm, &up64->shm_perm);
0588     err |= __put_user(sem64->shm_atime, &up64->shm_atime);
0589     err |= __put_user(sem64->shm_dtime, &up64->shm_dtime);
0590     err |= __put_user(sem64->shm_ctime, &up64->shm_ctime);
0591     err |= __put_user(sem64->shm_segsz, &up64->shm_segsz);
0592     err |= __put_user(sem64->shm_nattch, &up64->shm_nattch);
0593     err |= __put_user(sem64->shm_cpid, &up64->shm_cpid);
0594     err |= __put_user(sem64->shm_lpid, &up64->shm_lpid);
0595     return err;
0596 }
0597 
0598 static inline int put_compat_shmid_ds(struct shmid64_ds *s,
0599                       struct compat_shmid_ds __user *up)
0600 {
0601     int err;
0602 
0603     if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
0604         return -EFAULT;
0605     err  = __put_compat_ipc_perm(&s->shm_perm, &up->shm_perm);
0606     err |= __put_user(s->shm_atime, &up->shm_atime);
0607     err |= __put_user(s->shm_dtime, &up->shm_dtime);
0608     err |= __put_user(s->shm_ctime, &up->shm_ctime);
0609     err |= __put_user(s->shm_segsz, &up->shm_segsz);
0610     err |= __put_user(s->shm_nattch, &up->shm_nattch);
0611     err |= __put_user(s->shm_cpid, &up->shm_cpid);
0612     err |= __put_user(s->shm_lpid, &up->shm_lpid);
0613     return err;
0614 }
0615 
0616 static inline int put_compat_shminfo64(struct shminfo64 *smi,
0617                        struct compat_shminfo64 __user *up64)
0618 {
0619     int err;
0620 
0621     if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
0622         return -EFAULT;
0623     if (smi->shmmax > INT_MAX)
0624         smi->shmmax = INT_MAX;
0625     err  = __put_user(smi->shmmax, &up64->shmmax);
0626     err |= __put_user(smi->shmmin, &up64->shmmin);
0627     err |= __put_user(smi->shmmni, &up64->shmmni);
0628     err |= __put_user(smi->shmseg, &up64->shmseg);
0629     err |= __put_user(smi->shmall, &up64->shmall);
0630     return err;
0631 }
0632 
0633 static inline int put_compat_shminfo(struct shminfo64 *smi,
0634                      struct shminfo __user *up)
0635 {
0636     int err;
0637 
0638     if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
0639         return -EFAULT;
0640     if (smi->shmmax > INT_MAX)
0641         smi->shmmax = INT_MAX;
0642     err  = __put_user(smi->shmmax, &up->shmmax);
0643     err |= __put_user(smi->shmmin, &up->shmmin);
0644     err |= __put_user(smi->shmmni, &up->shmmni);
0645     err |= __put_user(smi->shmseg, &up->shmseg);
0646     err |= __put_user(smi->shmall, &up->shmall);
0647     return err;
0648 }
0649 
0650 static inline int put_compat_shm_info(struct shm_info __user *ip,
0651                       struct compat_shm_info __user *uip)
0652 {
0653     int err;
0654     struct shm_info si;
0655 
0656     if (!access_ok(VERIFY_WRITE, uip, sizeof(*uip)) ||
0657         copy_from_user(&si, ip, sizeof(si)))
0658         return -EFAULT;
0659     err  = __put_user(si.used_ids, &uip->used_ids);
0660     err |= __put_user(si.shm_tot, &uip->shm_tot);
0661     err |= __put_user(si.shm_rss, &uip->shm_rss);
0662     err |= __put_user(si.shm_swp, &uip->shm_swp);
0663     err |= __put_user(si.swap_attempts, &uip->swap_attempts);
0664     err |= __put_user(si.swap_successes, &uip->swap_successes);
0665     return err;
0666 }
0667 
0668 COMPAT_SYSCALL_DEFINE3(shmctl, int, first, int, second, void __user *, uptr)
0669 {
0670     void __user *p;
0671     struct shmid64_ds sem64;
0672     struct shminfo64 smi;
0673     int err, err2;
0674     int version = compat_ipc_parse_version(&second);
0675 
0676     memset(&sem64, 0, sizeof(sem64));
0677 
0678     switch (second & (~IPC_64)) {
0679     case IPC_RMID:
0680     case SHM_LOCK:
0681     case SHM_UNLOCK:
0682         err = sys_shmctl(first, second, uptr);
0683         break;
0684 
0685     case IPC_INFO:
0686         p = compat_alloc_user_space(sizeof(smi));
0687         err = sys_shmctl(first, second, p);
0688         if (err < 0)
0689             break;
0690         if (copy_from_user(&smi, p, sizeof(smi)))
0691             err2 = -EFAULT;
0692         else if (version == IPC_64)
0693             err2 = put_compat_shminfo64(&smi, uptr);
0694         else
0695             err2 = put_compat_shminfo(&smi, uptr);
0696         if (err2)
0697             err = -EFAULT;
0698         break;
0699 
0700 
0701     case IPC_SET:
0702         if (version == IPC_64)
0703             err = get_compat_shmid64_ds(&sem64, uptr);
0704         else
0705             err = get_compat_shmid_ds(&sem64, uptr);
0706 
0707         if (err)
0708             break;
0709         p = compat_alloc_user_space(sizeof(sem64));
0710         if (copy_to_user(p, &sem64, sizeof(sem64)))
0711             err = -EFAULT;
0712         else
0713             err = sys_shmctl(first, second, p);
0714         break;
0715 
0716     case IPC_STAT:
0717     case SHM_STAT:
0718         p = compat_alloc_user_space(sizeof(sem64));
0719         err = sys_shmctl(first, second, p);
0720         if (err < 0)
0721             break;
0722         if (copy_from_user(&sem64, p, sizeof(sem64)))
0723             err2 = -EFAULT;
0724         else if (version == IPC_64)
0725             err2 = put_compat_shmid64_ds(&sem64, uptr);
0726         else
0727             err2 = put_compat_shmid_ds(&sem64, uptr);
0728         if (err2)
0729             err = -EFAULT;
0730         break;
0731 
0732     case SHM_INFO:
0733         p = compat_alloc_user_space(sizeof(struct shm_info));
0734         err = sys_shmctl(first, second, p);
0735         if (err < 0)
0736             break;
0737         err2 = put_compat_shm_info(p, uptr);
0738         if (err2)
0739             err = -EFAULT;
0740         break;
0741 
0742     default:
0743         err = -EINVAL;
0744         break;
0745     }
0746     return err;
0747 }
0748 
0749 COMPAT_SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsems,
0750                unsigned, nsops,
0751                const struct compat_timespec __user *, timeout)
0752 {
0753     struct timespec __user *ts64;
0754     if (compat_convert_timespec(&ts64, timeout))
0755         return -EFAULT;
0756     return sys_semtimedop(semid, tsems, nsops, ts64);
0757 }