xref: /linux/ipc/compat.c (revision 4ba24fef3eb3b142197135223b90ced2f319cd53)
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>
337153e402SPaul McQuade #include <linux/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 static inline int compat_ipc_parse_version(int *cmd)
1171da177e4SLinus Torvalds {
118c1d7e01dSWill Deacon #ifdef	CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION
1191da177e4SLinus Torvalds 	int version = *cmd & IPC_64;
1201da177e4SLinus Torvalds 
1211da177e4SLinus Torvalds 	/* this is tricky: architectures that have support for the old
1221da177e4SLinus Torvalds 	 * ipc structures in 64 bit binaries need to have IPC_64 set
1231da177e4SLinus Torvalds 	 * in cmd, the others need to have it cleared */
1241da177e4SLinus Torvalds #ifndef ipc_parse_version
1251da177e4SLinus Torvalds 	*cmd |= IPC_64;
1261da177e4SLinus Torvalds #else
1271da177e4SLinus Torvalds 	*cmd &= ~IPC_64;
1281da177e4SLinus Torvalds #endif
1291da177e4SLinus Torvalds 	return version;
13048b25c43SChris Metcalf #else
13148b25c43SChris Metcalf 	/* With the asm-generic APIs, we always use the 64-bit versions. */
13248b25c43SChris Metcalf 	return IPC_64;
13348b25c43SChris Metcalf #endif
1341da177e4SLinus Torvalds }
1351da177e4SLinus Torvalds 
1361da177e4SLinus Torvalds static inline int __get_compat_ipc64_perm(struct ipc64_perm *p64,
1371da177e4SLinus Torvalds 					  struct compat_ipc64_perm __user *up64)
1381da177e4SLinus Torvalds {
1391da177e4SLinus Torvalds 	int err;
1401da177e4SLinus Torvalds 
1411da177e4SLinus Torvalds 	err  = __get_user(p64->uid, &up64->uid);
1421da177e4SLinus Torvalds 	err |= __get_user(p64->gid, &up64->gid);
1431da177e4SLinus Torvalds 	err |= __get_user(p64->mode, &up64->mode);
1441da177e4SLinus Torvalds 	return err;
1451da177e4SLinus Torvalds }
1461da177e4SLinus Torvalds 
1471da177e4SLinus Torvalds static inline int __get_compat_ipc_perm(struct ipc64_perm *p,
1481da177e4SLinus Torvalds 					struct compat_ipc_perm __user *up)
1491da177e4SLinus Torvalds {
1501da177e4SLinus Torvalds 	int err;
1511da177e4SLinus Torvalds 
1521da177e4SLinus Torvalds 	err  = __get_user(p->uid, &up->uid);
1531da177e4SLinus Torvalds 	err |= __get_user(p->gid, &up->gid);
1541da177e4SLinus Torvalds 	err |= __get_user(p->mode, &up->mode);
1551da177e4SLinus Torvalds 	return err;
1561da177e4SLinus Torvalds }
1571da177e4SLinus Torvalds 
1581da177e4SLinus Torvalds static inline int __put_compat_ipc64_perm(struct ipc64_perm *p64,
1591da177e4SLinus Torvalds 					  struct compat_ipc64_perm __user *up64)
1601da177e4SLinus Torvalds {
1611da177e4SLinus Torvalds 	int err;
1621da177e4SLinus Torvalds 
1631da177e4SLinus Torvalds 	err  = __put_user(p64->key, &up64->key);
1641da177e4SLinus Torvalds 	err |= __put_user(p64->uid, &up64->uid);
1651da177e4SLinus Torvalds 	err |= __put_user(p64->gid, &up64->gid);
1661da177e4SLinus Torvalds 	err |= __put_user(p64->cuid, &up64->cuid);
1671da177e4SLinus Torvalds 	err |= __put_user(p64->cgid, &up64->cgid);
1681da177e4SLinus Torvalds 	err |= __put_user(p64->mode, &up64->mode);
1691da177e4SLinus Torvalds 	err |= __put_user(p64->seq, &up64->seq);
1701da177e4SLinus Torvalds 	return err;
1711da177e4SLinus Torvalds }
1721da177e4SLinus Torvalds 
1731da177e4SLinus Torvalds static inline int __put_compat_ipc_perm(struct ipc64_perm *p,
174*0d5e7580SMark Rustad 					struct compat_ipc_perm __user *uip)
1751da177e4SLinus Torvalds {
1761da177e4SLinus Torvalds 	int err;
177202e5979SStephen Rothwell 	__compat_uid_t u;
178202e5979SStephen Rothwell 	__compat_gid_t g;
1791da177e4SLinus Torvalds 
180*0d5e7580SMark Rustad 	err  = __put_user(p->key, &uip->key);
1811da177e4SLinus Torvalds 	SET_UID(u, p->uid);
182*0d5e7580SMark Rustad 	err |= __put_user(u, &uip->uid);
1831da177e4SLinus Torvalds 	SET_GID(g, p->gid);
184*0d5e7580SMark Rustad 	err |= __put_user(g, &uip->gid);
1851da177e4SLinus Torvalds 	SET_UID(u, p->cuid);
186*0d5e7580SMark Rustad 	err |= __put_user(u, &uip->cuid);
1871da177e4SLinus Torvalds 	SET_GID(g, p->cgid);
188*0d5e7580SMark Rustad 	err |= __put_user(g, &uip->cgid);
189*0d5e7580SMark Rustad 	err |= __put_user(p->mode, &uip->mode);
190*0d5e7580SMark Rustad 	err |= __put_user(p->seq, &uip->seq);
1911da177e4SLinus Torvalds 	return err;
1921da177e4SLinus Torvalds }
1931da177e4SLinus Torvalds 
194*0d5e7580SMark Rustad static inline int get_compat_semid64_ds(struct semid64_ds *sem64,
1951da177e4SLinus Torvalds 					struct compat_semid64_ds __user *up64)
1961da177e4SLinus Torvalds {
1971da177e4SLinus Torvalds 	if (!access_ok(VERIFY_READ, up64, sizeof(*up64)))
1981da177e4SLinus Torvalds 		return -EFAULT;
199*0d5e7580SMark Rustad 	return __get_compat_ipc64_perm(&sem64->sem_perm, &up64->sem_perm);
2001da177e4SLinus Torvalds }
2011da177e4SLinus Torvalds 
2021da177e4SLinus Torvalds static inline int get_compat_semid_ds(struct semid64_ds *s,
2031da177e4SLinus Torvalds 				      struct compat_semid_ds __user *up)
2041da177e4SLinus Torvalds {
2051da177e4SLinus Torvalds 	if (!access_ok(VERIFY_READ, up, sizeof(*up)))
2061da177e4SLinus Torvalds 		return -EFAULT;
2071da177e4SLinus Torvalds 	return __get_compat_ipc_perm(&s->sem_perm, &up->sem_perm);
2081da177e4SLinus Torvalds }
2091da177e4SLinus Torvalds 
210*0d5e7580SMark Rustad static inline int put_compat_semid64_ds(struct semid64_ds *sem64,
2111da177e4SLinus Torvalds 					struct compat_semid64_ds __user *up64)
2121da177e4SLinus Torvalds {
2131da177e4SLinus Torvalds 	int err;
2141da177e4SLinus Torvalds 
2151da177e4SLinus Torvalds 	if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
2161da177e4SLinus Torvalds 		return -EFAULT;
217*0d5e7580SMark Rustad 	err  = __put_compat_ipc64_perm(&sem64->sem_perm, &up64->sem_perm);
218*0d5e7580SMark Rustad 	err |= __put_user(sem64->sem_otime, &up64->sem_otime);
219*0d5e7580SMark Rustad 	err |= __put_user(sem64->sem_ctime, &up64->sem_ctime);
220*0d5e7580SMark Rustad 	err |= __put_user(sem64->sem_nsems, &up64->sem_nsems);
2211da177e4SLinus Torvalds 	return err;
2221da177e4SLinus Torvalds }
2231da177e4SLinus Torvalds 
2241da177e4SLinus Torvalds static inline int put_compat_semid_ds(struct semid64_ds *s,
2251da177e4SLinus Torvalds 				      struct compat_semid_ds __user *up)
2261da177e4SLinus Torvalds {
2271da177e4SLinus Torvalds 	int err;
2281da177e4SLinus Torvalds 
2291da177e4SLinus Torvalds 	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
230d57d9731SAlexander Graf 		return -EFAULT;
2311da177e4SLinus Torvalds 	err  = __put_compat_ipc_perm(&s->sem_perm, &up->sem_perm);
2321da177e4SLinus Torvalds 	err |= __put_user(s->sem_otime, &up->sem_otime);
2331da177e4SLinus Torvalds 	err |= __put_user(s->sem_ctime, &up->sem_ctime);
2341da177e4SLinus Torvalds 	err |= __put_user(s->sem_nsems, &up->sem_nsems);
2351da177e4SLinus Torvalds 	return err;
2361da177e4SLinus Torvalds }
2371da177e4SLinus Torvalds 
23848b25c43SChris Metcalf static long do_compat_semctl(int first, int second, int third, u32 pad)
2391da177e4SLinus Torvalds {
240e1fd1f49SAl Viro 	unsigned long fourth;
2411da177e4SLinus Torvalds 	int err, err2;
242*0d5e7580SMark Rustad 	struct semid64_ds sem64;
2431da177e4SLinus Torvalds 	struct semid64_ds __user *up64;
2441da177e4SLinus Torvalds 	int version = compat_ipc_parse_version(&third);
2451da177e4SLinus Torvalds 
246*0d5e7580SMark Rustad 	memset(&sem64, 0, sizeof(sem64));
24703145bebSDan Rosenberg 
2481da177e4SLinus Torvalds 	if ((third & (~IPC_64)) == SETVAL)
249e1fd1f49SAl Viro #ifdef __BIG_ENDIAN
250e1fd1f49SAl Viro 		fourth = (unsigned long)pad << 32;
251e1fd1f49SAl Viro #else
252e1fd1f49SAl Viro 		fourth = pad;
253e1fd1f49SAl Viro #endif
2541da177e4SLinus Torvalds 	else
255e1fd1f49SAl Viro 		fourth = (unsigned long)compat_ptr(pad);
2561da177e4SLinus Torvalds 	switch (third & (~IPC_64)) {
2571da177e4SLinus Torvalds 	case IPC_INFO:
2581da177e4SLinus Torvalds 	case IPC_RMID:
2591da177e4SLinus Torvalds 	case SEM_INFO:
2601da177e4SLinus Torvalds 	case GETVAL:
2611da177e4SLinus Torvalds 	case GETPID:
2621da177e4SLinus Torvalds 	case GETNCNT:
2631da177e4SLinus Torvalds 	case GETZCNT:
2641da177e4SLinus Torvalds 	case GETALL:
2651da177e4SLinus Torvalds 	case SETVAL:
2661da177e4SLinus Torvalds 	case SETALL:
2671da177e4SLinus Torvalds 		err = sys_semctl(first, second, third, fourth);
2681da177e4SLinus Torvalds 		break;
2691da177e4SLinus Torvalds 
2701da177e4SLinus Torvalds 	case IPC_STAT:
2711da177e4SLinus Torvalds 	case SEM_STAT:
272*0d5e7580SMark Rustad 		up64 = compat_alloc_user_space(sizeof(sem64));
273e1fd1f49SAl Viro 		fourth = (unsigned long)up64;
2741da177e4SLinus Torvalds 		err = sys_semctl(first, second, third, fourth);
2751da177e4SLinus Torvalds 		if (err < 0)
2761da177e4SLinus Torvalds 			break;
277*0d5e7580SMark Rustad 		if (copy_from_user(&sem64, up64, sizeof(sem64)))
2781da177e4SLinus Torvalds 			err2 = -EFAULT;
2791da177e4SLinus Torvalds 		else if (version == IPC_64)
280*0d5e7580SMark Rustad 			err2 = put_compat_semid64_ds(&sem64, compat_ptr(pad));
2811da177e4SLinus Torvalds 		else
282*0d5e7580SMark Rustad 			err2 = put_compat_semid_ds(&sem64, compat_ptr(pad));
2831da177e4SLinus Torvalds 		if (err2)
2841da177e4SLinus Torvalds 			err = -EFAULT;
2851da177e4SLinus Torvalds 		break;
2861da177e4SLinus Torvalds 
2871da177e4SLinus Torvalds 	case IPC_SET:
2883ab08fe2SDavidlohr Bueso 		if (version == IPC_64)
289*0d5e7580SMark Rustad 			err = get_compat_semid64_ds(&sem64, compat_ptr(pad));
2903ab08fe2SDavidlohr Bueso 		else
291*0d5e7580SMark Rustad 			err = get_compat_semid_ds(&sem64, compat_ptr(pad));
2923ab08fe2SDavidlohr Bueso 
293*0d5e7580SMark Rustad 		up64 = compat_alloc_user_space(sizeof(sem64));
294*0d5e7580SMark Rustad 		if (copy_to_user(up64, &sem64, sizeof(sem64)))
2951da177e4SLinus Torvalds 			err = -EFAULT;
2961da177e4SLinus Torvalds 		if (err)
2971da177e4SLinus Torvalds 			break;
2981da177e4SLinus Torvalds 
299e1fd1f49SAl Viro 		fourth = (unsigned long)up64;
3001da177e4SLinus Torvalds 		err = sys_semctl(first, second, third, fourth);
3011da177e4SLinus Torvalds 		break;
3021da177e4SLinus Torvalds 
3031da177e4SLinus Torvalds 	default:
3041da177e4SLinus Torvalds 		err = -EINVAL;
3051da177e4SLinus Torvalds 		break;
3061da177e4SLinus Torvalds 	}
3071da177e4SLinus Torvalds 	return err;
3081da177e4SLinus Torvalds }
3091da177e4SLinus Torvalds 
3100e65a81bSAl Viro static long compat_do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz)
311f9dd87f4SStanislav Kinsbursky {
312f9dd87f4SStanislav Kinsbursky 	struct compat_msgbuf __user *msgp = dest;
313f9dd87f4SStanislav Kinsbursky 	size_t msgsz;
314f9dd87f4SStanislav Kinsbursky 
315f9dd87f4SStanislav Kinsbursky 	if (put_user(msg->m_type, &msgp->mtype))
316f9dd87f4SStanislav Kinsbursky 		return -EFAULT;
317f9dd87f4SStanislav Kinsbursky 
318f9dd87f4SStanislav Kinsbursky 	msgsz = (bufsz > msg->m_ts) ? msg->m_ts : bufsz;
319f9dd87f4SStanislav Kinsbursky 	if (store_msg(msgp->mtext, msg, msgsz))
320f9dd87f4SStanislav Kinsbursky 		return -EFAULT;
321f9dd87f4SStanislav Kinsbursky 	return msgsz;
322f9dd87f4SStanislav Kinsbursky }
323f9dd87f4SStanislav Kinsbursky 
3240e65a81bSAl Viro #ifndef COMPAT_SHMLBA
3250e65a81bSAl Viro #define COMPAT_SHMLBA	SHMLBA
3260e65a81bSAl Viro #endif
3270e65a81bSAl Viro 
32848b25c43SChris Metcalf #ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC
32956e41d3cSAl Viro COMPAT_SYSCALL_DEFINE6(ipc, u32, call, int, first, int, second,
33056e41d3cSAl Viro 	u32, third, compat_uptr_t, ptr, u32, fifth)
33156e41d3cSAl Viro {
33256e41d3cSAl Viro 	int version;
3330e65a81bSAl Viro 	u32 pad;
33456e41d3cSAl Viro 
33556e41d3cSAl Viro 	version = call >> 16; /* hack for backward compatibility */
33656e41d3cSAl Viro 	call &= 0xffff;
33756e41d3cSAl Viro 
33856e41d3cSAl Viro 	switch (call) {
33956e41d3cSAl Viro 	case SEMOP:
34056e41d3cSAl Viro 		/* struct sembuf is the same on 32 and 64bit :)) */
34156e41d3cSAl Viro 		return sys_semtimedop(first, compat_ptr(ptr), second, NULL);
34256e41d3cSAl Viro 	case SEMTIMEDOP:
34356e41d3cSAl Viro 		return compat_sys_semtimedop(first, compat_ptr(ptr), second,
34456e41d3cSAl Viro 						compat_ptr(fifth));
34556e41d3cSAl Viro 	case SEMGET:
34656e41d3cSAl Viro 		return sys_semget(first, second, third);
34756e41d3cSAl Viro 	case SEMCTL:
3480e65a81bSAl Viro 		if (!ptr)
3490e65a81bSAl Viro 			return -EINVAL;
3500e65a81bSAl Viro 		if (get_user(pad, (u32 __user *) compat_ptr(ptr)))
3510e65a81bSAl Viro 			return -EFAULT;
3520e65a81bSAl Viro 		return do_compat_semctl(first, second, third, pad);
35356e41d3cSAl Viro 
3540e65a81bSAl Viro 	case MSGSND: {
3550e65a81bSAl Viro 		struct compat_msgbuf __user *up = compat_ptr(ptr);
3560e65a81bSAl Viro 		compat_long_t type;
3570e65a81bSAl Viro 
3580e65a81bSAl Viro 		if (first < 0 || second < 0)
3590e65a81bSAl Viro 			return -EINVAL;
3600e65a81bSAl Viro 
3610e65a81bSAl Viro 		if (get_user(type, &up->mtype))
3620e65a81bSAl Viro 			return -EFAULT;
3630e65a81bSAl Viro 
3640e65a81bSAl Viro 		return do_msgsnd(first, type, up->mtext, second, third);
3650e65a81bSAl Viro 	}
3660e65a81bSAl Viro 	case MSGRCV: {
3670e65a81bSAl Viro 		void __user *uptr = compat_ptr(ptr);
3680e65a81bSAl Viro 
3690e65a81bSAl Viro 		if (first < 0 || second < 0)
3700e65a81bSAl Viro 			return -EINVAL;
3710e65a81bSAl Viro 
3720e65a81bSAl Viro 		if (!version) {
3730e65a81bSAl Viro 			struct compat_ipc_kludge ipck;
3740e65a81bSAl Viro 			if (!uptr)
3750e65a81bSAl Viro 				return -EINVAL;
3760e65a81bSAl Viro 			if (copy_from_user(&ipck, uptr, sizeof(ipck)))
3770e65a81bSAl Viro 				return -EFAULT;
3780e65a81bSAl Viro 			uptr = compat_ptr(ipck.msgp);
3790e65a81bSAl Viro 			fifth = ipck.msgtyp;
3800e65a81bSAl Viro 		}
381e7ca2552SMateusz Guzik 		return do_msgrcv(first, uptr, second, (s32)fifth, third,
3820e65a81bSAl Viro 				 compat_do_msg_fill);
3830e65a81bSAl Viro 	}
38456e41d3cSAl Viro 	case MSGGET:
38556e41d3cSAl Viro 		return sys_msgget(first, second);
38656e41d3cSAl Viro 	case MSGCTL:
38756e41d3cSAl Viro 		return compat_sys_msgctl(first, second, compat_ptr(ptr));
38856e41d3cSAl Viro 
3890e65a81bSAl Viro 	case SHMAT: {
3900e65a81bSAl Viro 		int err;
3910e65a81bSAl Viro 		unsigned long raddr;
3920e65a81bSAl Viro 
3930e65a81bSAl Viro 		if (version == 1)
3940e65a81bSAl Viro 			return -EINVAL;
3950e65a81bSAl Viro 		err = do_shmat(first, compat_ptr(ptr), second, &raddr,
3960e65a81bSAl Viro 			       COMPAT_SHMLBA);
3970e65a81bSAl Viro 		if (err < 0)
3980e65a81bSAl Viro 			return err;
3990e65a81bSAl Viro 		return put_user(raddr, (compat_ulong_t *)compat_ptr(third));
4000e65a81bSAl Viro 	}
40156e41d3cSAl Viro 	case SHMDT:
40256e41d3cSAl Viro 		return sys_shmdt(compat_ptr(ptr));
40356e41d3cSAl Viro 	case SHMGET:
40456e41d3cSAl Viro 		return sys_shmget(first, (unsigned)second, third);
40556e41d3cSAl Viro 	case SHMCTL:
40656e41d3cSAl Viro 		return compat_sys_shmctl(first, second, compat_ptr(ptr));
40756e41d3cSAl Viro 	}
40856e41d3cSAl Viro 
40956e41d3cSAl Viro 	return -ENOSYS;
41056e41d3cSAl Viro }
4110e65a81bSAl Viro #endif
4120e65a81bSAl Viro 
4130e65a81bSAl Viro COMPAT_SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, int, arg)
41448b25c43SChris Metcalf {
41548b25c43SChris Metcalf 	return do_compat_semctl(semid, semnum, cmd, arg);
41648b25c43SChris Metcalf }
41748b25c43SChris Metcalf 
4180e65a81bSAl Viro COMPAT_SYSCALL_DEFINE4(msgsnd, int, msqid, compat_uptr_t, msgp,
4190e65a81bSAl Viro 		       compat_ssize_t, msgsz, int, msgflg)
42048b25c43SChris Metcalf {
4210e65a81bSAl Viro 	struct compat_msgbuf __user *up = compat_ptr(msgp);
42248b25c43SChris Metcalf 	compat_long_t mtype;
42348b25c43SChris Metcalf 
4240e65a81bSAl Viro 	if (get_user(mtype, &up->mtype))
42548b25c43SChris Metcalf 		return -EFAULT;
4260e65a81bSAl Viro 	return do_msgsnd(msqid, mtype, up->mtext, (ssize_t)msgsz, msgflg);
42748b25c43SChris Metcalf }
42848b25c43SChris Metcalf 
4290e65a81bSAl Viro COMPAT_SYSCALL_DEFINE5(msgrcv, int, msqid, compat_uptr_t, msgp,
430291fdb0bSHeiko Carstens 		       compat_ssize_t, msgsz, compat_long_t, msgtyp, int, msgflg)
43148b25c43SChris Metcalf {
432291fdb0bSHeiko Carstens 	return do_msgrcv(msqid, compat_ptr(msgp), (ssize_t)msgsz, (long)msgtyp,
4330e65a81bSAl Viro 			 msgflg, compat_do_msg_fill);
43448b25c43SChris Metcalf }
4351da177e4SLinus Torvalds 
4361da177e4SLinus Torvalds static inline int get_compat_msqid64(struct msqid64_ds *m64,
4371da177e4SLinus Torvalds 				     struct compat_msqid64_ds __user *up64)
4381da177e4SLinus Torvalds {
4391da177e4SLinus Torvalds 	int err;
4401da177e4SLinus Torvalds 
4411da177e4SLinus Torvalds 	if (!access_ok(VERIFY_READ, up64, sizeof(*up64)))
4421da177e4SLinus Torvalds 		return -EFAULT;
4431da177e4SLinus Torvalds 	err  = __get_compat_ipc64_perm(&m64->msg_perm, &up64->msg_perm);
4441da177e4SLinus Torvalds 	err |= __get_user(m64->msg_qbytes, &up64->msg_qbytes);
4451da177e4SLinus Torvalds 	return err;
4461da177e4SLinus Torvalds }
4471da177e4SLinus Torvalds 
4481da177e4SLinus Torvalds static inline int get_compat_msqid(struct msqid64_ds *m,
4491da177e4SLinus Torvalds 				   struct compat_msqid_ds __user *up)
4501da177e4SLinus Torvalds {
4511da177e4SLinus Torvalds 	int err;
4521da177e4SLinus Torvalds 
4531da177e4SLinus Torvalds 	if (!access_ok(VERIFY_READ, up, sizeof(*up)))
4541da177e4SLinus Torvalds 		return -EFAULT;
4551da177e4SLinus Torvalds 	err  = __get_compat_ipc_perm(&m->msg_perm, &up->msg_perm);
4561da177e4SLinus Torvalds 	err |= __get_user(m->msg_qbytes, &up->msg_qbytes);
4571da177e4SLinus Torvalds 	return err;
4581da177e4SLinus Torvalds }
4591da177e4SLinus Torvalds 
4601da177e4SLinus Torvalds static inline int put_compat_msqid64_ds(struct msqid64_ds *m64,
4611da177e4SLinus Torvalds 				 struct compat_msqid64_ds __user *up64)
4621da177e4SLinus Torvalds {
4631da177e4SLinus Torvalds 	int err;
4641da177e4SLinus Torvalds 
4651da177e4SLinus Torvalds 	if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
4661da177e4SLinus Torvalds 		return -EFAULT;
4671da177e4SLinus Torvalds 	err  = __put_compat_ipc64_perm(&m64->msg_perm, &up64->msg_perm);
4681da177e4SLinus Torvalds 	err |= __put_user(m64->msg_stime, &up64->msg_stime);
4691da177e4SLinus Torvalds 	err |= __put_user(m64->msg_rtime, &up64->msg_rtime);
4701da177e4SLinus Torvalds 	err |= __put_user(m64->msg_ctime, &up64->msg_ctime);
4711da177e4SLinus Torvalds 	err |= __put_user(m64->msg_cbytes, &up64->msg_cbytes);
4721da177e4SLinus Torvalds 	err |= __put_user(m64->msg_qnum, &up64->msg_qnum);
4731da177e4SLinus Torvalds 	err |= __put_user(m64->msg_qbytes, &up64->msg_qbytes);
4741da177e4SLinus Torvalds 	err |= __put_user(m64->msg_lspid, &up64->msg_lspid);
4751da177e4SLinus Torvalds 	err |= __put_user(m64->msg_lrpid, &up64->msg_lrpid);
4761da177e4SLinus Torvalds 	return err;
4771da177e4SLinus Torvalds }
4781da177e4SLinus Torvalds 
4791da177e4SLinus Torvalds static inline int put_compat_msqid_ds(struct msqid64_ds *m,
4801da177e4SLinus Torvalds 				      struct compat_msqid_ds __user *up)
4811da177e4SLinus Torvalds {
4821da177e4SLinus Torvalds 	int err;
4831da177e4SLinus Torvalds 
4841da177e4SLinus Torvalds 	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
4851da177e4SLinus Torvalds 		return -EFAULT;
4861da177e4SLinus Torvalds 	err  = __put_compat_ipc_perm(&m->msg_perm, &up->msg_perm);
4871da177e4SLinus Torvalds 	err |= __put_user(m->msg_stime, &up->msg_stime);
4881da177e4SLinus Torvalds 	err |= __put_user(m->msg_rtime, &up->msg_rtime);
4891da177e4SLinus Torvalds 	err |= __put_user(m->msg_ctime, &up->msg_ctime);
4901da177e4SLinus Torvalds 	err |= __put_user(m->msg_cbytes, &up->msg_cbytes);
4911da177e4SLinus Torvalds 	err |= __put_user(m->msg_qnum, &up->msg_qnum);
4921da177e4SLinus Torvalds 	err |= __put_user(m->msg_qbytes, &up->msg_qbytes);
4931da177e4SLinus Torvalds 	err |= __put_user(m->msg_lspid, &up->msg_lspid);
4941da177e4SLinus Torvalds 	err |= __put_user(m->msg_lrpid, &up->msg_lrpid);
4951da177e4SLinus Torvalds 	return err;
4961da177e4SLinus Torvalds }
4971da177e4SLinus Torvalds 
4985d70a596SHeiko Carstens COMPAT_SYSCALL_DEFINE3(msgctl, int, first, int, second, void __user *, uptr)
4991da177e4SLinus Torvalds {
5001da177e4SLinus Torvalds 	int err, err2;
5011da177e4SLinus Torvalds 	struct msqid64_ds m64;
5021da177e4SLinus Torvalds 	int version = compat_ipc_parse_version(&second);
5031da177e4SLinus Torvalds 	void __user *p;
5041da177e4SLinus Torvalds 
50503145bebSDan Rosenberg 	memset(&m64, 0, sizeof(m64));
50603145bebSDan Rosenberg 
5071da177e4SLinus Torvalds 	switch (second & (~IPC_64)) {
5081da177e4SLinus Torvalds 	case IPC_INFO:
5091da177e4SLinus Torvalds 	case IPC_RMID:
5101da177e4SLinus Torvalds 	case MSG_INFO:
5111da177e4SLinus Torvalds 		err = sys_msgctl(first, second, uptr);
5121da177e4SLinus Torvalds 		break;
5131da177e4SLinus Torvalds 
5141da177e4SLinus Torvalds 	case IPC_SET:
5153ab08fe2SDavidlohr Bueso 		if (version == IPC_64)
5161da177e4SLinus Torvalds 			err = get_compat_msqid64(&m64, uptr);
5173ab08fe2SDavidlohr Bueso 		else
5181da177e4SLinus Torvalds 			err = get_compat_msqid(&m64, uptr);
5193ab08fe2SDavidlohr Bueso 
5201da177e4SLinus Torvalds 		if (err)
5211da177e4SLinus Torvalds 			break;
5221da177e4SLinus Torvalds 		p = compat_alloc_user_space(sizeof(m64));
5231da177e4SLinus Torvalds 		if (copy_to_user(p, &m64, sizeof(m64)))
5241da177e4SLinus Torvalds 			err = -EFAULT;
5251da177e4SLinus Torvalds 		else
5261da177e4SLinus Torvalds 			err = sys_msgctl(first, second, p);
5271da177e4SLinus Torvalds 		break;
5281da177e4SLinus Torvalds 
5291da177e4SLinus Torvalds 	case IPC_STAT:
5301da177e4SLinus Torvalds 	case MSG_STAT:
5311da177e4SLinus Torvalds 		p = compat_alloc_user_space(sizeof(m64));
5321da177e4SLinus Torvalds 		err = sys_msgctl(first, second, p);
5331da177e4SLinus Torvalds 		if (err < 0)
5341da177e4SLinus Torvalds 			break;
5351da177e4SLinus Torvalds 		if (copy_from_user(&m64, p, sizeof(m64)))
5361da177e4SLinus Torvalds 			err2 = -EFAULT;
5371da177e4SLinus Torvalds 		else if (version == IPC_64)
5381da177e4SLinus Torvalds 			err2 = put_compat_msqid64_ds(&m64, uptr);
5391da177e4SLinus Torvalds 		else
5401da177e4SLinus Torvalds 			err2 = put_compat_msqid_ds(&m64, uptr);
5411da177e4SLinus Torvalds 		if (err2)
5421da177e4SLinus Torvalds 			err = -EFAULT;
5431da177e4SLinus Torvalds 		break;
5441da177e4SLinus Torvalds 
5451da177e4SLinus Torvalds 	default:
5461da177e4SLinus Torvalds 		err = -EINVAL;
5471da177e4SLinus Torvalds 		break;
5481da177e4SLinus Torvalds 	}
5491da177e4SLinus Torvalds 	return err;
5501da177e4SLinus Torvalds }
5511da177e4SLinus Torvalds 
5520e65a81bSAl Viro COMPAT_SYSCALL_DEFINE3(shmat, int, shmid, compat_uptr_t, shmaddr, int, shmflg)
55348b25c43SChris Metcalf {
55448b25c43SChris Metcalf 	unsigned long ret;
55548b25c43SChris Metcalf 	long err;
55648b25c43SChris Metcalf 
557079a96aeSWill Deacon 	err = do_shmat(shmid, compat_ptr(shmaddr), shmflg, &ret, COMPAT_SHMLBA);
55848b25c43SChris Metcalf 	if (err)
55948b25c43SChris Metcalf 		return err;
56048b25c43SChris Metcalf 	force_successful_syscall_return();
56148b25c43SChris Metcalf 	return (long)ret;
56248b25c43SChris Metcalf }
5631da177e4SLinus Torvalds 
564*0d5e7580SMark Rustad static inline int get_compat_shmid64_ds(struct shmid64_ds *sem64,
5651da177e4SLinus Torvalds 					struct compat_shmid64_ds __user *up64)
5661da177e4SLinus Torvalds {
5671da177e4SLinus Torvalds 	if (!access_ok(VERIFY_READ, up64, sizeof(*up64)))
5681da177e4SLinus Torvalds 		return -EFAULT;
569*0d5e7580SMark Rustad 	return __get_compat_ipc64_perm(&sem64->shm_perm, &up64->shm_perm);
5701da177e4SLinus Torvalds }
5711da177e4SLinus Torvalds 
5721da177e4SLinus Torvalds static inline int get_compat_shmid_ds(struct shmid64_ds *s,
5731da177e4SLinus Torvalds 				      struct compat_shmid_ds __user *up)
5741da177e4SLinus Torvalds {
5751da177e4SLinus Torvalds 	if (!access_ok(VERIFY_READ, up, sizeof(*up)))
5761da177e4SLinus Torvalds 		return -EFAULT;
5771da177e4SLinus Torvalds 	return __get_compat_ipc_perm(&s->shm_perm, &up->shm_perm);
5781da177e4SLinus Torvalds }
5791da177e4SLinus Torvalds 
580*0d5e7580SMark Rustad static inline int put_compat_shmid64_ds(struct shmid64_ds *sem64,
5811da177e4SLinus Torvalds 					struct compat_shmid64_ds __user *up64)
5821da177e4SLinus Torvalds {
5831da177e4SLinus Torvalds 	int err;
5841da177e4SLinus Torvalds 
5851da177e4SLinus Torvalds 	if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
5861da177e4SLinus Torvalds 		return -EFAULT;
587*0d5e7580SMark Rustad 	err  = __put_compat_ipc64_perm(&sem64->shm_perm, &up64->shm_perm);
588*0d5e7580SMark Rustad 	err |= __put_user(sem64->shm_atime, &up64->shm_atime);
589*0d5e7580SMark Rustad 	err |= __put_user(sem64->shm_dtime, &up64->shm_dtime);
590*0d5e7580SMark Rustad 	err |= __put_user(sem64->shm_ctime, &up64->shm_ctime);
591*0d5e7580SMark Rustad 	err |= __put_user(sem64->shm_segsz, &up64->shm_segsz);
592*0d5e7580SMark Rustad 	err |= __put_user(sem64->shm_nattch, &up64->shm_nattch);
593*0d5e7580SMark Rustad 	err |= __put_user(sem64->shm_cpid, &up64->shm_cpid);
594*0d5e7580SMark Rustad 	err |= __put_user(sem64->shm_lpid, &up64->shm_lpid);
5951da177e4SLinus Torvalds 	return err;
5961da177e4SLinus Torvalds }
5971da177e4SLinus Torvalds 
5981da177e4SLinus Torvalds static inline int put_compat_shmid_ds(struct shmid64_ds *s,
5991da177e4SLinus Torvalds 				      struct compat_shmid_ds __user *up)
6001da177e4SLinus Torvalds {
6011da177e4SLinus Torvalds 	int err;
6021da177e4SLinus Torvalds 
6031da177e4SLinus Torvalds 	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
6041da177e4SLinus Torvalds 		return -EFAULT;
6051da177e4SLinus Torvalds 	err  = __put_compat_ipc_perm(&s->shm_perm, &up->shm_perm);
6061da177e4SLinus Torvalds 	err |= __put_user(s->shm_atime, &up->shm_atime);
6071da177e4SLinus Torvalds 	err |= __put_user(s->shm_dtime, &up->shm_dtime);
6081da177e4SLinus Torvalds 	err |= __put_user(s->shm_ctime, &up->shm_ctime);
6091da177e4SLinus Torvalds 	err |= __put_user(s->shm_segsz, &up->shm_segsz);
6101da177e4SLinus Torvalds 	err |= __put_user(s->shm_nattch, &up->shm_nattch);
6111da177e4SLinus Torvalds 	err |= __put_user(s->shm_cpid, &up->shm_cpid);
6121da177e4SLinus Torvalds 	err |= __put_user(s->shm_lpid, &up->shm_lpid);
6131da177e4SLinus Torvalds 	return err;
6141da177e4SLinus Torvalds }
6151da177e4SLinus Torvalds 
6161da177e4SLinus Torvalds static inline int put_compat_shminfo64(struct shminfo64 *smi,
6171da177e4SLinus Torvalds 				       struct compat_shminfo64 __user *up64)
6181da177e4SLinus Torvalds {
6191da177e4SLinus Torvalds 	int err;
6201da177e4SLinus Torvalds 
6211da177e4SLinus Torvalds 	if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
6221da177e4SLinus Torvalds 		return -EFAULT;
623af7c693fSGuy Streeter 	if (smi->shmmax > INT_MAX)
624af7c693fSGuy Streeter 		smi->shmmax = INT_MAX;
6251da177e4SLinus Torvalds 	err  = __put_user(smi->shmmax, &up64->shmmax);
6261da177e4SLinus Torvalds 	err |= __put_user(smi->shmmin, &up64->shmmin);
6271da177e4SLinus Torvalds 	err |= __put_user(smi->shmmni, &up64->shmmni);
6281da177e4SLinus Torvalds 	err |= __put_user(smi->shmseg, &up64->shmseg);
6291da177e4SLinus Torvalds 	err |= __put_user(smi->shmall, &up64->shmall);
6301da177e4SLinus Torvalds 	return err;
6311da177e4SLinus Torvalds }
6321da177e4SLinus Torvalds 
6331da177e4SLinus Torvalds static inline int put_compat_shminfo(struct shminfo64 *smi,
6341da177e4SLinus Torvalds 				     struct shminfo __user *up)
6351da177e4SLinus Torvalds {
6361da177e4SLinus Torvalds 	int err;
6371da177e4SLinus Torvalds 
6381da177e4SLinus Torvalds 	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
6391da177e4SLinus Torvalds 		return -EFAULT;
640af7c693fSGuy Streeter 	if (smi->shmmax > INT_MAX)
641af7c693fSGuy Streeter 		smi->shmmax = INT_MAX;
6421da177e4SLinus Torvalds 	err  = __put_user(smi->shmmax, &up->shmmax);
6431da177e4SLinus Torvalds 	err |= __put_user(smi->shmmin, &up->shmmin);
6441da177e4SLinus Torvalds 	err |= __put_user(smi->shmmni, &up->shmmni);
6451da177e4SLinus Torvalds 	err |= __put_user(smi->shmseg, &up->shmseg);
6461da177e4SLinus Torvalds 	err |= __put_user(smi->shmall, &up->shmall);
647214a627cSJesse Millan 	return err;
6481da177e4SLinus Torvalds }
6491da177e4SLinus Torvalds 
6501da177e4SLinus Torvalds static inline int put_compat_shm_info(struct shm_info __user *ip,
6511da177e4SLinus Torvalds 				      struct compat_shm_info __user *uip)
6521da177e4SLinus Torvalds {
6531da177e4SLinus Torvalds 	int err;
6541da177e4SLinus Torvalds 	struct shm_info si;
6551da177e4SLinus Torvalds 
6561da177e4SLinus Torvalds 	if (!access_ok(VERIFY_WRITE, uip, sizeof(*uip)) ||
6571da177e4SLinus Torvalds 	    copy_from_user(&si, ip, sizeof(si)))
6581da177e4SLinus Torvalds 		return -EFAULT;
6591da177e4SLinus Torvalds 	err  = __put_user(si.used_ids, &uip->used_ids);
6601da177e4SLinus Torvalds 	err |= __put_user(si.shm_tot, &uip->shm_tot);
6611da177e4SLinus Torvalds 	err |= __put_user(si.shm_rss, &uip->shm_rss);
6621da177e4SLinus Torvalds 	err |= __put_user(si.shm_swp, &uip->shm_swp);
6631da177e4SLinus Torvalds 	err |= __put_user(si.swap_attempts, &uip->swap_attempts);
6641da177e4SLinus Torvalds 	err |= __put_user(si.swap_successes, &uip->swap_successes);
6651da177e4SLinus Torvalds 	return err;
6661da177e4SLinus Torvalds }
6671da177e4SLinus Torvalds 
6685d70a596SHeiko Carstens COMPAT_SYSCALL_DEFINE3(shmctl, int, first, int, second, void __user *, uptr)
6691da177e4SLinus Torvalds {
6701da177e4SLinus Torvalds 	void __user *p;
671*0d5e7580SMark Rustad 	struct shmid64_ds sem64;
6721da177e4SLinus Torvalds 	struct shminfo64 smi;
6731da177e4SLinus Torvalds 	int err, err2;
6741da177e4SLinus Torvalds 	int version = compat_ipc_parse_version(&second);
6751da177e4SLinus Torvalds 
676*0d5e7580SMark Rustad 	memset(&sem64, 0, sizeof(sem64));
67703145bebSDan Rosenberg 
6781da177e4SLinus Torvalds 	switch (second & (~IPC_64)) {
6791da177e4SLinus Torvalds 	case IPC_RMID:
6801da177e4SLinus Torvalds 	case SHM_LOCK:
6811da177e4SLinus Torvalds 	case SHM_UNLOCK:
6821da177e4SLinus Torvalds 		err = sys_shmctl(first, second, uptr);
6831da177e4SLinus Torvalds 		break;
6841da177e4SLinus Torvalds 
6851da177e4SLinus Torvalds 	case IPC_INFO:
6861da177e4SLinus Torvalds 		p = compat_alloc_user_space(sizeof(smi));
6871da177e4SLinus Torvalds 		err = sys_shmctl(first, second, p);
6881da177e4SLinus Torvalds 		if (err < 0)
6891da177e4SLinus Torvalds 			break;
6901da177e4SLinus Torvalds 		if (copy_from_user(&smi, p, sizeof(smi)))
6911da177e4SLinus Torvalds 			err2 = -EFAULT;
6921da177e4SLinus Torvalds 		else if (version == IPC_64)
6931da177e4SLinus Torvalds 			err2 = put_compat_shminfo64(&smi, uptr);
6941da177e4SLinus Torvalds 		else
6951da177e4SLinus Torvalds 			err2 = put_compat_shminfo(&smi, uptr);
6961da177e4SLinus Torvalds 		if (err2)
6971da177e4SLinus Torvalds 			err = -EFAULT;
6981da177e4SLinus Torvalds 		break;
6991da177e4SLinus Torvalds 
7001da177e4SLinus Torvalds 
7011da177e4SLinus Torvalds 	case IPC_SET:
7023ab08fe2SDavidlohr Bueso 		if (version == IPC_64)
703*0d5e7580SMark Rustad 			err = get_compat_shmid64_ds(&sem64, uptr);
7043ab08fe2SDavidlohr Bueso 		else
705*0d5e7580SMark Rustad 			err = get_compat_shmid_ds(&sem64, uptr);
7063ab08fe2SDavidlohr Bueso 
7071da177e4SLinus Torvalds 		if (err)
7081da177e4SLinus Torvalds 			break;
709*0d5e7580SMark Rustad 		p = compat_alloc_user_space(sizeof(sem64));
710*0d5e7580SMark Rustad 		if (copy_to_user(p, &sem64, sizeof(sem64)))
7111da177e4SLinus Torvalds 			err = -EFAULT;
7121da177e4SLinus Torvalds 		else
7131da177e4SLinus Torvalds 			err = sys_shmctl(first, second, p);
7141da177e4SLinus Torvalds 		break;
7151da177e4SLinus Torvalds 
7161da177e4SLinus Torvalds 	case IPC_STAT:
7171da177e4SLinus Torvalds 	case SHM_STAT:
718*0d5e7580SMark Rustad 		p = compat_alloc_user_space(sizeof(sem64));
7191da177e4SLinus Torvalds 		err = sys_shmctl(first, second, p);
7201da177e4SLinus Torvalds 		if (err < 0)
7211da177e4SLinus Torvalds 			break;
722*0d5e7580SMark Rustad 		if (copy_from_user(&sem64, p, sizeof(sem64)))
7231da177e4SLinus Torvalds 			err2 = -EFAULT;
7241da177e4SLinus Torvalds 		else if (version == IPC_64)
725*0d5e7580SMark Rustad 			err2 = put_compat_shmid64_ds(&sem64, uptr);
7261da177e4SLinus Torvalds 		else
727*0d5e7580SMark Rustad 			err2 = put_compat_shmid_ds(&sem64, uptr);
7281da177e4SLinus Torvalds 		if (err2)
7291da177e4SLinus Torvalds 			err = -EFAULT;
7301da177e4SLinus Torvalds 		break;
7311da177e4SLinus Torvalds 
7321da177e4SLinus Torvalds 	case SHM_INFO:
7331da177e4SLinus Torvalds 		p = compat_alloc_user_space(sizeof(struct shm_info));
7341da177e4SLinus Torvalds 		err = sys_shmctl(first, second, p);
7351da177e4SLinus Torvalds 		if (err < 0)
7361da177e4SLinus Torvalds 			break;
7371da177e4SLinus Torvalds 		err2 = put_compat_shm_info(p, uptr);
7381da177e4SLinus Torvalds 		if (err2)
7391da177e4SLinus Torvalds 			err = -EFAULT;
7401da177e4SLinus Torvalds 		break;
7411da177e4SLinus Torvalds 
7421da177e4SLinus Torvalds 	default:
7431da177e4SLinus Torvalds 		err = -EINVAL;
7441da177e4SLinus Torvalds 		break;
7451da177e4SLinus Torvalds 	}
7461da177e4SLinus Torvalds 	return err;
7471da177e4SLinus Torvalds }
7481da177e4SLinus Torvalds 
7495d70a596SHeiko Carstens COMPAT_SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsems,
7505d70a596SHeiko Carstens 		       unsigned, nsops,
7515d70a596SHeiko Carstens 		       const struct compat_timespec __user *, timeout)
7521da177e4SLinus Torvalds {
75381993e81SH. Peter Anvin 	struct timespec __user *ts64;
75481993e81SH. Peter Anvin 	if (compat_convert_timespec(&ts64, timeout))
7551da177e4SLinus Torvalds 		return -EFAULT;
7561da177e4SLinus Torvalds 	return sys_semtimedop(semid, tsems, nsops, ts64);
7571da177e4SLinus Torvalds }
758