syscall.c revision 69894718
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * sys_ipc() is the old de-multiplexer for the SysV IPC calls.
4 *
5 * This is really horribly ugly, and new architectures should just wire up
6 * the individual syscalls instead.
7 */
8#include <linux/unistd.h>
9#include <linux/syscalls.h>
10#include <linux/security.h>
11#include <linux/ipc_namespace.h>
12#include "util.h"
13
14#ifdef __ARCH_WANT_SYS_IPC
15#include <linux/errno.h>
16#include <linux/ipc.h>
17#include <linux/shm.h>
18#include <linux/uaccess.h>
19
20SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, unsigned long, second,
21		unsigned long, third, void __user *, ptr, long, fifth)
22{
23	int version, ret;
24
25	version = call >> 16; /* hack for backward compatibility */
26	call &= 0xffff;
27
28	switch (call) {
29	case SEMOP:
30		return ksys_semtimedop(first, (struct sembuf __user *)ptr,
31				       second, NULL);
32	case SEMTIMEDOP:
33		return ksys_semtimedop(first, (struct sembuf __user *)ptr,
34				       second,
35				       (const struct timespec __user *)fifth);
36
37	case SEMGET:
38		return ksys_semget(first, second, third);
39	case SEMCTL: {
40		unsigned long arg;
41		if (!ptr)
42			return -EINVAL;
43		if (get_user(arg, (unsigned long __user *) ptr))
44			return -EFAULT;
45		return sys_semctl(first, second, third, arg);
46	}
47
48	case MSGSND:
49		return sys_msgsnd(first, (struct msgbuf __user *) ptr,
50				  second, third);
51	case MSGRCV:
52		switch (version) {
53		case 0: {
54			struct ipc_kludge tmp;
55			if (!ptr)
56				return -EINVAL;
57
58			if (copy_from_user(&tmp,
59					   (struct ipc_kludge __user *) ptr,
60					   sizeof(tmp)))
61				return -EFAULT;
62			return sys_msgrcv(first, tmp.msgp, second,
63					   tmp.msgtyp, third);
64		}
65		default:
66			return sys_msgrcv(first,
67					   (struct msgbuf __user *) ptr,
68					   second, fifth, third);
69		}
70	case MSGGET:
71		return sys_msgget((key_t) first, second);
72	case MSGCTL:
73		return sys_msgctl(first, second, (struct msqid_ds __user *)ptr);
74
75	case SHMAT:
76		switch (version) {
77		default: {
78			unsigned long raddr;
79			ret = do_shmat(first, (char __user *)ptr,
80				       second, &raddr, SHMLBA);
81			if (ret)
82				return ret;
83			return put_user(raddr, (unsigned long __user *) third);
84		}
85		case 1:
86			/*
87			 * This was the entry point for kernel-originating calls
88			 * from iBCS2 in 2.2 days.
89			 */
90			return -EINVAL;
91		}
92	case SHMDT:
93		return sys_shmdt((char __user *)ptr);
94	case SHMGET:
95		return sys_shmget(first, second, third);
96	case SHMCTL:
97		return sys_shmctl(first, second,
98				   (struct shmid_ds __user *) ptr);
99	default:
100		return -ENOSYS;
101	}
102}
103#endif
104
105#ifdef CONFIG_COMPAT
106#include <linux/compat.h>
107
108#ifndef COMPAT_SHMLBA
109#define COMPAT_SHMLBA	SHMLBA
110#endif
111
112struct compat_ipc_kludge {
113	compat_uptr_t msgp;
114	compat_long_t msgtyp;
115};
116
117#ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC
118COMPAT_SYSCALL_DEFINE6(ipc, u32, call, int, first, int, second,
119	u32, third, compat_uptr_t, ptr, u32, fifth)
120{
121	int version;
122	u32 pad;
123
124	version = call >> 16; /* hack for backward compatibility */
125	call &= 0xffff;
126
127	switch (call) {
128	case SEMOP:
129		/* struct sembuf is the same on 32 and 64bit :)) */
130		return ksys_semtimedop(first, compat_ptr(ptr), second, NULL);
131	case SEMTIMEDOP:
132		return compat_ksys_semtimedop(first, compat_ptr(ptr), second,
133						compat_ptr(fifth));
134	case SEMGET:
135		return ksys_semget(first, second, third);
136	case SEMCTL:
137		if (!ptr)
138			return -EINVAL;
139		if (get_user(pad, (u32 __user *) compat_ptr(ptr)))
140			return -EFAULT;
141		return compat_sys_semctl(first, second, third, pad);
142
143	case MSGSND:
144		return compat_sys_msgsnd(first, ptr, second, third);
145
146	case MSGRCV: {
147		void __user *uptr = compat_ptr(ptr);
148
149		if (first < 0 || second < 0)
150			return -EINVAL;
151
152		if (!version) {
153			struct compat_ipc_kludge ipck;
154			if (!uptr)
155				return -EINVAL;
156			if (copy_from_user(&ipck, uptr, sizeof(ipck)))
157				return -EFAULT;
158			return compat_sys_msgrcv(first, ipck.msgp, second,
159						 ipck.msgtyp, third);
160		}
161		return compat_sys_msgrcv(first, ptr, second, fifth, third);
162	}
163	case MSGGET:
164		return sys_msgget(first, second);
165	case MSGCTL:
166		return compat_sys_msgctl(first, second, compat_ptr(ptr));
167
168	case SHMAT: {
169		int err;
170		unsigned long raddr;
171
172		if (version == 1)
173			return -EINVAL;
174		err = do_shmat(first, compat_ptr(ptr), second, &raddr,
175			       COMPAT_SHMLBA);
176		if (err < 0)
177			return err;
178		return put_user(raddr, (compat_ulong_t __user *)compat_ptr(third));
179	}
180	case SHMDT:
181		return sys_shmdt(compat_ptr(ptr));
182	case SHMGET:
183		return sys_shmget(first, (unsigned)second, third);
184	case SHMCTL:
185		return compat_sys_shmctl(first, second, compat_ptr(ptr));
186	}
187
188	return -ENOSYS;
189}
190#endif
191#endif
192