syscall.c 4.73 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0
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>
Al Viro's avatar
Al Viro committed
9
#include <linux/syscalls.h>
10 11 12
#include <linux/security.h>
#include <linux/ipc_namespace.h>
#include "util.h"
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,
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);
32
	case SEMTIMEDOP:
33 34 35 36 37
		if (IS_ENABLED(CONFIG_64BIT) || !IS_ENABLED(CONFIG_64BIT_TIME))
			return ksys_semtimedop(first, ptr, second,
			        (const struct __kernel_timespec __user *)fifth);
		else if (IS_ENABLED(CONFIG_COMPAT_32BIT_TIME))
			return compat_ksys_semtimedop(first, ptr, second,
38
			        (const struct old_timespec32 __user *)fifth);
39 40
		else
			return -ENOSYS;
41 42

	case SEMGET:
43
		return ksys_semget(first, second, third);
44
	case SEMCTL: {
45
		unsigned long arg;
46 47
		if (!ptr)
			return -EINVAL;
48
		if (get_user(arg, (unsigned long __user *) ptr))
49
			return -EFAULT;
50
		return ksys_semctl(first, second, third, arg);
51 52 53
	}

	case MSGSND:
54
		return ksys_msgsnd(first, (struct msgbuf __user *) ptr,
55 56 57 58 59 60 61 62 63 64 65 66
				  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;
67
			return ksys_msgrcv(first, tmp.msgp, second,
68 69 70
					   tmp.msgtyp, third);
		}
		default:
71
			return ksys_msgrcv(first,
72 73 74 75
					   (struct msgbuf __user *) ptr,
					   second, fifth, third);
		}
	case MSGGET:
76
		return ksys_msgget((key_t) first, second);
77
	case MSGCTL:
78 79
		return ksys_msgctl(first, second,
				   (struct msqid_ds __user *)ptr);
80 81 82 83 84 85

	case SHMAT:
		switch (version) {
		default: {
			unsigned long raddr;
			ret = do_shmat(first, (char __user *)ptr,
86
				       second, &raddr, SHMLBA);
87 88 89 90 91 92 93 94 95 96 97 98
			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:
99
		return ksys_shmdt((char __user *)ptr);
100
	case SHMGET:
101
		return ksys_shmget(first, second, third);
102
	case SHMCTL:
103
		return ksys_shmctl(first, second,
104 105 106 107 108 109
				   (struct shmid_ds __user *) ptr);
	default:
		return -ENOSYS;
	}
}
#endif
Al Viro's avatar
Al Viro committed
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135

#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 :)) */
136
		return ksys_semtimedop(first, compat_ptr(ptr), second, NULL);
Al Viro's avatar
Al Viro committed
137
	case SEMTIMEDOP:
138 139
		if (!IS_ENABLED(CONFIG_COMPAT_32BIT_TIME))
			return -ENOSYS;
140
		return compat_ksys_semtimedop(first, compat_ptr(ptr), second,
Al Viro's avatar
Al Viro committed
141 142
						compat_ptr(fifth));
	case SEMGET:
143
		return ksys_semget(first, second, third);
Al Viro's avatar
Al Viro committed
144 145 146 147 148
	case SEMCTL:
		if (!ptr)
			return -EINVAL;
		if (get_user(pad, (u32 __user *) compat_ptr(ptr)))
			return -EFAULT;
149
		return compat_ksys_semctl(first, second, third, pad);
Al Viro's avatar
Al Viro committed
150 151

	case MSGSND:
152
		return compat_ksys_msgsnd(first, ptr, second, third);
Al Viro's avatar
Al Viro committed
153 154 155 156 157 158 159 160 161 162 163 164 165

	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;
166
			return compat_ksys_msgrcv(first, ipck.msgp, second,
Al Viro's avatar
Al Viro committed
167 168
						 ipck.msgtyp, third);
		}
169
		return compat_ksys_msgrcv(first, ptr, second, fifth, third);
Al Viro's avatar
Al Viro committed
170 171
	}
	case MSGGET:
172
		return ksys_msgget(first, second);
Al Viro's avatar
Al Viro committed
173
	case MSGCTL:
174
		return compat_ksys_msgctl(first, second, compat_ptr(ptr));
Al Viro's avatar
Al Viro committed
175 176 177 178 179 180 181 182 183 184 185

	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;
186
		return put_user(raddr, (compat_ulong_t __user *)compat_ptr(third));
Al Viro's avatar
Al Viro committed
187 188
	}
	case SHMDT:
189
		return ksys_shmdt(compat_ptr(ptr));
Al Viro's avatar
Al Viro committed
190
	case SHMGET:
191
		return ksys_shmget(first, (unsigned int)second, third);
Al Viro's avatar
Al Viro committed
192
	case SHMCTL:
193
		return compat_ksys_shmctl(first, second, compat_ptr(ptr));
Al Viro's avatar
Al Viro committed
194 195 196 197 198 199
	}

	return -ENOSYS;
}
#endif
#endif