xref: /linux/ipc/compat.c (revision 56e41d3c5aa84d679eebdb3cb8a70b03c5fbd6c3)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * 32 bit compatibility code for System V IPC
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Copyright (C) 1997,1998	Jakub Jelinek (jj@sunsite.mff.cuni.cz)
51da177e4SLinus Torvalds  * Copyright (C) 1997		David S. Miller (davem@caip.rutgers.edu)
61da177e4SLinus Torvalds  * Copyright (C) 1999		Arun Sharma <arun.sharma@intel.com>
71da177e4SLinus Torvalds  * Copyright (C) 2000		VA Linux Co
81da177e4SLinus Torvalds  * Copyright (C) 2000		Don Dugger <n0ano@valinux.com>
91da177e4SLinus Torvalds  * Copyright (C) 2000           Hewlett-Packard Co.
101da177e4SLinus Torvalds  * Copyright (C) 2000           David Mosberger-Tang <davidm@hpl.hp.com>
111da177e4SLinus Torvalds  * Copyright (C) 2000           Gerhard Tonn (ton@de.ibm.com)
121da177e4SLinus Torvalds  * Copyright (C) 2000-2002      Andi Kleen, SuSE Labs (x86-64 port)
131da177e4SLinus Torvalds  * Copyright (C) 2000		Silicon Graphics, Inc.
141da177e4SLinus Torvalds  * Copyright (C) 2001		IBM
151da177e4SLinus Torvalds  * Copyright (C) 2004		IBM Deutschland Entwicklung GmbH, IBM Corporation
161da177e4SLinus Torvalds  * Copyright (C) 2004		Arnd Bergmann (arnd@arndb.de)
171da177e4SLinus Torvalds  *
181da177e4SLinus Torvalds  * This code is collected from the versions for sparc64, mips64, s390x, ia64,
191da177e4SLinus Torvalds  * ppc64 and x86_64, all of which are based on the original sparc64 version
201da177e4SLinus Torvalds  * by Jakub Jelinek.
211da177e4SLinus Torvalds  *
221da177e4SLinus Torvalds  */
231da177e4SLinus Torvalds #include <linux/compat.h>
241da177e4SLinus Torvalds #include <linux/errno.h>
251da177e4SLinus Torvalds #include <linux/highuid.h>
261da177e4SLinus Torvalds #include <linux/init.h>
271da177e4SLinus Torvalds #include <linux/msg.h>
281da177e4SLinus Torvalds #include <linux/shm.h>
291da177e4SLinus Torvalds #include <linux/syscalls.h>
3048b25c43SChris Metcalf #include <linux/ptrace.h>
311da177e4SLinus Torvalds 
325f921ae9SIngo Molnar #include <linux/mutex.h>
331da177e4SLinus Torvalds #include <asm/uaccess.h>
341da177e4SLinus Torvalds 
351da177e4SLinus Torvalds #include "util.h"
361da177e4SLinus Torvalds 
371da177e4SLinus Torvalds struct compat_msgbuf {
381da177e4SLinus Torvalds 	compat_long_t mtype;
391da177e4SLinus Torvalds 	char mtext[1];
401da177e4SLinus Torvalds };
411da177e4SLinus Torvalds 
421da177e4SLinus Torvalds struct compat_ipc_perm {
431da177e4SLinus Torvalds 	key_t key;
44202e5979SStephen Rothwell 	__compat_uid_t uid;
45202e5979SStephen Rothwell 	__compat_gid_t gid;
46202e5979SStephen Rothwell 	__compat_uid_t cuid;
47202e5979SStephen Rothwell 	__compat_gid_t cgid;
481da177e4SLinus Torvalds 	compat_mode_t mode;
491da177e4SLinus Torvalds 	unsigned short seq;
501da177e4SLinus Torvalds };
511da177e4SLinus Torvalds 
521da177e4SLinus Torvalds struct compat_semid_ds {
531da177e4SLinus Torvalds 	struct compat_ipc_perm sem_perm;
541da177e4SLinus Torvalds 	compat_time_t sem_otime;
551da177e4SLinus Torvalds 	compat_time_t sem_ctime;
561da177e4SLinus Torvalds 	compat_uptr_t sem_base;
571da177e4SLinus Torvalds 	compat_uptr_t sem_pending;
581da177e4SLinus Torvalds 	compat_uptr_t sem_pending_last;
591da177e4SLinus Torvalds 	compat_uptr_t undo;
601da177e4SLinus Torvalds 	unsigned short sem_nsems;
611da177e4SLinus Torvalds };
621da177e4SLinus Torvalds 
631da177e4SLinus Torvalds struct compat_msqid_ds {
641da177e4SLinus Torvalds 	struct compat_ipc_perm msg_perm;
651da177e4SLinus Torvalds 	compat_uptr_t msg_first;
661da177e4SLinus Torvalds 	compat_uptr_t msg_last;
671da177e4SLinus Torvalds 	compat_time_t msg_stime;
681da177e4SLinus Torvalds 	compat_time_t msg_rtime;
691da177e4SLinus Torvalds 	compat_time_t msg_ctime;
701da177e4SLinus Torvalds 	compat_ulong_t msg_lcbytes;
711da177e4SLinus Torvalds 	compat_ulong_t msg_lqbytes;
721da177e4SLinus Torvalds 	unsigned short msg_cbytes;
731da177e4SLinus Torvalds 	unsigned short msg_qnum;
741da177e4SLinus Torvalds 	unsigned short msg_qbytes;
751da177e4SLinus Torvalds 	compat_ipc_pid_t msg_lspid;
761da177e4SLinus Torvalds 	compat_ipc_pid_t msg_lrpid;
771da177e4SLinus Torvalds };
781da177e4SLinus Torvalds 
791da177e4SLinus Torvalds struct compat_shmid_ds {
801da177e4SLinus Torvalds 	struct compat_ipc_perm shm_perm;
811da177e4SLinus Torvalds 	int shm_segsz;
821da177e4SLinus Torvalds 	compat_time_t shm_atime;
831da177e4SLinus Torvalds 	compat_time_t shm_dtime;
841da177e4SLinus Torvalds 	compat_time_t shm_ctime;
851da177e4SLinus Torvalds 	compat_ipc_pid_t shm_cpid;
861da177e4SLinus Torvalds 	compat_ipc_pid_t shm_lpid;
871da177e4SLinus Torvalds 	unsigned short shm_nattch;
881da177e4SLinus Torvalds 	unsigned short shm_unused;
891da177e4SLinus Torvalds 	compat_uptr_t shm_unused2;
901da177e4SLinus Torvalds 	compat_uptr_t shm_unused3;
911da177e4SLinus Torvalds };
921da177e4SLinus Torvalds 
931da177e4SLinus Torvalds struct compat_ipc_kludge {
941da177e4SLinus Torvalds 	compat_uptr_t msgp;
951da177e4SLinus Torvalds 	compat_long_t msgtyp;
961da177e4SLinus Torvalds };
971da177e4SLinus Torvalds 
981da177e4SLinus Torvalds struct compat_shminfo64 {
991da177e4SLinus Torvalds 	compat_ulong_t shmmax;
1001da177e4SLinus Torvalds 	compat_ulong_t shmmin;
1011da177e4SLinus Torvalds 	compat_ulong_t shmmni;
1021da177e4SLinus Torvalds 	compat_ulong_t shmseg;
1031da177e4SLinus Torvalds 	compat_ulong_t shmall;
1041da177e4SLinus Torvalds 	compat_ulong_t __unused1;
1051da177e4SLinus Torvalds 	compat_ulong_t __unused2;
1061da177e4SLinus Torvalds 	compat_ulong_t __unused3;
1071da177e4SLinus Torvalds 	compat_ulong_t __unused4;
1081da177e4SLinus Torvalds };
1091da177e4SLinus Torvalds 
1101da177e4SLinus Torvalds struct compat_shm_info {
1111da177e4SLinus Torvalds 	compat_int_t used_ids;
1121da177e4SLinus Torvalds 	compat_ulong_t shm_tot, shm_rss, shm_swp;
1131da177e4SLinus Torvalds 	compat_ulong_t swap_attempts, swap_successes;
1141da177e4SLinus Torvalds };
1151da177e4SLinus Torvalds 
1161da177e4SLinus Torvalds extern int sem_ctls[];
1171da177e4SLinus Torvalds #define sc_semopm	(sem_ctls[2])
1181da177e4SLinus Torvalds 
1191da177e4SLinus Torvalds static inline int compat_ipc_parse_version(int *cmd)
1201da177e4SLinus Torvalds {
121c1d7e01dSWill Deacon #ifdef	CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION
1221da177e4SLinus Torvalds 	int version = *cmd & IPC_64;
1231da177e4SLinus Torvalds 
1241da177e4SLinus Torvalds 	/* this is tricky: architectures that have support for the old
1251da177e4SLinus Torvalds 	 * ipc structures in 64 bit binaries need to have IPC_64 set
1261da177e4SLinus Torvalds 	 * in cmd, the others need to have it cleared */
1271da177e4SLinus Torvalds #ifndef ipc_parse_version
1281da177e4SLinus Torvalds 	*cmd |= IPC_64;
1291da177e4SLinus Torvalds #else
1301da177e4SLinus Torvalds 	*cmd &= ~IPC_64;
1311da177e4SLinus Torvalds #endif
1321da177e4SLinus Torvalds 	return version;
13348b25c43SChris Metcalf #else
13448b25c43SChris Metcalf 	/* With the asm-generic APIs, we always use the 64-bit versions. */
13548b25c43SChris Metcalf 	return IPC_64;
13648b25c43SChris Metcalf #endif
1371da177e4SLinus Torvalds }
1381da177e4SLinus Torvalds 
1391da177e4SLinus Torvalds static inline int __get_compat_ipc64_perm(struct ipc64_perm *p64,
1401da177e4SLinus Torvalds 					  struct compat_ipc64_perm __user *up64)
1411da177e4SLinus Torvalds {
1421da177e4SLinus Torvalds 	int err;
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds 	err  = __get_user(p64->uid, &up64->uid);
1451da177e4SLinus Torvalds 	err |= __get_user(p64->gid, &up64->gid);
1461da177e4SLinus Torvalds 	err |= __get_user(p64->mode, &up64->mode);
1471da177e4SLinus Torvalds 	return err;
1481da177e4SLinus Torvalds }
1491da177e4SLinus Torvalds 
1501da177e4SLinus Torvalds static inline int __get_compat_ipc_perm(struct ipc64_perm *p,
1511da177e4SLinus Torvalds 					struct compat_ipc_perm __user *up)
1521da177e4SLinus Torvalds {
1531da177e4SLinus Torvalds 	int err;
1541da177e4SLinus Torvalds 
1551da177e4SLinus Torvalds 	err  = __get_user(p->uid, &up->uid);
1561da177e4SLinus Torvalds 	err |= __get_user(p->gid, &up->gid);
1571da177e4SLinus Torvalds 	err |= __get_user(p->mode, &up->mode);
1581da177e4SLinus Torvalds 	return err;
1591da177e4SLinus Torvalds }
1601da177e4SLinus Torvalds 
1611da177e4SLinus Torvalds static inline int __put_compat_ipc64_perm(struct ipc64_perm *p64,
1621da177e4SLinus Torvalds 					  struct compat_ipc64_perm __user *up64)
1631da177e4SLinus Torvalds {
1641da177e4SLinus Torvalds 	int err;
1651da177e4SLinus Torvalds 
1661da177e4SLinus Torvalds 	err  = __put_user(p64->key, &up64->key);
1671da177e4SLinus Torvalds 	err |= __put_user(p64->uid, &up64->uid);
1681da177e4SLinus Torvalds 	err |= __put_user(p64->gid, &up64->gid);
1691da177e4SLinus Torvalds 	err |= __put_user(p64->cuid, &up64->cuid);
1701da177e4SLinus Torvalds 	err |= __put_user(p64->cgid, &up64->cgid);
1711da177e4SLinus Torvalds 	err |= __put_user(p64->mode, &up64->mode);
1721da177e4SLinus Torvalds 	err |= __put_user(p64->seq, &up64->seq);
1731da177e4SLinus Torvalds 	return err;
1741da177e4SLinus Torvalds }
1751da177e4SLinus Torvalds 
1761da177e4SLinus Torvalds static inline int __put_compat_ipc_perm(struct ipc64_perm *p,
1771da177e4SLinus Torvalds 					struct compat_ipc_perm __user *up)
1781da177e4SLinus Torvalds {
1791da177e4SLinus Torvalds 	int err;
180202e5979SStephen Rothwell 	__compat_uid_t u;
181202e5979SStephen Rothwell 	__compat_gid_t g;
1821da177e4SLinus Torvalds 
1831da177e4SLinus Torvalds 	err  = __put_user(p->key, &up->key);
1841da177e4SLinus Torvalds 	SET_UID(u, p->uid);
1851da177e4SLinus Torvalds 	err |= __put_user(u, &up->uid);
1861da177e4SLinus Torvalds 	SET_GID(g, p->gid);
1871da177e4SLinus Torvalds 	err |= __put_user(g, &up->gid);
1881da177e4SLinus Torvalds 	SET_UID(u, p->cuid);
1891da177e4SLinus Torvalds 	err |= __put_user(u, &up->cuid);
1901da177e4SLinus Torvalds 	SET_GID(g, p->cgid);
1911da177e4SLinus Torvalds 	err |= __put_user(g, &up->cgid);
1921da177e4SLinus Torvalds 	err |= __put_user(p->mode, &up->mode);
1931da177e4SLinus Torvalds 	err |= __put_user(p->seq, &up->seq);
1941da177e4SLinus Torvalds 	return err;
1951da177e4SLinus Torvalds }
1961da177e4SLinus Torvalds 
1971da177e4SLinus Torvalds static inline int get_compat_semid64_ds(struct semid64_ds *s64,
1981da177e4SLinus Torvalds 					struct compat_semid64_ds __user *up64)
1991da177e4SLinus Torvalds {
2001da177e4SLinus Torvalds 	if (!access_ok (VERIFY_READ, up64, sizeof(*up64)))
2011da177e4SLinus Torvalds 		return -EFAULT;
2021da177e4SLinus Torvalds 	return __get_compat_ipc64_perm(&s64->sem_perm, &up64->sem_perm);
2031da177e4SLinus Torvalds }
2041da177e4SLinus Torvalds 
2051da177e4SLinus Torvalds static inline int get_compat_semid_ds(struct semid64_ds *s,
2061da177e4SLinus Torvalds 				      struct compat_semid_ds __user *up)
2071da177e4SLinus Torvalds {
2081da177e4SLinus Torvalds 	if (!access_ok (VERIFY_READ, up, sizeof(*up)))
2091da177e4SLinus Torvalds 		return -EFAULT;
2101da177e4SLinus Torvalds 	return __get_compat_ipc_perm(&s->sem_perm, &up->sem_perm);
2111da177e4SLinus Torvalds }
2121da177e4SLinus Torvalds 
2131da177e4SLinus Torvalds static inline int put_compat_semid64_ds(struct semid64_ds *s64,
2141da177e4SLinus Torvalds 					struct compat_semid64_ds __user *up64)
2151da177e4SLinus Torvalds {
2161da177e4SLinus Torvalds 	int err;
2171da177e4SLinus Torvalds 
2181da177e4SLinus Torvalds 	if (!access_ok (VERIFY_WRITE, up64, sizeof(*up64)))
2191da177e4SLinus Torvalds 		return -EFAULT;
2201da177e4SLinus Torvalds 	err  = __put_compat_ipc64_perm(&s64->sem_perm, &up64->sem_perm);
2211da177e4SLinus Torvalds 	err |= __put_user(s64->sem_otime, &up64->sem_otime);
2221da177e4SLinus Torvalds 	err |= __put_user(s64->sem_ctime, &up64->sem_ctime);
2231da177e4SLinus Torvalds 	err |= __put_user(s64->sem_nsems, &up64->sem_nsems);
2241da177e4SLinus Torvalds 	return err;
2251da177e4SLinus Torvalds }
2261da177e4SLinus Torvalds 
2271da177e4SLinus Torvalds static inline int put_compat_semid_ds(struct semid64_ds *s,
2281da177e4SLinus Torvalds 				      struct compat_semid_ds __user *up)
2291da177e4SLinus Torvalds {
2301da177e4SLinus Torvalds 	int err;
2311da177e4SLinus Torvalds 
2321da177e4SLinus Torvalds 	if (!access_ok (VERIFY_WRITE, up, sizeof(*up)))
233d57d9731SAlexander Graf 		return -EFAULT;
2341da177e4SLinus Torvalds 	err  = __put_compat_ipc_perm(&s->sem_perm, &up->sem_perm);
2351da177e4SLinus Torvalds 	err |= __put_user(s->sem_otime, &up->sem_otime);
2361da177e4SLinus Torvalds 	err |= __put_user(s->sem_ctime, &up->sem_ctime);
2371da177e4SLinus Torvalds 	err |= __put_user(s->sem_nsems, &up->sem_nsems);
2381da177e4SLinus Torvalds 	return err;
2391da177e4SLinus Torvalds }
2401da177e4SLinus Torvalds 
24148b25c43SChris Metcalf static long do_compat_semctl(int first, int second, int third, u32 pad)
2421da177e4SLinus Torvalds {
2431da177e4SLinus Torvalds 	union semun fourth;
2441da177e4SLinus Torvalds 	int err, err2;
2451da177e4SLinus Torvalds 	struct semid64_ds s64;
2461da177e4SLinus Torvalds 	struct semid64_ds __user *up64;
2471da177e4SLinus Torvalds 	int version = compat_ipc_parse_version(&third);
2481da177e4SLinus Torvalds 
24903145bebSDan Rosenberg 	memset(&s64, 0, sizeof(s64));
25003145bebSDan Rosenberg 
2511da177e4SLinus Torvalds 	if ((third & (~IPC_64)) == SETVAL)
2521da177e4SLinus Torvalds 		fourth.val = (int) pad;
2531da177e4SLinus Torvalds 	else
2541da177e4SLinus Torvalds 		fourth.__pad = compat_ptr(pad);
2551da177e4SLinus Torvalds 	switch (third & (~IPC_64)) {
2561da177e4SLinus Torvalds 	case IPC_INFO:
2571da177e4SLinus Torvalds 	case IPC_RMID:
2581da177e4SLinus Torvalds 	case SEM_INFO:
2591da177e4SLinus Torvalds 	case GETVAL:
2601da177e4SLinus Torvalds 	case GETPID:
2611da177e4SLinus Torvalds 	case GETNCNT:
2621da177e4SLinus Torvalds 	case GETZCNT:
2631da177e4SLinus Torvalds 	case GETALL:
2641da177e4SLinus Torvalds 	case SETVAL:
2651da177e4SLinus Torvalds 	case SETALL:
2661da177e4SLinus Torvalds 		err = sys_semctl(first, second, third, fourth);
2671da177e4SLinus Torvalds 		break;
2681da177e4SLinus Torvalds 
2691da177e4SLinus Torvalds 	case IPC_STAT:
2701da177e4SLinus Torvalds 	case SEM_STAT:
2711da177e4SLinus Torvalds 		up64 = compat_alloc_user_space(sizeof(s64));
2721da177e4SLinus Torvalds 		fourth.__pad = up64;
2731da177e4SLinus Torvalds 		err = sys_semctl(first, second, third, fourth);
2741da177e4SLinus Torvalds 		if (err < 0)
2751da177e4SLinus Torvalds 			break;
2761da177e4SLinus Torvalds 		if (copy_from_user(&s64, up64, sizeof(s64)))
2771da177e4SLinus Torvalds 			err2 = -EFAULT;
2781da177e4SLinus Torvalds 		else if (version == IPC_64)
2791da177e4SLinus Torvalds 			err2 = put_compat_semid64_ds(&s64, compat_ptr(pad));
2801da177e4SLinus Torvalds 		else
2811da177e4SLinus Torvalds 			err2 = put_compat_semid_ds(&s64, compat_ptr(pad));
2821da177e4SLinus Torvalds 		if (err2)
2831da177e4SLinus Torvalds 			err = -EFAULT;
2841da177e4SLinus Torvalds 		break;
2851da177e4SLinus Torvalds 
2861da177e4SLinus Torvalds 	case IPC_SET:
2871da177e4SLinus Torvalds 		if (version == IPC_64) {
2881da177e4SLinus Torvalds 			err = get_compat_semid64_ds(&s64, compat_ptr(pad));
2891da177e4SLinus Torvalds 		} else {
2901da177e4SLinus Torvalds 			err = get_compat_semid_ds(&s64, compat_ptr(pad));
2911da177e4SLinus Torvalds 		}
2921da177e4SLinus Torvalds 		up64 = compat_alloc_user_space(sizeof(s64));
2931da177e4SLinus Torvalds 		if (copy_to_user(up64, &s64, sizeof(s64)))
2941da177e4SLinus Torvalds 			err = -EFAULT;
2951da177e4SLinus Torvalds 		if (err)
2961da177e4SLinus Torvalds 			break;
2971da177e4SLinus Torvalds 
2981da177e4SLinus Torvalds 		fourth.__pad = up64;
2991da177e4SLinus Torvalds 		err = sys_semctl(first, second, third, fourth);
3001da177e4SLinus Torvalds 		break;
3011da177e4SLinus Torvalds 
3021da177e4SLinus Torvalds 	default:
3031da177e4SLinus Torvalds 		err = -EINVAL;
3041da177e4SLinus Torvalds 		break;
3051da177e4SLinus Torvalds 	}
3061da177e4SLinus Torvalds 	return err;
3071da177e4SLinus Torvalds }
3081da177e4SLinus Torvalds 
309f9dd87f4SStanislav Kinsbursky long compat_do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz)
310f9dd87f4SStanislav Kinsbursky {
311f9dd87f4SStanislav Kinsbursky 	struct compat_msgbuf __user *msgp = dest;
312f9dd87f4SStanislav Kinsbursky 	size_t msgsz;
313f9dd87f4SStanislav Kinsbursky 
314f9dd87f4SStanislav Kinsbursky 	if (put_user(msg->m_type, &msgp->mtype))
315f9dd87f4SStanislav Kinsbursky 		return -EFAULT;
316f9dd87f4SStanislav Kinsbursky 
317f9dd87f4SStanislav Kinsbursky 	msgsz = (bufsz > msg->m_ts) ? msg->m_ts : bufsz;
318f9dd87f4SStanislav Kinsbursky 	if (store_msg(msgp->mtext, msg, msgsz))
319f9dd87f4SStanislav Kinsbursky 		return -EFAULT;
320f9dd87f4SStanislav Kinsbursky 	return msgsz;
321f9dd87f4SStanislav Kinsbursky }
322f9dd87f4SStanislav Kinsbursky 
32348b25c43SChris Metcalf #ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC
32448b25c43SChris Metcalf long compat_sys_semctl(int first, int second, int third, void __user *uptr)
32548b25c43SChris Metcalf {
32648b25c43SChris Metcalf 	u32 pad;
32748b25c43SChris Metcalf 
32848b25c43SChris Metcalf 	if (!uptr)
32948b25c43SChris Metcalf 		return -EINVAL;
33048b25c43SChris Metcalf 	if (get_user(pad, (u32 __user *) uptr))
33148b25c43SChris Metcalf 		return -EFAULT;
33248b25c43SChris Metcalf 	return do_compat_semctl(first, second, third, pad);
33348b25c43SChris Metcalf }
33448b25c43SChris Metcalf 
3351da177e4SLinus Torvalds long compat_sys_msgsnd(int first, int second, int third, void __user *uptr)
3361da177e4SLinus Torvalds {
3371da177e4SLinus Torvalds 	struct compat_msgbuf __user *up = uptr;
3381da177e4SLinus Torvalds 	long type;
3391da177e4SLinus Torvalds 
3401da177e4SLinus Torvalds 	if (first < 0)
3411da177e4SLinus Torvalds 		return -EINVAL;
342651971cbSsuzuki 	if (second < 0)
3431da177e4SLinus Torvalds 		return -EINVAL;
3441da177e4SLinus Torvalds 
345651971cbSsuzuki 	if (get_user(type, &up->mtype))
3461da177e4SLinus Torvalds 		return -EFAULT;
3471da177e4SLinus Torvalds 
348651971cbSsuzuki 	return do_msgsnd(first, type, up->mtext, second, third);
3491da177e4SLinus Torvalds }
3501da177e4SLinus Torvalds 
3511da177e4SLinus Torvalds long compat_sys_msgrcv(int first, int second, int msgtyp, int third,
3521da177e4SLinus Torvalds 			   int version, void __user *uptr)
3531da177e4SLinus Torvalds {
3541da177e4SLinus Torvalds 	if (first < 0)
3551da177e4SLinus Torvalds 		return -EINVAL;
356651971cbSsuzuki 	if (second < 0)
3571da177e4SLinus Torvalds 		return -EINVAL;
3581da177e4SLinus Torvalds 
3591da177e4SLinus Torvalds 	if (!version) {
3601da177e4SLinus Torvalds 		struct compat_ipc_kludge ipck;
3611da177e4SLinus Torvalds 		if (!uptr)
362f9dd87f4SStanislav Kinsbursky 			return -EINVAL;
3631da177e4SLinus Torvalds 		if (copy_from_user (&ipck, uptr, sizeof(ipck)))
364f9dd87f4SStanislav Kinsbursky 			return -EFAULT;
3651da177e4SLinus Torvalds 		uptr = compat_ptr(ipck.msgp);
3661da177e4SLinus Torvalds 		msgtyp = ipck.msgtyp;
3671da177e4SLinus Torvalds 	}
3683a665531SStanislav Kinsbursky 	return do_msgrcv(first, uptr, second, msgtyp, third,
3693a665531SStanislav Kinsbursky 			 compat_do_msg_fill);
3701da177e4SLinus Torvalds }
371*56e41d3cSAl Viro 
372*56e41d3cSAl Viro COMPAT_SYSCALL_DEFINE6(ipc, u32, call, int, first, int, second,
373*56e41d3cSAl Viro 	u32, third, compat_uptr_t, ptr, u32, fifth)
374*56e41d3cSAl Viro {
375*56e41d3cSAl Viro 	int version;
376*56e41d3cSAl Viro 
377*56e41d3cSAl Viro 	version = call >> 16; /* hack for backward compatibility */
378*56e41d3cSAl Viro 	call &= 0xffff;
379*56e41d3cSAl Viro 
380*56e41d3cSAl Viro 	switch (call) {
381*56e41d3cSAl Viro 	case SEMOP:
382*56e41d3cSAl Viro 		/* struct sembuf is the same on 32 and 64bit :)) */
383*56e41d3cSAl Viro 		return sys_semtimedop(first, compat_ptr(ptr), second, NULL);
384*56e41d3cSAl Viro 	case SEMTIMEDOP:
385*56e41d3cSAl Viro 		return compat_sys_semtimedop(first, compat_ptr(ptr), second,
386*56e41d3cSAl Viro 						compat_ptr(fifth));
387*56e41d3cSAl Viro 	case SEMGET:
388*56e41d3cSAl Viro 		return sys_semget(first, second, third);
389*56e41d3cSAl Viro 	case SEMCTL:
390*56e41d3cSAl Viro 		return compat_sys_semctl(first, second, third, compat_ptr(ptr));
391*56e41d3cSAl Viro 
392*56e41d3cSAl Viro 	case MSGSND:
393*56e41d3cSAl Viro 		return compat_sys_msgsnd(first, second, third, compat_ptr(ptr));
394*56e41d3cSAl Viro 	case MSGRCV:
395*56e41d3cSAl Viro 		return compat_sys_msgrcv(first, second, fifth, third,
396*56e41d3cSAl Viro 					 version, compat_ptr(ptr));
397*56e41d3cSAl Viro 	case MSGGET:
398*56e41d3cSAl Viro 		return sys_msgget(first, second);
399*56e41d3cSAl Viro 	case MSGCTL:
400*56e41d3cSAl Viro 		return compat_sys_msgctl(first, second, compat_ptr(ptr));
401*56e41d3cSAl Viro 
402*56e41d3cSAl Viro 	case SHMAT:
403*56e41d3cSAl Viro 		return compat_sys_shmat(first, second, third, version,
404*56e41d3cSAl Viro 					compat_ptr(ptr));
405*56e41d3cSAl Viro 	case SHMDT:
406*56e41d3cSAl Viro 		return sys_shmdt(compat_ptr(ptr));
407*56e41d3cSAl Viro 	case SHMGET:
408*56e41d3cSAl Viro 		return sys_shmget(first, (unsigned)second, third);
409*56e41d3cSAl Viro 	case SHMCTL:
410*56e41d3cSAl Viro 		return compat_sys_shmctl(first, second, compat_ptr(ptr));
411*56e41d3cSAl Viro 	}
412*56e41d3cSAl Viro 
413*56e41d3cSAl Viro 	return -ENOSYS;
414*56e41d3cSAl Viro }
41548b25c43SChris Metcalf #else
41648b25c43SChris Metcalf long compat_sys_semctl(int semid, int semnum, int cmd, int arg)
41748b25c43SChris Metcalf {
41848b25c43SChris Metcalf 	return do_compat_semctl(semid, semnum, cmd, arg);
41948b25c43SChris Metcalf }
42048b25c43SChris Metcalf 
42148b25c43SChris Metcalf long compat_sys_msgsnd(int msqid, struct compat_msgbuf __user *msgp,
42205ba3f1aSWill Deacon 		       compat_ssize_t msgsz, int msgflg)
42348b25c43SChris Metcalf {
42448b25c43SChris Metcalf 	compat_long_t mtype;
42548b25c43SChris Metcalf 
42648b25c43SChris Metcalf 	if (get_user(mtype, &msgp->mtype))
42748b25c43SChris Metcalf 		return -EFAULT;
42805ba3f1aSWill Deacon 	return do_msgsnd(msqid, mtype, msgp->mtext, (ssize_t)msgsz, msgflg);
42948b25c43SChris Metcalf }
43048b25c43SChris Metcalf 
43148b25c43SChris Metcalf long compat_sys_msgrcv(int msqid, struct compat_msgbuf __user *msgp,
43205ba3f1aSWill Deacon 		       compat_ssize_t msgsz, long msgtyp, int msgflg)
43348b25c43SChris Metcalf {
434f9dd87f4SStanislav Kinsbursky 	return do_msgrcv(msqid, msgp, (ssize_t)msgsz, msgtyp, msgflg,
435f9dd87f4SStanislav Kinsbursky 			 compat_do_msg_fill);
43648b25c43SChris Metcalf }
43748b25c43SChris Metcalf #endif
4381da177e4SLinus Torvalds 
4391da177e4SLinus Torvalds static inline int get_compat_msqid64(struct msqid64_ds *m64,
4401da177e4SLinus Torvalds 				     struct compat_msqid64_ds __user *up64)
4411da177e4SLinus Torvalds {
4421da177e4SLinus Torvalds 	int err;
4431da177e4SLinus Torvalds 
4441da177e4SLinus Torvalds 	if (!access_ok(VERIFY_READ, up64, sizeof(*up64)))
4451da177e4SLinus Torvalds 		return -EFAULT;
4461da177e4SLinus Torvalds 	err  = __get_compat_ipc64_perm(&m64->msg_perm, &up64->msg_perm);
4471da177e4SLinus Torvalds 	err |= __get_user(m64->msg_qbytes, &up64->msg_qbytes);
4481da177e4SLinus Torvalds 	return err;
4491da177e4SLinus Torvalds }
4501da177e4SLinus Torvalds 
4511da177e4SLinus Torvalds static inline int get_compat_msqid(struct msqid64_ds *m,
4521da177e4SLinus Torvalds 				   struct compat_msqid_ds __user *up)
4531da177e4SLinus Torvalds {
4541da177e4SLinus Torvalds 	int err;
4551da177e4SLinus Torvalds 
4561da177e4SLinus Torvalds 	if (!access_ok(VERIFY_READ, up, sizeof(*up)))
4571da177e4SLinus Torvalds 		return -EFAULT;
4581da177e4SLinus Torvalds 	err  = __get_compat_ipc_perm(&m->msg_perm, &up->msg_perm);
4591da177e4SLinus Torvalds 	err |= __get_user(m->msg_qbytes, &up->msg_qbytes);
4601da177e4SLinus Torvalds 	return err;
4611da177e4SLinus Torvalds }
4621da177e4SLinus Torvalds 
4631da177e4SLinus Torvalds static inline int put_compat_msqid64_ds(struct msqid64_ds *m64,
4641da177e4SLinus Torvalds 				 struct compat_msqid64_ds __user *up64)
4651da177e4SLinus Torvalds {
4661da177e4SLinus Torvalds 	int err;
4671da177e4SLinus Torvalds 
4681da177e4SLinus Torvalds 	if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
4691da177e4SLinus Torvalds 		return -EFAULT;
4701da177e4SLinus Torvalds 	err  = __put_compat_ipc64_perm(&m64->msg_perm, &up64->msg_perm);
4711da177e4SLinus Torvalds 	err |= __put_user(m64->msg_stime, &up64->msg_stime);
4721da177e4SLinus Torvalds 	err |= __put_user(m64->msg_rtime, &up64->msg_rtime);
4731da177e4SLinus Torvalds 	err |= __put_user(m64->msg_ctime, &up64->msg_ctime);
4741da177e4SLinus Torvalds 	err |= __put_user(m64->msg_cbytes, &up64->msg_cbytes);
4751da177e4SLinus Torvalds 	err |= __put_user(m64->msg_qnum, &up64->msg_qnum);
4761da177e4SLinus Torvalds 	err |= __put_user(m64->msg_qbytes, &up64->msg_qbytes);
4771da177e4SLinus Torvalds 	err |= __put_user(m64->msg_lspid, &up64->msg_lspid);
4781da177e4SLinus Torvalds 	err |= __put_user(m64->msg_lrpid, &up64->msg_lrpid);
4791da177e4SLinus Torvalds 	return err;
4801da177e4SLinus Torvalds }
4811da177e4SLinus Torvalds 
4821da177e4SLinus Torvalds static inline int put_compat_msqid_ds(struct msqid64_ds *m,
4831da177e4SLinus Torvalds 				      struct compat_msqid_ds __user *up)
4841da177e4SLinus Torvalds {
4851da177e4SLinus Torvalds 	int err;
4861da177e4SLinus Torvalds 
4871da177e4SLinus Torvalds 	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
4881da177e4SLinus Torvalds 		return -EFAULT;
4891da177e4SLinus Torvalds 	err  = __put_compat_ipc_perm(&m->msg_perm, &up->msg_perm);
4901da177e4SLinus Torvalds 	err |= __put_user(m->msg_stime, &up->msg_stime);
4911da177e4SLinus Torvalds 	err |= __put_user(m->msg_rtime, &up->msg_rtime);
4921da177e4SLinus Torvalds 	err |= __put_user(m->msg_ctime, &up->msg_ctime);
4931da177e4SLinus Torvalds 	err |= __put_user(m->msg_cbytes, &up->msg_cbytes);
4941da177e4SLinus Torvalds 	err |= __put_user(m->msg_qnum, &up->msg_qnum);
4951da177e4SLinus Torvalds 	err |= __put_user(m->msg_qbytes, &up->msg_qbytes);
4961da177e4SLinus Torvalds 	err |= __put_user(m->msg_lspid, &up->msg_lspid);
4971da177e4SLinus Torvalds 	err |= __put_user(m->msg_lrpid, &up->msg_lrpid);
4981da177e4SLinus Torvalds 	return err;
4991da177e4SLinus Torvalds }
5001da177e4SLinus Torvalds 
5011da177e4SLinus Torvalds long compat_sys_msgctl(int first, int second, void __user *uptr)
5021da177e4SLinus Torvalds {
5031da177e4SLinus Torvalds 	int err, err2;
5041da177e4SLinus Torvalds 	struct msqid64_ds m64;
5051da177e4SLinus Torvalds 	int version = compat_ipc_parse_version(&second);
5061da177e4SLinus Torvalds 	void __user *p;
5071da177e4SLinus Torvalds 
50803145bebSDan Rosenberg 	memset(&m64, 0, sizeof(m64));
50903145bebSDan Rosenberg 
5101da177e4SLinus Torvalds 	switch (second & (~IPC_64)) {
5111da177e4SLinus Torvalds 	case IPC_INFO:
5121da177e4SLinus Torvalds 	case IPC_RMID:
5131da177e4SLinus Torvalds 	case MSG_INFO:
5141da177e4SLinus Torvalds 		err = sys_msgctl(first, second, uptr);
5151da177e4SLinus Torvalds 		break;
5161da177e4SLinus Torvalds 
5171da177e4SLinus Torvalds 	case IPC_SET:
5181da177e4SLinus Torvalds 		if (version == IPC_64) {
5191da177e4SLinus Torvalds 			err = get_compat_msqid64(&m64, uptr);
5201da177e4SLinus Torvalds 		} else {
5211da177e4SLinus Torvalds 			err = get_compat_msqid(&m64, uptr);
5221da177e4SLinus Torvalds 		}
5231da177e4SLinus Torvalds 		if (err)
5241da177e4SLinus Torvalds 			break;
5251da177e4SLinus Torvalds 		p = compat_alloc_user_space(sizeof(m64));
5261da177e4SLinus Torvalds 		if (copy_to_user(p, &m64, sizeof(m64)))
5271da177e4SLinus Torvalds 			err = -EFAULT;
5281da177e4SLinus Torvalds 		else
5291da177e4SLinus Torvalds 			err = sys_msgctl(first, second, p);
5301da177e4SLinus Torvalds 		break;
5311da177e4SLinus Torvalds 
5321da177e4SLinus Torvalds 	case IPC_STAT:
5331da177e4SLinus Torvalds 	case MSG_STAT:
5341da177e4SLinus Torvalds 		p = compat_alloc_user_space(sizeof(m64));
5351da177e4SLinus Torvalds 		err = sys_msgctl(first, second, p);
5361da177e4SLinus Torvalds 		if (err < 0)
5371da177e4SLinus Torvalds 			break;
5381da177e4SLinus Torvalds 		if (copy_from_user(&m64, p, sizeof(m64)))
5391da177e4SLinus Torvalds 			err2 = -EFAULT;
5401da177e4SLinus Torvalds 		else if (version == IPC_64)
5411da177e4SLinus Torvalds 			err2 = put_compat_msqid64_ds(&m64, uptr);
5421da177e4SLinus Torvalds 		else
5431da177e4SLinus Torvalds 			err2 = put_compat_msqid_ds(&m64, uptr);
5441da177e4SLinus Torvalds 		if (err2)
5451da177e4SLinus Torvalds 			err = -EFAULT;
5461da177e4SLinus Torvalds 		break;
5471da177e4SLinus Torvalds 
5481da177e4SLinus Torvalds 	default:
5491da177e4SLinus Torvalds 		err = -EINVAL;
5501da177e4SLinus Torvalds 		break;
5511da177e4SLinus Torvalds 	}
5521da177e4SLinus Torvalds 	return err;
5531da177e4SLinus Torvalds }
5541da177e4SLinus Torvalds 
555079a96aeSWill Deacon #ifndef COMPAT_SHMLBA
556079a96aeSWill Deacon #define COMPAT_SHMLBA	SHMLBA
557079a96aeSWill Deacon #endif
558079a96aeSWill Deacon 
55948b25c43SChris Metcalf #ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC
5601da177e4SLinus Torvalds long compat_sys_shmat(int first, int second, compat_uptr_t third, int version,
5611da177e4SLinus Torvalds 			void __user *uptr)
5621da177e4SLinus Torvalds {
5631da177e4SLinus Torvalds 	int err;
5641da177e4SLinus Torvalds 	unsigned long raddr;
5651da177e4SLinus Torvalds 	compat_ulong_t __user *uaddr;
5661da177e4SLinus Torvalds 
5671da177e4SLinus Torvalds 	if (version == 1)
5681da177e4SLinus Torvalds 		return -EINVAL;
569079a96aeSWill Deacon 	err = do_shmat(first, uptr, second, &raddr, COMPAT_SHMLBA);
5701da177e4SLinus Torvalds 	if (err < 0)
5711da177e4SLinus Torvalds 		return err;
5721da177e4SLinus Torvalds 	uaddr = compat_ptr(third);
5731da177e4SLinus Torvalds 	return put_user(raddr, uaddr);
5741da177e4SLinus Torvalds }
57548b25c43SChris Metcalf #else
57648b25c43SChris Metcalf long compat_sys_shmat(int shmid, compat_uptr_t shmaddr, int shmflg)
57748b25c43SChris Metcalf {
57848b25c43SChris Metcalf 	unsigned long ret;
57948b25c43SChris Metcalf 	long err;
58048b25c43SChris Metcalf 
581079a96aeSWill Deacon 	err = do_shmat(shmid, compat_ptr(shmaddr), shmflg, &ret, COMPAT_SHMLBA);
58248b25c43SChris Metcalf 	if (err)
58348b25c43SChris Metcalf 		return err;
58448b25c43SChris Metcalf 	force_successful_syscall_return();
58548b25c43SChris Metcalf 	return (long)ret;
58648b25c43SChris Metcalf }
58748b25c43SChris Metcalf #endif
5881da177e4SLinus Torvalds 
5891da177e4SLinus Torvalds static inline int get_compat_shmid64_ds(struct shmid64_ds *s64,
5901da177e4SLinus Torvalds 					struct compat_shmid64_ds __user *up64)
5911da177e4SLinus Torvalds {
5921da177e4SLinus Torvalds 	if (!access_ok(VERIFY_READ, up64, sizeof(*up64)))
5931da177e4SLinus Torvalds 		return -EFAULT;
5941da177e4SLinus Torvalds 	return __get_compat_ipc64_perm(&s64->shm_perm, &up64->shm_perm);
5951da177e4SLinus Torvalds }
5961da177e4SLinus Torvalds 
5971da177e4SLinus Torvalds static inline int get_compat_shmid_ds(struct shmid64_ds *s,
5981da177e4SLinus Torvalds 				      struct compat_shmid_ds __user *up)
5991da177e4SLinus Torvalds {
6001da177e4SLinus Torvalds 	if (!access_ok(VERIFY_READ, up, sizeof(*up)))
6011da177e4SLinus Torvalds 		return -EFAULT;
6021da177e4SLinus Torvalds 	return __get_compat_ipc_perm(&s->shm_perm, &up->shm_perm);
6031da177e4SLinus Torvalds }
6041da177e4SLinus Torvalds 
6051da177e4SLinus Torvalds static inline int put_compat_shmid64_ds(struct shmid64_ds *s64,
6061da177e4SLinus Torvalds 					struct compat_shmid64_ds __user *up64)
6071da177e4SLinus Torvalds {
6081da177e4SLinus Torvalds 	int err;
6091da177e4SLinus Torvalds 
6101da177e4SLinus Torvalds 	if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
6111da177e4SLinus Torvalds 		return -EFAULT;
6121da177e4SLinus Torvalds 	err  = __put_compat_ipc64_perm(&s64->shm_perm, &up64->shm_perm);
6131da177e4SLinus Torvalds 	err |= __put_user(s64->shm_atime, &up64->shm_atime);
6141da177e4SLinus Torvalds 	err |= __put_user(s64->shm_dtime, &up64->shm_dtime);
6151da177e4SLinus Torvalds 	err |= __put_user(s64->shm_ctime, &up64->shm_ctime);
6161da177e4SLinus Torvalds 	err |= __put_user(s64->shm_segsz, &up64->shm_segsz);
6171da177e4SLinus Torvalds 	err |= __put_user(s64->shm_nattch, &up64->shm_nattch);
6181da177e4SLinus Torvalds 	err |= __put_user(s64->shm_cpid, &up64->shm_cpid);
6191da177e4SLinus Torvalds 	err |= __put_user(s64->shm_lpid, &up64->shm_lpid);
6201da177e4SLinus Torvalds 	return err;
6211da177e4SLinus Torvalds }
6221da177e4SLinus Torvalds 
6231da177e4SLinus Torvalds static inline int put_compat_shmid_ds(struct shmid64_ds *s,
6241da177e4SLinus Torvalds 				      struct compat_shmid_ds __user *up)
6251da177e4SLinus Torvalds {
6261da177e4SLinus Torvalds 	int err;
6271da177e4SLinus Torvalds 
6281da177e4SLinus Torvalds 	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
6291da177e4SLinus Torvalds 		return -EFAULT;
6301da177e4SLinus Torvalds 	err  = __put_compat_ipc_perm(&s->shm_perm, &up->shm_perm);
6311da177e4SLinus Torvalds 	err |= __put_user(s->shm_atime, &up->shm_atime);
6321da177e4SLinus Torvalds 	err |= __put_user(s->shm_dtime, &up->shm_dtime);
6331da177e4SLinus Torvalds 	err |= __put_user(s->shm_ctime, &up->shm_ctime);
6341da177e4SLinus Torvalds 	err |= __put_user(s->shm_segsz, &up->shm_segsz);
6351da177e4SLinus Torvalds 	err |= __put_user(s->shm_nattch, &up->shm_nattch);
6361da177e4SLinus Torvalds 	err |= __put_user(s->shm_cpid, &up->shm_cpid);
6371da177e4SLinus Torvalds 	err |= __put_user(s->shm_lpid, &up->shm_lpid);
6381da177e4SLinus Torvalds 	return err;
6391da177e4SLinus Torvalds }
6401da177e4SLinus Torvalds 
6411da177e4SLinus Torvalds static inline int put_compat_shminfo64(struct shminfo64 *smi,
6421da177e4SLinus Torvalds 				       struct compat_shminfo64 __user *up64)
6431da177e4SLinus Torvalds {
6441da177e4SLinus Torvalds 	int err;
6451da177e4SLinus Torvalds 
6461da177e4SLinus Torvalds 	if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
6471da177e4SLinus Torvalds 		return -EFAULT;
648af7c693fSGuy Streeter 	if (smi->shmmax > INT_MAX)
649af7c693fSGuy Streeter 		smi->shmmax = INT_MAX;
6501da177e4SLinus Torvalds 	err  = __put_user(smi->shmmax, &up64->shmmax);
6511da177e4SLinus Torvalds 	err |= __put_user(smi->shmmin, &up64->shmmin);
6521da177e4SLinus Torvalds 	err |= __put_user(smi->shmmni, &up64->shmmni);
6531da177e4SLinus Torvalds 	err |= __put_user(smi->shmseg, &up64->shmseg);
6541da177e4SLinus Torvalds 	err |= __put_user(smi->shmall, &up64->shmall);
6551da177e4SLinus Torvalds 	return err;
6561da177e4SLinus Torvalds }
6571da177e4SLinus Torvalds 
6581da177e4SLinus Torvalds static inline int put_compat_shminfo(struct shminfo64 *smi,
6591da177e4SLinus Torvalds 				     struct shminfo __user *up)
6601da177e4SLinus Torvalds {
6611da177e4SLinus Torvalds 	int err;
6621da177e4SLinus Torvalds 
6631da177e4SLinus Torvalds 	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
6641da177e4SLinus Torvalds 		return -EFAULT;
665af7c693fSGuy Streeter 	if (smi->shmmax > INT_MAX)
666af7c693fSGuy Streeter 		smi->shmmax = INT_MAX;
6671da177e4SLinus Torvalds 	err  = __put_user(smi->shmmax, &up->shmmax);
6681da177e4SLinus Torvalds 	err |= __put_user(smi->shmmin, &up->shmmin);
6691da177e4SLinus Torvalds 	err |= __put_user(smi->shmmni, &up->shmmni);
6701da177e4SLinus Torvalds 	err |= __put_user(smi->shmseg, &up->shmseg);
6711da177e4SLinus Torvalds 	err |= __put_user(smi->shmall, &up->shmall);
672214a627cSJesse Millan 	return err;
6731da177e4SLinus Torvalds }
6741da177e4SLinus Torvalds 
6751da177e4SLinus Torvalds static inline int put_compat_shm_info(struct shm_info __user *ip,
6761da177e4SLinus Torvalds 				      struct compat_shm_info __user *uip)
6771da177e4SLinus Torvalds {
6781da177e4SLinus Torvalds 	int err;
6791da177e4SLinus Torvalds 	struct shm_info si;
6801da177e4SLinus Torvalds 
6811da177e4SLinus Torvalds 	if (!access_ok(VERIFY_WRITE, uip, sizeof(*uip)) ||
6821da177e4SLinus Torvalds 	    copy_from_user(&si, ip, sizeof(si)))
6831da177e4SLinus Torvalds 		return -EFAULT;
6841da177e4SLinus Torvalds 	err  = __put_user(si.used_ids, &uip->used_ids);
6851da177e4SLinus Torvalds 	err |= __put_user(si.shm_tot, &uip->shm_tot);
6861da177e4SLinus Torvalds 	err |= __put_user(si.shm_rss, &uip->shm_rss);
6871da177e4SLinus Torvalds 	err |= __put_user(si.shm_swp, &uip->shm_swp);
6881da177e4SLinus Torvalds 	err |= __put_user(si.swap_attempts, &uip->swap_attempts);
6891da177e4SLinus Torvalds 	err |= __put_user(si.swap_successes, &uip->swap_successes);
6901da177e4SLinus Torvalds 	return err;
6911da177e4SLinus Torvalds }
6921da177e4SLinus Torvalds 
6931da177e4SLinus Torvalds long compat_sys_shmctl(int first, int second, void __user *uptr)
6941da177e4SLinus Torvalds {
6951da177e4SLinus Torvalds 	void __user *p;
6961da177e4SLinus Torvalds 	struct shmid64_ds s64;
6971da177e4SLinus Torvalds 	struct shminfo64 smi;
6981da177e4SLinus Torvalds 	int err, err2;
6991da177e4SLinus Torvalds 	int version = compat_ipc_parse_version(&second);
7001da177e4SLinus Torvalds 
70103145bebSDan Rosenberg 	memset(&s64, 0, sizeof(s64));
70203145bebSDan Rosenberg 
7031da177e4SLinus Torvalds 	switch (second & (~IPC_64)) {
7041da177e4SLinus Torvalds 	case IPC_RMID:
7051da177e4SLinus Torvalds 	case SHM_LOCK:
7061da177e4SLinus Torvalds 	case SHM_UNLOCK:
7071da177e4SLinus Torvalds 		err = sys_shmctl(first, second, uptr);
7081da177e4SLinus Torvalds 		break;
7091da177e4SLinus Torvalds 
7101da177e4SLinus Torvalds 	case IPC_INFO:
7111da177e4SLinus Torvalds 		p = compat_alloc_user_space(sizeof(smi));
7121da177e4SLinus Torvalds 		err = sys_shmctl(first, second, p);
7131da177e4SLinus Torvalds 		if (err < 0)
7141da177e4SLinus Torvalds 			break;
7151da177e4SLinus Torvalds 		if (copy_from_user(&smi, p, sizeof(smi)))
7161da177e4SLinus Torvalds 			err2 = -EFAULT;
7171da177e4SLinus Torvalds 		else if (version == IPC_64)
7181da177e4SLinus Torvalds 			err2 = put_compat_shminfo64(&smi, uptr);
7191da177e4SLinus Torvalds 		else
7201da177e4SLinus Torvalds 			err2 = put_compat_shminfo(&smi, uptr);
7211da177e4SLinus Torvalds 		if (err2)
7221da177e4SLinus Torvalds 			err = -EFAULT;
7231da177e4SLinus Torvalds 		break;
7241da177e4SLinus Torvalds 
7251da177e4SLinus Torvalds 
7261da177e4SLinus Torvalds 	case IPC_SET:
7271da177e4SLinus Torvalds 		if (version == IPC_64) {
7281da177e4SLinus Torvalds 			err = get_compat_shmid64_ds(&s64, uptr);
7291da177e4SLinus Torvalds 		} else {
7301da177e4SLinus Torvalds 			err = get_compat_shmid_ds(&s64, uptr);
7311da177e4SLinus Torvalds 		}
7321da177e4SLinus Torvalds 		if (err)
7331da177e4SLinus Torvalds 			break;
7341da177e4SLinus Torvalds 		p = compat_alloc_user_space(sizeof(s64));
7351da177e4SLinus Torvalds 		if (copy_to_user(p, &s64, sizeof(s64)))
7361da177e4SLinus Torvalds 			err = -EFAULT;
7371da177e4SLinus Torvalds 		else
7381da177e4SLinus Torvalds 			err = sys_shmctl(first, second, p);
7391da177e4SLinus Torvalds 		break;
7401da177e4SLinus Torvalds 
7411da177e4SLinus Torvalds 	case IPC_STAT:
7421da177e4SLinus Torvalds 	case SHM_STAT:
7431da177e4SLinus Torvalds 		p = compat_alloc_user_space(sizeof(s64));
7441da177e4SLinus Torvalds 		err = sys_shmctl(first, second, p);
7451da177e4SLinus Torvalds 		if (err < 0)
7461da177e4SLinus Torvalds 			break;
7471da177e4SLinus Torvalds 		if (copy_from_user(&s64, p, sizeof(s64)))
7481da177e4SLinus Torvalds 			err2 = -EFAULT;
7491da177e4SLinus Torvalds 		else if (version == IPC_64)
7501da177e4SLinus Torvalds 			err2 = put_compat_shmid64_ds(&s64, uptr);
7511da177e4SLinus Torvalds 		else
7521da177e4SLinus Torvalds 			err2 = put_compat_shmid_ds(&s64, uptr);
7531da177e4SLinus Torvalds 		if (err2)
7541da177e4SLinus Torvalds 			err = -EFAULT;
7551da177e4SLinus Torvalds 		break;
7561da177e4SLinus Torvalds 
7571da177e4SLinus Torvalds 	case SHM_INFO:
7581da177e4SLinus Torvalds 		p = compat_alloc_user_space(sizeof(struct shm_info));
7591da177e4SLinus Torvalds 		err = sys_shmctl(first, second, p);
7601da177e4SLinus Torvalds 		if (err < 0)
7611da177e4SLinus Torvalds 			break;
7621da177e4SLinus Torvalds 		err2 = put_compat_shm_info(p, uptr);
7631da177e4SLinus Torvalds 		if (err2)
7641da177e4SLinus Torvalds 			err = -EFAULT;
7651da177e4SLinus Torvalds 		break;
7661da177e4SLinus Torvalds 
7671da177e4SLinus Torvalds 	default:
7681da177e4SLinus Torvalds 		err = -EINVAL;
7691da177e4SLinus Torvalds 		break;
7701da177e4SLinus Torvalds 	}
7711da177e4SLinus Torvalds 	return err;
7721da177e4SLinus Torvalds }
7731da177e4SLinus Torvalds 
7741da177e4SLinus Torvalds long compat_sys_semtimedop(int semid, struct sembuf __user *tsems,
7751da177e4SLinus Torvalds 		unsigned nsops, const struct compat_timespec __user *timeout)
7761da177e4SLinus Torvalds {
7771da177e4SLinus Torvalds 	struct timespec __user *ts64 = NULL;
7781da177e4SLinus Torvalds 	if (timeout) {
7791da177e4SLinus Torvalds 		struct timespec ts;
7801da177e4SLinus Torvalds 		ts64 = compat_alloc_user_space(sizeof(*ts64));
7811da177e4SLinus Torvalds 		if (get_compat_timespec(&ts, timeout))
7821da177e4SLinus Torvalds 			return -EFAULT;
7831da177e4SLinus Torvalds 		if (copy_to_user(ts64, &ts, sizeof(ts)))
7841da177e4SLinus Torvalds 			return -EFAULT;
7851da177e4SLinus Torvalds 	}
7861da177e4SLinus Torvalds 	return sys_semtimedop(semid, tsems, nsops, ts64);
7871da177e4SLinus Torvalds }
788