1/*	$NetBSD: linux_ipccall.c,v 1.34 2021/09/23 06:56:27 ryo Exp $	*/
2
3/*-
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Frank van der Linden and Eric Haszlakiewicz.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33__KERNEL_RCSID(0, "$NetBSD: linux_ipccall.c,v 1.34 2021/09/23 06:56:27 ryo Exp $");
34
35#if defined(_KERNEL_OPT)
36#include "opt_sysv.h"
37#endif
38
39#include <sys/param.h>
40#include <sys/shm.h>
41#include <sys/sem.h>
42#include <sys/msg.h>
43#include <sys/proc.h>
44#include <sys/systm.h>
45
46/* real syscalls */
47#include <sys/mount.h>
48#include <sys/syscallargs.h>
49
50/* sys_ipc + args prototype */
51#include <compat/linux/common/linux_types.h>
52#include <compat/linux/common/linux_signal.h>
53
54#include <compat/linux/linux_syscallargs.h>
55#include <compat/linux/linux_syscall.h>
56
57/* general ipc defines */
58#include <compat/linux/common/linux_ipc.h>
59
60/* prototypes for real/normal linux-emul syscalls */
61#include <compat/linux/common/linux_msg.h>
62#include <compat/linux/common/linux_shm.h>
63#include <compat/linux/common/linux_sem.h>
64
65/* prototypes for sys_ipc stuff */
66#include <compat/linux/common/linux_ipccall.h>
67
68/* Used on: arm, i386, m68k, mips, ppc, sparc, sparc64 */
69/* Not used on: aarch64, alpha */
70
71/*
72 * Stuff to deal with the SysV ipc/shm/semaphore interface in Linux.
73 * The main difference is, that Linux handles it all via one
74 * system call, which has the usual maximum amount of 5 arguments.
75 * This results in a kludge for calls that take 6 of them.
76 *
77 * The SYSV??? options have to be enabled to get the appropriate
78 * functions to work.
79 */
80
81int
82linux_sys_ipc(struct lwp *l, const struct linux_sys_ipc_args *uap, register_t *retval)
83{
84	/* {
85		syscallarg(int) what;
86		syscallarg(int) a1;
87		syscallarg(int) a2;
88		syscallarg(int) a3;
89		syscallarg(void *) ptr;
90	} */
91
92	switch (SCARG(uap, what)) {
93#ifdef SYSVSEM
94	case LINUX_SYS_SEMOP:
95		return linux_semop(l, uap, retval);
96	case LINUX_SYS_SEMGET:
97		return linux_semget(l, uap, retval);
98	case LINUX_SYS_SEMCTL: {
99		struct linux_sys_semctl_args bsa;
100		union linux_semun arg;
101		int error;
102
103		SCARG(&bsa, semid) = SCARG(uap, a1);
104		SCARG(&bsa, semnum) = SCARG(uap, a2);
105		SCARG(&bsa, cmd) = SCARG(uap, a3);
106		/* Convert from (union linux_semun *) to (union linux_semun) */
107		if ((error = copyin(SCARG(uap, ptr), &arg, sizeof arg)))
108			return error;
109		SCARG(&bsa, arg) = arg;
110
111		return linux_sys_semctl(l, &bsa, retval);
112	    }
113#endif
114#ifdef SYSVMSG
115	case LINUX_SYS_MSGSND:
116		return linux_msgsnd(l, uap, retval);
117	case LINUX_SYS_MSGRCV:
118		return linux_msgrcv(l, uap, retval);
119	case LINUX_SYS_MSGGET:
120		return linux_msgget(l, uap, retval);
121	case LINUX_SYS_MSGCTL: {
122		struct linux_sys_msgctl_args bsa;
123
124		SCARG(&bsa, msqid) = SCARG(uap, a1);
125		SCARG(&bsa, cmd) = SCARG(uap, a2);
126		SCARG(&bsa, buf) = (struct linux_msqid_ds *)SCARG(uap, ptr);
127
128		return linux_sys_msgctl(l, &bsa, retval);
129	    }
130#endif
131#ifdef SYSVSHM
132	case LINUX_SYS_SHMAT: {
133		struct linux_sys_shmat_args bsa;
134
135		SCARG(&bsa, shmid) = SCARG(uap, a1);
136		SCARG(&bsa, shmaddr) = (void *)SCARG(uap, ptr);
137		SCARG(&bsa, shmflg) = SCARG(uap, a2);
138		/* XXX passing pointer inside int here */
139		SCARG(&bsa, raddr) = (u_long *)SCARG(uap, a3);
140
141		return linux_sys_shmat(l, &bsa, retval);
142	    }
143	case LINUX_SYS_SHMDT:
144		return linux_shmdt(l, uap, retval);
145	case LINUX_SYS_SHMGET:
146		return linux_shmget(l, uap, retval);
147	case LINUX_SYS_SHMCTL: {
148		struct linux_sys_shmctl_args bsa;
149
150		SCARG(&bsa, shmid) = SCARG(uap, a1);
151		SCARG(&bsa, cmd) = SCARG(uap, a2);
152		SCARG(&bsa, buf) = (struct linux_shmid_ds *)SCARG(uap, ptr);
153
154		return linux_sys_shmctl(l, &bsa, retval);
155	    }
156#endif
157	default:
158		return ENOSYS;
159	}
160}
161
162#ifdef SYSVSEM
163int
164linux_semop(struct lwp *l, const struct linux_sys_ipc_args *uap, register_t *retval)
165{
166	/* {
167		syscallarg(int) what;
168		syscallarg(int) a1;
169		syscallarg(int) a2;
170		syscallarg(int) a3;
171		syscallarg(void *) ptr;
172	} */
173	struct sys_semop_args bsa;
174
175	SCARG(&bsa, semid) = SCARG(uap, a1);
176	SCARG(&bsa, sops) = (struct sembuf *)SCARG(uap, ptr);
177	SCARG(&bsa, nsops) = SCARG(uap, a2);
178
179	return sys_semop(l, &bsa, retval);
180}
181
182int
183linux_semget(struct lwp *l, const struct linux_sys_ipc_args *uap, register_t *retval)
184{
185	/* {
186		syscallarg(int) what;
187		syscallarg(int) a1;
188		syscallarg(int) a2;
189		syscallarg(int) a3;
190		syscallarg(void *) ptr;
191	} */
192	struct sys_semget_args bsa;
193
194	SCARG(&bsa, key) = (key_t)SCARG(uap, a1);
195	SCARG(&bsa, nsems) = SCARG(uap, a2);
196	SCARG(&bsa, semflg) = SCARG(uap, a3);
197
198	return sys_semget(l, &bsa, retval);
199}
200
201#endif /* SYSVSEM */
202
203#ifdef SYSVMSG
204
205int
206linux_msgsnd(struct lwp *l, const struct linux_sys_ipc_args *uap, register_t *retval)
207{
208	struct sys_msgsnd_args bma;
209
210	SCARG(&bma, msqid) = SCARG(uap, a1);
211	SCARG(&bma, msgp) = SCARG(uap, ptr);
212	SCARG(&bma, msgsz) = SCARG(uap, a2);
213	SCARG(&bma, msgflg) = SCARG(uap, a3);
214
215	return sys_msgsnd(l, &bma, retval);
216}
217
218int
219linux_msgrcv(struct lwp *l, const struct linux_sys_ipc_args *uap, register_t *retval)
220{
221	struct sys_msgrcv_args bma;
222	struct linux_msgrcv_msgarg kluge;
223	int error;
224
225	if ((error = copyin(SCARG(uap, ptr), &kluge, sizeof kluge)))
226		return error;
227
228	SCARG(&bma, msqid) = SCARG(uap, a1);
229	SCARG(&bma, msgp) = kluge.msg;
230	SCARG(&bma, msgsz) = SCARG(uap, a2);
231	SCARG(&bma, msgtyp) = kluge.type;
232	SCARG(&bma, msgflg) = SCARG(uap, a3);
233
234	return sys_msgrcv(l, &bma, retval);
235}
236
237int
238linux_msgget(struct lwp *l, const struct linux_sys_ipc_args *uap, register_t *retval)
239{
240	struct sys_msgget_args bma;
241
242	SCARG(&bma, key) = (key_t)SCARG(uap, a1);
243	SCARG(&bma, msgflg) = SCARG(uap, a2);
244
245	return sys_msgget(l, &bma, retval);
246}
247
248#endif /* SYSVMSG */
249
250#ifdef SYSVSHM
251/*
252 * shmdt(): this could have been mapped directly, if it wasn't for
253 * the extra indirection by the linux_ipc system call.
254 */
255int
256linux_shmdt(struct lwp *l, const struct linux_sys_ipc_args *uap, register_t *retval)
257{
258	struct sys_shmdt_args bsa;
259
260	SCARG(&bsa, shmaddr) = SCARG(uap, ptr);
261
262	return sys_shmdt(l, &bsa, retval);
263}
264
265/*
266 * Same story as shmdt.
267 */
268int
269linux_shmget(struct lwp *l, const struct linux_sys_ipc_args *uap, register_t *retval)
270{
271	struct linux_sys_shmget_args bsa;
272
273	SCARG(&bsa, key) = SCARG(uap, a1);
274	SCARG(&bsa, size) = SCARG(uap, a2);
275	SCARG(&bsa, shmflg) = SCARG(uap, a3);
276
277	return linux_sys_shmget(l, &bsa, retval);
278}
279
280#endif /* SYSVSHM */
281