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 71 72 73 74 75 76 77 78 79
	}

	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:
		return sys_msgget((key_t) first, second);
	case MSGCTL:
		return sys_msgctl(first, second, (struct msqid_ds __user *)ptr);

	case SHMAT:
		switch (version) {
		default: {
			unsigned long raddr;
			ret = do_shmat(first, (char __user *)ptr,
W
Will Deacon 已提交
80
				       second, &raddr, SHMLBA);
C
Christoph Hellwig 已提交
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
			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:
		return sys_shmdt((char __user *)ptr);
	case SHMGET:
		return sys_shmget(first, second, third);
	case SHMCTL:
		return sys_shmctl(first, second,
				   (struct shmid_ds __user *) ptr);
	default:
		return -ENOSYS;
	}
}
#endif
A
Al Viro 已提交
104 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

#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 :)) */
130
		return ksys_semtimedop(first, compat_ptr(ptr), second, NULL);
A
Al Viro 已提交
131
	case SEMTIMEDOP:
132
		return compat_ksys_semtimedop(first, compat_ptr(ptr), second,
A
Al Viro 已提交
133 134
						compat_ptr(fifth));
	case SEMGET:
135
		return ksys_semget(first, second, third);
A
Al Viro 已提交
136 137 138 139 140
	case SEMCTL:
		if (!ptr)
			return -EINVAL;
		if (get_user(pad, (u32 __user *) compat_ptr(ptr)))
			return -EFAULT;
141
		return compat_ksys_semctl(first, second, third, pad);
A
Al Viro 已提交
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177

	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:
		return sys_msgget(first, second);
	case MSGCTL:
		return compat_sys_msgctl(first, second, compat_ptr(ptr));

	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;
178
		return put_user(raddr, (compat_ulong_t __user *)compat_ptr(third));
A
Al Viro 已提交
179 180 181 182 183 184 185 186 187 188 189 190 191
	}
	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;
}
#endif
#endif