compat.c 5.8 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
/*
 * 32 bit compatibility code for System V IPC
 *
 * Copyright (C) 1997,1998	Jakub Jelinek (jj@sunsite.mff.cuni.cz)
 * Copyright (C) 1997		David S. Miller (davem@caip.rutgers.edu)
 * Copyright (C) 1999		Arun Sharma <arun.sharma@intel.com>
 * Copyright (C) 2000		VA Linux Co
 * Copyright (C) 2000		Don Dugger <n0ano@valinux.com>
 * Copyright (C) 2000           Hewlett-Packard Co.
 * Copyright (C) 2000           David Mosberger-Tang <davidm@hpl.hp.com>
 * Copyright (C) 2000           Gerhard Tonn (ton@de.ibm.com)
 * Copyright (C) 2000-2002      Andi Kleen, SuSE Labs (x86-64 port)
 * Copyright (C) 2000		Silicon Graphics, Inc.
 * Copyright (C) 2001		IBM
 * Copyright (C) 2004		IBM Deutschland Entwicklung GmbH, IBM Corporation
 * Copyright (C) 2004		Arnd Bergmann (arnd@arndb.de)
 *
 * This code is collected from the versions for sparc64, mips64, s390x, ia64,
 * ppc64 and x86_64, all of which are based on the original sparc64 version
 * by Jakub Jelinek.
 *
 */
#include <linux/compat.h>
#include <linux/errno.h>
#include <linux/highuid.h>
#include <linux/init.h>
#include <linux/msg.h>
#include <linux/shm.h>
#include <linux/syscalls.h>
30
#include <linux/ptrace.h>
L
Linus Torvalds 已提交
31

I
Ingo Molnar 已提交
32
#include <linux/mutex.h>
P
Paul McQuade 已提交
33
#include <linux/uaccess.h>
L
Linus Torvalds 已提交
34 35 36 37 38 39 40 41 42 43 44 45 46

#include "util.h"

struct compat_msgbuf {
	compat_long_t mtype;
	char mtext[1];
};

struct compat_ipc_kludge {
	compat_uptr_t msgp;
	compat_long_t msgtyp;
};

A
Al Viro 已提交
47 48
int get_compat_ipc64_perm(struct ipc64_perm *to,
			  struct compat_ipc64_perm __user *from)
L
Linus Torvalds 已提交
49
{
A
Al Viro 已提交
50 51
	struct compat_ipc64_perm v;
	if (copy_from_user(&v, from, sizeof(v)))
L
Linus Torvalds 已提交
52
		return -EFAULT;
A
Al Viro 已提交
53 54 55 56
	to->uid = v.uid;
	to->gid = v.gid;
	to->mode = v.mode;
	return 0;
L
Linus Torvalds 已提交
57 58
}

A
Al Viro 已提交
59 60
int get_compat_ipc_perm(struct ipc64_perm *to,
			struct compat_ipc_perm __user *from)
L
Linus Torvalds 已提交
61
{
A
Al Viro 已提交
62 63
	struct compat_ipc_perm v;
	if (copy_from_user(&v, from, sizeof(v)))
L
Linus Torvalds 已提交
64
		return -EFAULT;
A
Al Viro 已提交
65 66 67 68
	to->uid = v.uid;
	to->gid = v.gid;
	to->mode = v.mode;
	return 0;
L
Linus Torvalds 已提交
69 70
}

A
Al Viro 已提交
71
void to_compat_ipc64_perm(struct compat_ipc64_perm *to, struct ipc64_perm *from)
L
Linus Torvalds 已提交
72
{
A
Al Viro 已提交
73 74 75 76 77 78 79
	to->key = from->key;
	to->uid = from->uid;
	to->gid = from->gid;
	to->cuid = from->cuid;
	to->cgid = from->cgid;
	to->mode = from->mode;
	to->seq = from->seq;
L
Linus Torvalds 已提交
80 81
}

A
Al Viro 已提交
82
void to_compat_ipc_perm(struct compat_ipc_perm *to, struct ipc64_perm *from)
L
Linus Torvalds 已提交
83
{
A
Al Viro 已提交
84 85 86 87 88 89 90
	to->key = from->key;
	SET_UID(to->uid, from->uid);
	SET_GID(to->gid, from->gid);
	SET_UID(to->cuid, from->cuid);
	SET_GID(to->cgid, from->cgid);
	to->mode = from->mode;
	to->seq = from->seq;
L
Linus Torvalds 已提交
91 92
}

93
static long compat_do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz)
94 95 96 97 98 99 100 101 102 103 104 105 106
{
	struct compat_msgbuf __user *msgp = dest;
	size_t msgsz;

	if (put_user(msg->m_type, &msgp->mtype))
		return -EFAULT;

	msgsz = (bufsz > msg->m_ts) ? msg->m_ts : bufsz;
	if (store_msg(msgp->mtext, msg, msgsz))
		return -EFAULT;
	return msgsz;
}

107 108 109
#ifndef COMPAT_SHMLBA
#define COMPAT_SHMLBA	SHMLBA
#endif
A
Al Viro 已提交
110

111
#ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC
A
Al Viro 已提交
112 113 114 115
COMPAT_SYSCALL_DEFINE6(ipc, u32, call, int, first, int, second,
	u32, third, compat_uptr_t, ptr, u32, fifth)
{
	int version;
116
	u32 pad;
A
Al Viro 已提交
117 118 119 120 121 122 123 124 125 126 127 128 129 130

	version = call >> 16; /* hack for backward compatibility */
	call &= 0xffff;

	switch (call) {
	case SEMOP:
		/* struct sembuf is the same on 32 and 64bit :)) */
		return sys_semtimedop(first, compat_ptr(ptr), second, NULL);
	case SEMTIMEDOP:
		return compat_sys_semtimedop(first, compat_ptr(ptr), second,
						compat_ptr(fifth));
	case SEMGET:
		return sys_semget(first, second, third);
	case SEMCTL:
131 132 133 134
		if (!ptr)
			return -EINVAL;
		if (get_user(pad, (u32 __user *) compat_ptr(ptr)))
			return -EFAULT;
A
Al Viro 已提交
135
		return compat_sys_semctl(first, second, third, pad);
136 137 138 139 140 141 142

	case MSGSND: {
		struct compat_msgbuf __user *up = compat_ptr(ptr);
		compat_long_t type;

		if (first < 0 || second < 0)
			return -EINVAL;
A
Al Viro 已提交
143

144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
		if (get_user(type, &up->mtype))
			return -EFAULT;

		return do_msgsnd(first, type, up->mtext, second, third);
	}
	case MSGRCV: {
		void __user *uptr = compat_ptr(ptr);

		if (first < 0 || second < 0)
			return -EINVAL;

		if (!version) {
			struct compat_ipc_kludge ipck;
			if (!uptr)
				return -EINVAL;
M
Manfred Spraul 已提交
159
			if (copy_from_user(&ipck, uptr, sizeof(ipck)))
160 161 162 163
				return -EFAULT;
			uptr = compat_ptr(ipck.msgp);
			fifth = ipck.msgtyp;
		}
164
		return do_msgrcv(first, uptr, second, (s32)fifth, third,
165 166
				 compat_do_msg_fill);
	}
A
Al Viro 已提交
167 168 169 170 171
	case MSGGET:
		return sys_msgget(first, second);
	case MSGCTL:
		return compat_sys_msgctl(first, second, compat_ptr(ptr));

172 173 174 175 176 177 178 179 180 181 182 183
	case SHMAT: {
		int err;
		unsigned long raddr;

		if (version == 1)
			return -EINVAL;
		err = do_shmat(first, compat_ptr(ptr), second, &raddr,
			       COMPAT_SHMLBA);
		if (err < 0)
			return err;
		return put_user(raddr, (compat_ulong_t *)compat_ptr(third));
	}
A
Al Viro 已提交
184 185 186 187 188 189 190 191 192 193
	case SHMDT:
		return sys_shmdt(compat_ptr(ptr));
	case SHMGET:
		return sys_shmget(first, (unsigned)second, third);
	case SHMCTL:
		return compat_sys_shmctl(first, second, compat_ptr(ptr));
	}

	return -ENOSYS;
}
194 195 196 197
#endif

COMPAT_SYSCALL_DEFINE4(msgsnd, int, msqid, compat_uptr_t, msgp,
		       compat_ssize_t, msgsz, int, msgflg)
198
{
199
	struct compat_msgbuf __user *up = compat_ptr(msgp);
200 201
	compat_long_t mtype;

202
	if (get_user(mtype, &up->mtype))
203
		return -EFAULT;
204
	return do_msgsnd(msqid, mtype, up->mtext, (ssize_t)msgsz, msgflg);
205 206
}

207
COMPAT_SYSCALL_DEFINE5(msgrcv, int, msqid, compat_uptr_t, msgp,
208
		       compat_ssize_t, msgsz, compat_long_t, msgtyp, int, msgflg)
209
{
210
	return do_msgrcv(msqid, compat_ptr(msgp), (ssize_t)msgsz, (long)msgtyp,
211
			 msgflg, compat_do_msg_fill);
212
}
L
Linus Torvalds 已提交
213

214
COMPAT_SYSCALL_DEFINE3(shmat, int, shmid, compat_uptr_t, shmaddr, int, shmflg)
215 216 217 218
{
	unsigned long ret;
	long err;

W
Will Deacon 已提交
219
	err = do_shmat(shmid, compat_ptr(shmaddr), shmflg, &ret, COMPAT_SHMLBA);
220 221 222 223 224
	if (err)
		return err;
	force_successful_syscall_return();
	return (long)ret;
}
L
Linus Torvalds 已提交
225

226 227 228
COMPAT_SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsems,
		       unsigned, nsops,
		       const struct compat_timespec __user *, timeout)
L
Linus Torvalds 已提交
229
{
230 231 232
	struct timespec __user *ts64;
	if (compat_convert_timespec(&ts64, timeout))
		return -EFAULT;
L
Linus Torvalds 已提交
233 234
	return sys_semtimedop(semid, tsems, nsops, ts64);
}