syscall.c 4.4 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0
C
Christoph Hellwig 已提交
2 3 4 5 6 7 8
/*
 * sys_ipc() is the old de-multiplexer for the SysV IPC calls.
 *
 * This is really horribly ugly, and new architectures should just wire up
 * the individual syscalls instead.
 */
#include <linux/unistd.h>
A
Al Viro 已提交
9
#include <linux/syscalls.h>
10 11 12
#include <linux/security.h>
#include <linux/ipc_namespace.h>
#include "util.h"
C
Christoph Hellwig 已提交
13 14 15 16 17 18 19

#ifdef __ARCH_WANT_SYS_IPC
#include <linux/errno.h>
#include <linux/ipc.h>
#include <linux/shm.h>
#include <linux/uaccess.h>

20
SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, unsigned long, second,
C
Christoph Hellwig 已提交
21 22 23 24 25 26 27 28 29
		unsigned long, third, void __user *, ptr, long, fifth)
{
	int version, ret;

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

	switch (call) {
	case SEMOP:
30 31
		return ksys_semtimedop(first, (struct sembuf __user *)ptr,
				       second, NULL);
C
Christoph Hellwig 已提交
32
	case SEMTIMEDOP:
33 34 35
		return ksys_semtimedop(first, (struct sembuf __user *)ptr,
				       second,
				       (const struct timespec __user *)fifth);
C
Christoph Hellwig 已提交
36 37

	case SEMGET:
38
		return ksys_semget(first, second, third);
C
Christoph Hellwig 已提交
39
	case SEMCTL: {
40
		unsigned long arg;
C
Christoph Hellwig 已提交
41 42
		if (!ptr)
			return -EINVAL;
43
		if (get_user(arg, (unsigned long __user *) ptr))
C
Christoph Hellwig 已提交
44
			return -EFAULT;
45
		return ksys_semctl(first, second, third, arg);
C
Christoph Hellwig 已提交
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
	}

	case MSGSND:
		return sys_msgsnd(first, (struct msgbuf __user *) ptr,
				  second, third);
	case MSGRCV:
		switch (version) {
		case 0: {
			struct ipc_kludge tmp;
			if (!ptr)
				return -EINVAL;

			if (copy_from_user(&tmp,
					   (struct ipc_kludge __user *) ptr,
					   sizeof(tmp)))
				return -EFAULT;
			return sys_msgrcv(first, tmp.msgp, second,
					   tmp.msgtyp, third);
		}
		default:
			return sys_msgrcv(first,
					   (struct msgbuf __user *) ptr,
					   second, fifth, third);
		}
	case MSGGET:
71
		return ksys_msgget((key_t) first, second);
C
Christoph Hellwig 已提交
72
	case MSGCTL:
73 74
		return ksys_msgctl(first, second,
				   (struct msqid_ds __user *)ptr);
C
Christoph Hellwig 已提交
75 76 77 78 79 80

	case SHMAT:
		switch (version) {
		default: {
			unsigned long raddr;
			ret = do_shmat(first, (char __user *)ptr,
W
Will Deacon 已提交
81
				       second, &raddr, SHMLBA);
C
Christoph Hellwig 已提交
82 83 84 85 86 87 88 89 90 91 92 93
			if (ret)
				return ret;
			return put_user(raddr, (unsigned long __user *) third);
		}
		case 1:
			/*
			 * This was the entry point for kernel-originating calls
			 * from iBCS2 in 2.2 days.
			 */
			return -EINVAL;
		}
	case SHMDT:
94
		return ksys_shmdt((char __user *)ptr);
C
Christoph Hellwig 已提交
95
	case SHMGET:
96
		return ksys_shmget(first, second, third);
C
Christoph Hellwig 已提交
97
	case SHMCTL:
98
		return ksys_shmctl(first, second,
C
Christoph Hellwig 已提交
99 100 101 102 103 104
				   (struct shmid_ds __user *) ptr);
	default:
		return -ENOSYS;
	}
}
#endif
A
Al Viro 已提交
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130

#ifdef CONFIG_COMPAT
#include <linux/compat.h>

#ifndef COMPAT_SHMLBA
#define COMPAT_SHMLBA	SHMLBA
#endif

struct compat_ipc_kludge {
	compat_uptr_t msgp;
	compat_long_t msgtyp;
};

#ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC
COMPAT_SYSCALL_DEFINE6(ipc, u32, call, int, first, int, second,
	u32, third, compat_uptr_t, ptr, u32, fifth)
{
	int version;
	u32 pad;

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

	switch (call) {
	case SEMOP:
		/* struct sembuf is the same on 32 and 64bit :)) */
131
		return ksys_semtimedop(first, compat_ptr(ptr), second, NULL);
A
Al Viro 已提交
132
	case SEMTIMEDOP:
133
		return compat_ksys_semtimedop(first, compat_ptr(ptr), second,
A
Al Viro 已提交
134 135
						compat_ptr(fifth));
	case SEMGET:
136
		return ksys_semget(first, second, third);
A
Al Viro 已提交
137 138 139 140 141
	case SEMCTL:
		if (!ptr)
			return -EINVAL;
		if (get_user(pad, (u32 __user *) compat_ptr(ptr)))
			return -EFAULT;
142
		return compat_ksys_semctl(first, second, third, pad);
A
Al Viro 已提交
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164

	case MSGSND:
		return compat_sys_msgsnd(first, ptr, 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;
			if (copy_from_user(&ipck, uptr, sizeof(ipck)))
				return -EFAULT;
			return compat_sys_msgrcv(first, ipck.msgp, second,
						 ipck.msgtyp, third);
		}
		return compat_sys_msgrcv(first, ptr, second, fifth, third);
	}
	case MSGGET:
165
		return ksys_msgget(first, second);
A
Al Viro 已提交
166
	case MSGCTL:
167
		return compat_ksys_msgctl(first, second, compat_ptr(ptr));
A
Al Viro 已提交
168 169 170 171 172 173 174 175 176 177 178

	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;
179
		return put_user(raddr, (compat_ulong_t __user *)compat_ptr(third));
A
Al Viro 已提交
180 181
	}
	case SHMDT:
182
		return ksys_shmdt(compat_ptr(ptr));
A
Al Viro 已提交
183
	case SHMGET:
184
		return ksys_shmget(first, (unsigned int)second, third);
A
Al Viro 已提交
185
	case SHMCTL:
186
		return compat_ksys_shmctl(first, second, compat_ptr(ptr));
A
Al Viro 已提交
187 188 189 190 191 192
	}

	return -ENOSYS;
}
#endif
#endif