1 /*	$NetBSD: netbsd32_mqueue.c,v 1.7 2019/01/27 02:08:40 pgoyette Exp $	*/
2 
3 /*-
4  * Copyright (c) 2008 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software developed for The NetBSD Foundation.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: netbsd32_mqueue.c,v 1.7 2019/01/27 02:08:40 pgoyette Exp $");
33 
34 #if defined(_KERNEL_OPT)
35 #include "opt_compat_netbsd.h"
36 #endif
37 
38 #include <sys/param.h>
39 #include <sys/dirent.h>
40 #include <sys/filedesc.h>
41 #include <sys/fcntl.h>
42 #include <sys/module.h>
43 #include <sys/syscallvar.h>
44 
45 #include <compat/netbsd32/netbsd32.h>
46 #include <compat/netbsd32/netbsd32_syscall.h>
47 #include <compat/netbsd32/netbsd32_syscallargs.h>
48 #include <compat/netbsd32/netbsd32_conv.h>
49 
50 int
netbsd32_mq_open(struct lwp * l,const struct netbsd32_mq_open_args * uap,register_t * retval)51 netbsd32_mq_open(struct lwp *l, const struct netbsd32_mq_open_args *uap,
52     register_t *retval)
53 {
54 	/* {
55 		syscallarg(const netbsd32_charp) name;
56 		syscallarg(int) oflag;
57 		syscallarg(mode_t) mode;
58 		syscallarg(struct netbsd32_mq_attrp_t) attr;
59 	} */
60 	struct netbsd32_mq_attr attr32;
61 	struct mq_attr *attr = NULL, a;
62 	int error;
63 
64 	if ((SCARG(uap, oflag) & O_CREAT) && SCARG_P32(uap, attr) != NULL) {
65 		error = copyin(SCARG_P32(uap, attr), &attr32, sizeof(attr32));
66 		if (error)
67 			return error;
68 		netbsd32_to_mq_attr(&attr32, &a);
69 		attr = &a;
70 	}
71 
72 	return mq_handle_open(l, SCARG_P32(uap, name), SCARG(uap, oflag),
73 	    SCARG(uap, mode), attr, retval);
74 }
75 
76 int
netbsd32_mq_close(struct lwp * l,const struct netbsd32_mq_close_args * uap,register_t * retval)77 netbsd32_mq_close(struct lwp *l, const struct netbsd32_mq_close_args *uap,
78     register_t *retval)
79 {
80 	/* {
81 		syscallarg(mqd_t) mqdes;
82 	} */
83 
84 	return netbsd32_close(l, (const void*)uap, retval);
85 }
86 
87 int
netbsd32_mq_unlink(struct lwp * l,const struct netbsd32_mq_unlink_args * uap,register_t * retval)88 netbsd32_mq_unlink(struct lwp *l, const struct netbsd32_mq_unlink_args *uap,
89     register_t *retval)
90 {
91 	/* {
92 		syscallarg(const netbsd32_charp) name;
93 	} */
94 	struct sys_mq_unlink_args ua;
95 
96 	NETBSD32TOP_UAP(name, const char);
97 	return sys_mq_unlink(l, &ua, retval);
98 }
99 
100 int
netbsd32_mq_getattr(struct lwp * l,const struct netbsd32_mq_getattr_args * uap,register_t * retval)101 netbsd32_mq_getattr(struct lwp *l, const struct netbsd32_mq_getattr_args *uap,
102     register_t *retval)
103 {
104 	/* {
105 		syscallarg(mqd_t) mqdes;
106 		syscallarg(netbsd32_mq_attrp_t) mqstat;
107 	} */
108 	struct mqueue *mq;
109 	struct mq_attr attr;
110 	struct netbsd32_mq_attr a32;
111 	int error;
112 
113 	error = mqueue_get(SCARG(uap, mqdes), 0, &mq);
114 	if (error)
115 		return error;
116 
117 	memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr));
118 	mutex_exit(&mq->mq_mtx);
119 	fd_putfile((int)SCARG(uap, mqdes));
120 	netbsd32_from_mq_attr(&attr, &a32);
121 	return copyout(&a32, SCARG_P32(uap,mqstat), sizeof(a32));
122 }
123 
124 int
netbsd32_mq_setattr(struct lwp * l,const struct netbsd32_mq_setattr_args * uap,register_t * retval)125 netbsd32_mq_setattr(struct lwp *l, const struct netbsd32_mq_setattr_args *uap,
126     register_t *retval)
127 {
128 	/* {
129 		syscallarg(mqd_t) mqdes;
130 		syscallarg(const netbsd32_mq_attrp_t) mqstat;
131 		syscallarg(netbsd32_mq_attrp_t) omqstat;
132 	} */
133 	struct mqueue *mq;
134 	struct netbsd32_mq_attr attr32;
135 	struct mq_attr attr;
136 	int error, nonblock;
137 
138 	error = copyin(SCARG_P32(uap, mqstat), &attr32, sizeof(attr32));
139 	if (error)
140 		return error;
141 	netbsd32_to_mq_attr(&attr32, &attr);
142 	nonblock = (attr.mq_flags & O_NONBLOCK);
143 
144 	error = mqueue_get(SCARG(uap, mqdes), 0, &mq);
145 	if (error)
146 		return error;
147 
148 	/* Copy the old attributes, if needed */
149 	if (SCARG_P32(uap, omqstat))
150 		memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr));
151 
152 	/* Ignore everything, except O_NONBLOCK */
153 	if (nonblock)
154 		mq->mq_attrib.mq_flags |= O_NONBLOCK;
155 	else
156 		mq->mq_attrib.mq_flags &= ~O_NONBLOCK;
157 
158 	mutex_exit(&mq->mq_mtx);
159 	fd_putfile((int)SCARG(uap, mqdes));
160 
161 	/*
162 	 * Copy the data to the user-space.
163 	 * Note: According to POSIX, the new attributes should not be set in
164 	 * case of fail - this would be violated.
165 	 */
166 	if (SCARG_P32(uap, omqstat)) {
167 		netbsd32_from_mq_attr(&attr, &attr32);
168 		error = copyout(&attr32, SCARG_P32(uap, omqstat),
169 		    sizeof(attr32));
170 	}
171 
172 	return error;
173 }
174 
175 int
netbsd32_mq_notify(struct lwp * l,const struct netbsd32_mq_notify_args * uap,register_t * result)176 netbsd32_mq_notify(struct lwp *l, const struct netbsd32_mq_notify_args *uap,
177     register_t *result)
178 {
179 	/* {
180 		syscallarg(mqd_t) mqdes;
181 		syscallarg(const netbsd32_sigeventp_t) notification;
182 	} */
183 	struct mqueue *mq;
184 	struct netbsd32_sigevent sig32;
185 	int error;
186 
187 	if (SCARG_P32(uap, notification)) {
188 		/* Get the signal from user-space */
189 		error = copyin(SCARG_P32(uap, notification), &sig32,
190 		    sizeof(sig32));
191 		if (error)
192 			return error;
193 		if (sig32.sigev_notify == SIGEV_SIGNAL &&
194 		    (sig32.sigev_signo <=0 || sig32.sigev_signo >= NSIG))
195 			return EINVAL;
196 	}
197 
198 	error = mqueue_get(SCARG(uap, mqdes), 0, &mq);
199 	if (error) {
200 		return error;
201 	}
202 	if (SCARG_P32(uap, notification)) {
203 		/* Register notification: set the signal and target process */
204 		if (mq->mq_notify_proc == NULL) {
205 			netbsd32_to_sigevent(&sig32, &mq->mq_sig_notify);
206 			mq->mq_notify_proc = l->l_proc;
207 		} else {
208 			/* Fail if someone else already registered */
209 			error = EBUSY;
210 		}
211 	} else {
212 		/* Unregister the notification */
213 		mq->mq_notify_proc = NULL;
214 	}
215 	mutex_exit(&mq->mq_mtx);
216 	fd_putfile((int)SCARG(uap, mqdes));
217 
218 	return error;
219 }
220 
221 int
netbsd32_mq_send(struct lwp * l,const struct netbsd32_mq_send_args * uap,register_t * result)222 netbsd32_mq_send(struct lwp *l, const struct netbsd32_mq_send_args *uap,
223     register_t *result)
224 {
225 	/* {
226 		syscallarg(mqd_t) mqdes;
227 		syscallarg(const netbsd32_charp) msg_ptr;
228 		syscallarg(netbsd32_size_t) msg_len;
229 		syscallarg(unsigned) msg_prio;
230 	} */
231 
232 
233 	return mq_send1(SCARG(uap, mqdes), SCARG_P32(uap, msg_ptr),
234 	    SCARG(uap, msg_len), SCARG(uap, msg_prio), NULL);
235 }
236 
237 int
netbsd32_mq_receive(struct lwp * l,const struct netbsd32_mq_receive_args * uap,register_t * retval)238 netbsd32_mq_receive(struct lwp *l, const struct netbsd32_mq_receive_args *uap,
239     register_t *retval)
240 {
241 	/* {
242 		syscallarg(mqd_t) mqdes;
243 		syscallarg(netbsd32_charp) msg_ptr;
244 		syscallarg(netbsd32_size_t) msg_len;
245 		syscallarg(netbsd32_uintp) msg_prio;
246 	} */
247 	ssize_t mlen;
248 	int error;
249 
250 	error = mq_recv1(SCARG(uap, mqdes), SCARG_P32(uap, msg_ptr),
251 	    SCARG(uap, msg_len), SCARG_P32(uap, msg_prio), NULL, &mlen);
252 	if (error == 0)
253 		*retval = mlen;
254 
255 	return error;
256 }
257 
258 int
netbsd32___mq_timedsend50(struct lwp * l,const struct netbsd32___mq_timedsend50_args * uap,register_t * retval)259 netbsd32___mq_timedsend50(struct lwp *l,
260      const struct netbsd32___mq_timedsend50_args *uap, register_t *retval)
261 {
262 	/* {
263 		syscallarg(mqd_t) mqdes;
264 		syscallarg(const netbsd32_charp) msg_ptr;
265 		syscallarg(netbsd32_size_t) msg_len;
266 		syscallarg(unsigned) msg_prio;
267 		syscallarg(const netbsd32_timespecp_t) abs_timeout;
268 	} */
269 	struct timespec ts, *tsp;
270 	struct netbsd32_timespec ts32;
271 	int error;
272 
273 	/* Get and convert time value */
274 	if (SCARG_P32(uap, abs_timeout)) {
275 		error = copyin(SCARG_P32(uap, abs_timeout), &ts32,
276 		     sizeof(ts32));
277 		if (error)
278 			return error;
279 		netbsd32_to_timespec(&ts32, &ts);
280 		tsp = &ts;
281 	} else {
282 		tsp = NULL;
283 	}
284 
285 	return mq_send1(SCARG(uap, mqdes), SCARG_P32(uap, msg_ptr),
286 	    SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp);
287 }
288 
289 int
netbsd32___mq_timedreceive50(struct lwp * l,const struct netbsd32___mq_timedreceive50_args * uap,register_t * retval)290 netbsd32___mq_timedreceive50(struct lwp *l,
291     const struct netbsd32___mq_timedreceive50_args *uap, register_t *retval)
292 {
293 	/* {
294 		syscallarg(mqd_t) mqdes;
295 		syscallarg(netbsd32_charp) msg_ptr;
296 		syscallarg(netbsd32_size_t) msg_len;
297 		syscallarg(netbsd32_uintp) msg_prio;
298 		syscallarg(const netbsd32_timespecp_t) abs_timeout;
299 	} */
300 	struct timespec ts, *tsp;
301 	struct netbsd32_timespec ts32;
302 	ssize_t mlen;
303 	int error;
304 
305 	/* Get and convert time value */
306 	if (SCARG_P32(uap, abs_timeout)) {
307 		error = copyin(SCARG_P32(uap, abs_timeout), &ts32,
308 		    sizeof(ts32));
309 		if (error)
310 			return error;
311 		netbsd32_to_timespec(&ts32, &ts);
312 		tsp = &ts;
313 	} else {
314 		tsp = NULL;
315 	}
316 
317 	error = mq_recv1(SCARG(uap, mqdes), SCARG_P32(uap, msg_ptr),
318 	    SCARG(uap, msg_len), SCARG_P32(uap, msg_prio), tsp, &mlen);
319 	if (error == 0)
320 		*retval = mlen;
321 
322 	return error;
323 }
324 
325 #ifdef COMPAT_50
326 
327 int
compat_50_netbsd32_mq_timedsend(struct lwp * l,const struct compat_50_netbsd32_mq_timedsend_args * uap,register_t * retval)328 compat_50_netbsd32_mq_timedsend(struct lwp *l,
329     const struct compat_50_netbsd32_mq_timedsend_args *uap,
330     register_t *retval)
331 {
332 	/* {
333 		syscallarg(mqd_t) mqdes;
334 		syscallarg(const netbsd32_charp) msg_ptr;
335 		syscallarg(netbsd32_size_t) msg_len;
336 		syscallarg(unsigned) msg_prio;
337 		syscallarg(const netbsd32_timespec50p_t) abs_timeout;
338 	} */
339 	struct timespec ts, *tsp;
340 	struct netbsd32_timespec50 ts32;
341 	int error;
342 
343 	/* Get and convert time value */
344 	if (SCARG_P32(uap, abs_timeout)) {
345 		error = copyin(SCARG_P32(uap, abs_timeout), &ts32,
346 		     sizeof(ts32));
347 		if (error)
348 			return error;
349 		netbsd32_to_timespec50(&ts32, &ts);
350 		tsp = &ts;
351 	} else {
352 		tsp = NULL;
353 	}
354 
355 	return mq_send1(SCARG(uap, mqdes), SCARG_P32(uap, msg_ptr),
356 	    SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp);
357 }
358 
359 int
compat_50_netbsd32_mq_timedreceive(struct lwp * l,const struct compat_50_netbsd32_mq_timedreceive_args * uap,register_t * retval)360 compat_50_netbsd32_mq_timedreceive(struct lwp *l,
361     const struct compat_50_netbsd32_mq_timedreceive_args *uap,
362     register_t *retval)
363 {
364 	/* {
365 		syscallarg(mqd_t) mqdes;
366 		syscallarg(netbsd32_charp) msg_ptr;
367 		syscallarg(netbsd32_size_t) msg_len;
368 		syscallarg(netbsd32_uintp) msg_prio;
369 		syscallarg(const netbsd32_timespec50p_t) abs_timeout;
370 	} */
371 	struct timespec ts, *tsp;
372 	struct netbsd32_timespec50 ts32;
373 	ssize_t mlen;
374 	int error;
375 
376 	/* Get and convert time value */
377 	if (SCARG_P32(uap, abs_timeout)) {
378 		error = copyin(SCARG_P32(uap, abs_timeout), &ts32,
379 		    sizeof(ts32));
380 		if (error)
381 			return error;
382 		netbsd32_to_timespec50(&ts32, &ts);
383 		tsp = &ts;
384 	} else {
385 		tsp = NULL;
386 	}
387 
388 	error = mq_recv1(SCARG(uap, mqdes), SCARG_P32(uap, msg_ptr),
389 	    SCARG(uap, msg_len), SCARG_P32(uap, msg_prio), tsp, &mlen);
390 	if (error == 0)
391 		*retval = mlen;
392 
393 	return error;
394 }
395 
396 #endif /* COMPAT_50 */
397 
398 #define _PKG_ENTRY(name)	\
399 	{ NETBSD32_SYS_ ## name, 0, (sy_call_t *)name }
400 
401 static const struct syscall_package compat_mqueue_syscalls[] = {
402 	_PKG_ENTRY(netbsd32_mq_open),
403 	_PKG_ENTRY(netbsd32_mq_close),
404 	_PKG_ENTRY(netbsd32_mq_unlink),
405 	_PKG_ENTRY(netbsd32_mq_getattr),
406 	_PKG_ENTRY(netbsd32_mq_setattr),
407 	_PKG_ENTRY(netbsd32_mq_notify),
408 	_PKG_ENTRY(netbsd32_mq_send),
409 	_PKG_ENTRY(netbsd32_mq_receive),
410 	_PKG_ENTRY(netbsd32___mq_timedsend50),
411 	_PKG_ENTRY(netbsd32___mq_timedreceive50),
412 #ifdef COMPAT_50
413 	_PKG_ENTRY(compat_50_netbsd32_mq_timedsend),
414 	_PKG_ENTRY(compat_50_netbsd32_mq_timedreceive),
415 #endif
416 	{0, 0, NULL}
417 };
418 
419 MODULE(MODULE_CLASS_EXEC, compat_netbsd32_mqueue, "mqueue,compat_netbsd32");
420 
421 static int
compat_netbsd32_mqueue_modcmd(modcmd_t cmd,void * arg)422 compat_netbsd32_mqueue_modcmd(modcmd_t cmd, void *arg)
423 {
424 	int error;
425 
426 	switch (cmd) {
427 	case MODULE_CMD_INIT:
428 		error = syscall_establish(&emul_netbsd32,
429 		    compat_mqueue_syscalls);
430 		break;
431 	case MODULE_CMD_FINI:
432 		error = syscall_disestablish(&emul_netbsd32,
433 		    compat_mqueue_syscalls);
434 		break;
435 	default:
436 		error = ENOTTY;
437 		break;
438 	}
439 	return error;
440 }
441