xref: /freebsd/sys/kern/sysv_msg.c (revision 8771dc950a463b35d5cdafd71c86dd5a2dbb9096)
1 /*-
2  * Implementation of SVID messages
3  *
4  * Author:  Daniel Boulet
5  *
6  * Copyright 1993 Daniel Boulet and RTMX Inc.
7  *
8  * This system call was implemented by Daniel Boulet under contract from RTMX.
9  *
10  * Redistribution and use in source forms, with and without modification,
11  * are permitted provided that this entire comment appears intact.
12  *
13  * Redistribution in binary form may occur without any restrictions.
14  * Obviously, it would be nice if you gave credit where credit is due
15  * but requiring it would be too onerous.
16  *
17  * This software is provided ``AS IS'' without any warranties of any kind.
18  */
19 /*-
20  * SPDX-License-Identifier: BSD-2-Clause
21  *
22  * Copyright (c) 2003-2005 McAfee, Inc.
23  * Copyright (c) 2016-2017 Robert N. M. Watson
24  * All rights reserved.
25  *
26  * This software was developed for the FreeBSD Project in part by McAfee
27  * Research, the Security Research Division of McAfee, Inc under DARPA/SPAWAR
28  * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS research
29  * program.
30  *
31  * Portions of this software were developed by BAE Systems, the University of
32  * Cambridge Computer Laboratory, and Memorial University under DARPA/AFRL
33  * contract FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent
34  * Computing (TC) research program.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  * 2. Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in the
43  *    documentation and/or other materials provided with the distribution.
44  *
45  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
46  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
49  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55  * SUCH DAMAGE.
56  */
57 
58 #include "opt_sysvipc.h"
59 
60 #include <sys/param.h>
61 #include <sys/systm.h>
62 #include <sys/sysproto.h>
63 #include <sys/kernel.h>
64 #include <sys/priv.h>
65 #include <sys/proc.h>
66 #include <sys/lock.h>
67 #include <sys/mutex.h>
68 #include <sys/module.h>
69 #include <sys/mount.h>
70 #include <sys/msg.h>
71 #include <sys/racct.h>
72 #include <sys/sx.h>
73 #include <sys/syscall.h>
74 #include <sys/syscallsubr.h>
75 #include <sys/sysent.h>
76 #include <sys/sysctl.h>
77 #include <sys/malloc.h>
78 #include <sys/jail.h>
79 
80 #include <security/audit/audit.h>
81 #include <security/mac/mac_framework.h>
82 
83 FEATURE(sysv_msg, "System V message queues support");
84 
85 static MALLOC_DEFINE(M_MSG, "msg", "SVID compatible message queues");
86 
87 static int msginit(void);
88 static int msgunload(void);
89 static int sysvmsg_modload(struct module *, int, void *);
90 static void msq_remove(struct msqid_kernel *);
91 static struct prison *msg_find_prison(struct ucred *);
92 static int msq_prison_cansee(struct prison *, struct msqid_kernel *);
93 static int msg_prison_check(void *, void *);
94 static int msg_prison_set(void *, void *);
95 static int msg_prison_get(void *, void *);
96 static int msg_prison_remove(void *, void *);
97 static void msg_prison_cleanup(struct prison *);
98 
99 #ifdef MSG_DEBUG
100 #define DPRINTF(a)	printf a
101 #else
102 #define DPRINTF(a)	(void)0
103 #endif
104 
105 static void msg_freehdr(struct msg *msghdr);
106 
107 #ifndef MSGSSZ
108 #define MSGSSZ	8		/* Each segment must be 2^N long */
109 #endif
110 #ifndef MSGSEG
111 #define MSGSEG	2048		/* must be less than 32767 */
112 #endif
113 #define MSGMAX	(MSGSSZ*MSGSEG)
114 #ifndef MSGMNB
115 #define MSGMNB	2048		/* max # of bytes in a queue */
116 #endif
117 #ifndef MSGMNI
118 #define MSGMNI	40
119 #endif
120 #ifndef MSGTQL
121 #define MSGTQL	40
122 #endif
123 
124 /*
125  * Based on the configuration parameters described in an SVR2 (yes, two)
126  * config(1m) man page.
127  *
128  * Each message is broken up and stored in segments that are msgssz bytes
129  * long.  For efficiency reasons, this should be a power of two.  Also,
130  * it doesn't make sense if it is less than 8 or greater than about 256.
131  * Consequently, msginit in kern/sysv_msg.c checks that msgssz is a power of
132  * two between 8 and 1024 inclusive (and panic's if it isn't).
133  */
134 struct msginfo msginfo = {
135                 MSGMAX,         /* max chars in a message */
136                 MSGMNI,         /* # of message queue identifiers */
137                 MSGMNB,         /* max chars in a queue */
138                 MSGTQL,         /* max messages in system */
139                 MSGSSZ,         /* size of a message segment */
140                 		/* (must be small power of 2 greater than 4) */
141                 MSGSEG          /* number of message segments */
142 };
143 
144 /*
145  * macros to convert between msqid_ds's and msqid's.
146  * (specific to this implementation)
147  */
148 #define MSQID(ix,ds)	((ix) & 0xffff | (((ds).msg_perm.seq << 16) & 0xffff0000))
149 #define MSQID_IX(id)	((id) & 0xffff)
150 #define MSQID_SEQ(id)	(((id) >> 16) & 0xffff)
151 
152 /*
153  * The rest of this file is specific to this particular implementation.
154  */
155 
156 struct msgmap {
157 	short	next;		/* next segment in buffer */
158     				/* -1 -> available */
159     				/* 0..(MSGSEG-1) -> index of next segment */
160 };
161 
162 #define MSG_LOCKED	01000	/* Is this msqid_ds locked? */
163 
164 static int nfree_msgmaps;	/* # of free map entries */
165 static short free_msgmaps;	/* head of linked list of free map entries */
166 static struct msg *free_msghdrs;/* list of free msg headers */
167 static char *msgpool;		/* MSGMAX byte long msg buffer pool */
168 static struct msgmap *msgmaps;	/* MSGSEG msgmap structures */
169 static struct msg *msghdrs;	/* MSGTQL msg headers */
170 static struct msqid_kernel *msqids;	/* MSGMNI msqid_kernel struct's */
171 static struct mtx msq_mtx;	/* global mutex for message queues. */
172 static unsigned msg_prison_slot;/* prison OSD slot */
173 
174 static struct syscall_helper_data msg_syscalls[] = {
175 	SYSCALL_INIT_HELPER(msgctl),
176 	SYSCALL_INIT_HELPER(msgget),
177 	SYSCALL_INIT_HELPER(msgsnd),
178 	SYSCALL_INIT_HELPER(msgrcv),
179 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
180     defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
181 	SYSCALL_INIT_HELPER(msgsys),
182 	SYSCALL_INIT_HELPER_COMPAT(freebsd7_msgctl),
183 #endif
184 	SYSCALL_INIT_LAST
185 };
186 
187 #ifdef COMPAT_FREEBSD32
188 #include <compat/freebsd32/freebsd32.h>
189 #include <compat/freebsd32/freebsd32_ipc.h>
190 #include <compat/freebsd32/freebsd32_proto.h>
191 #include <compat/freebsd32/freebsd32_signal.h>
192 #include <compat/freebsd32/freebsd32_syscall.h>
193 #include <compat/freebsd32/freebsd32_util.h>
194 
195 static struct syscall_helper_data msg32_syscalls[] = {
196 	SYSCALL32_INIT_HELPER(freebsd32_msgctl),
197 	SYSCALL32_INIT_HELPER(freebsd32_msgsnd),
198 	SYSCALL32_INIT_HELPER(freebsd32_msgrcv),
199 	SYSCALL32_INIT_HELPER_COMPAT(msgget),
200 	SYSCALL32_INIT_HELPER(freebsd32_msgsys),
201 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
202     defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
203 	SYSCALL32_INIT_HELPER(freebsd7_freebsd32_msgctl),
204 #endif
205 	SYSCALL_INIT_LAST
206 };
207 #endif
208 
209 static int
msginit(void)210 msginit(void)
211 {
212 	struct prison *pr;
213 	void **rsv;
214 	int i, error;
215 	osd_method_t methods[PR_MAXMETHOD] = {
216 	    [PR_METHOD_CHECK] =		msg_prison_check,
217 	    [PR_METHOD_SET] =		msg_prison_set,
218 	    [PR_METHOD_GET] =		msg_prison_get,
219 	    [PR_METHOD_REMOVE] =	msg_prison_remove,
220 	};
221 
222 	msginfo.msgmax = msginfo.msgseg * msginfo.msgssz;
223 	msgpool = malloc(msginfo.msgmax, M_MSG, M_WAITOK);
224 	msgmaps = malloc(sizeof(struct msgmap) * msginfo.msgseg, M_MSG, M_WAITOK);
225 	msghdrs = malloc(sizeof(struct msg) * msginfo.msgtql, M_MSG, M_WAITOK);
226 	msqids = malloc(sizeof(struct msqid_kernel) * msginfo.msgmni, M_MSG,
227 	    M_WAITOK | M_ZERO);
228 
229 	/*
230 	 * msginfo.msgssz should be a power of two for efficiency reasons.
231 	 * It is also pretty silly if msginfo.msgssz is less than 8
232 	 * or greater than about 256 so ...
233 	 */
234 
235 	i = 8;
236 	while (i < 1024 && i != msginfo.msgssz)
237 		i <<= 1;
238     	if (i != msginfo.msgssz) {
239 		DPRINTF(("msginfo.msgssz=%d (0x%x)\n", msginfo.msgssz,
240 		    msginfo.msgssz));
241 		panic("msginfo.msgssz not a small power of 2");
242 	}
243 
244 	if (msginfo.msgseg > 32767) {
245 		DPRINTF(("msginfo.msgseg=%d\n", msginfo.msgseg));
246 		panic("msginfo.msgseg > 32767");
247 	}
248 
249 	for (i = 0; i < msginfo.msgseg; i++) {
250 		if (i > 0)
251 			msgmaps[i-1].next = i;
252 		msgmaps[i].next = -1;	/* implies entry is available */
253 	}
254 	free_msgmaps = 0;
255 	nfree_msgmaps = msginfo.msgseg;
256 
257 	for (i = 0; i < msginfo.msgtql; i++) {
258 		msghdrs[i].msg_type = 0;
259 		if (i > 0)
260 			msghdrs[i-1].msg_next = &msghdrs[i];
261 		msghdrs[i].msg_next = NULL;
262 #ifdef MAC
263 		mac_sysvmsg_init(&msghdrs[i]);
264 #endif
265     	}
266 	free_msghdrs = &msghdrs[0];
267 
268 	for (i = 0; i < msginfo.msgmni; i++) {
269 		msqids[i].u.msg_qbytes = 0;	/* implies entry is available */
270 		msqids[i].u.msg_perm.seq = 0;	/* reset to a known value */
271 		msqids[i].u.msg_perm.mode = 0;
272 #ifdef MAC
273 		mac_sysvmsq_init(&msqids[i]);
274 #endif
275 	}
276 	mtx_init(&msq_mtx, "msq", NULL, MTX_DEF);
277 
278 	/* Set current prisons according to their allow.sysvipc. */
279 	msg_prison_slot = osd_jail_register(NULL, methods);
280 	rsv = osd_reserve(msg_prison_slot);
281 	prison_lock(&prison0);
282 	(void)osd_jail_set_reserved(&prison0, msg_prison_slot, rsv, &prison0);
283 	prison_unlock(&prison0);
284 	rsv = NULL;
285 	sx_slock(&allprison_lock);
286 	TAILQ_FOREACH(pr, &allprison, pr_list) {
287 		if (rsv == NULL)
288 			rsv = osd_reserve(msg_prison_slot);
289 		prison_lock(pr);
290 		if (pr->pr_allow & PR_ALLOW_SYSVIPC) {
291 			(void)osd_jail_set_reserved(pr, msg_prison_slot, rsv,
292 			    &prison0);
293 			rsv = NULL;
294 		}
295 		prison_unlock(pr);
296 	}
297 	if (rsv != NULL)
298 		osd_free_reserved(rsv);
299 	sx_sunlock(&allprison_lock);
300 
301 	error = syscall_helper_register(msg_syscalls, SY_THR_STATIC_KLD);
302 	if (error != 0)
303 		return (error);
304 #ifdef COMPAT_FREEBSD32
305 	error = syscall32_helper_register(msg32_syscalls, SY_THR_STATIC_KLD);
306 	if (error != 0)
307 		return (error);
308 #endif
309 	return (0);
310 }
311 
312 static int
msgunload(void)313 msgunload(void)
314 {
315 	struct msqid_kernel *msqkptr;
316 	int msqid;
317 #ifdef MAC
318 	int i;
319 #endif
320 
321 	syscall_helper_unregister(msg_syscalls);
322 #ifdef COMPAT_FREEBSD32
323 	syscall32_helper_unregister(msg32_syscalls);
324 #endif
325 
326 	for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
327 		msqkptr = &msqids[msqid];
328 		if (msqkptr->u.msg_qbytes != 0 ||
329 		    (msqkptr->u.msg_perm.mode & MSG_LOCKED) != 0)
330 			break;
331 	}
332 	if (msqid != msginfo.msgmni)
333 		return (EBUSY);
334 
335 	if (msg_prison_slot != 0)
336 		osd_jail_deregister(msg_prison_slot);
337 #ifdef MAC
338 	for (i = 0; i < msginfo.msgtql; i++)
339 		mac_sysvmsg_destroy(&msghdrs[i]);
340 	for (msqid = 0; msqid < msginfo.msgmni; msqid++)
341 		mac_sysvmsq_destroy(&msqids[msqid]);
342 #endif
343 	free(msgpool, M_MSG);
344 	free(msgmaps, M_MSG);
345 	free(msghdrs, M_MSG);
346 	free(msqids, M_MSG);
347 	mtx_destroy(&msq_mtx);
348 	return (0);
349 }
350 
351 static int
sysvmsg_modload(struct module * module,int cmd,void * arg)352 sysvmsg_modload(struct module *module, int cmd, void *arg)
353 {
354 	int error = 0;
355 
356 	switch (cmd) {
357 	case MOD_LOAD:
358 		error = msginit();
359 		if (error != 0)
360 			msgunload();
361 		break;
362 	case MOD_UNLOAD:
363 		error = msgunload();
364 		break;
365 	case MOD_SHUTDOWN:
366 		break;
367 	default:
368 		error = EINVAL;
369 		break;
370 	}
371 	return (error);
372 }
373 
374 static moduledata_t sysvmsg_mod = {
375 	"sysvmsg",
376 	&sysvmsg_modload,
377 	NULL
378 };
379 
380 DECLARE_MODULE(sysvmsg, sysvmsg_mod, SI_SUB_SYSV_MSG, SI_ORDER_FIRST);
381 MODULE_VERSION(sysvmsg, 1);
382 
383 static void
msg_freehdr(struct msg * msghdr)384 msg_freehdr(struct msg *msghdr)
385 {
386 	while (msghdr->msg_ts > 0) {
387 		short next;
388 		if (msghdr->msg_spot < 0 || msghdr->msg_spot >= msginfo.msgseg)
389 			panic("msghdr->msg_spot out of range");
390 		next = msgmaps[msghdr->msg_spot].next;
391 		msgmaps[msghdr->msg_spot].next = free_msgmaps;
392 		free_msgmaps = msghdr->msg_spot;
393 		nfree_msgmaps++;
394 		msghdr->msg_spot = next;
395 		if (msghdr->msg_ts >= msginfo.msgssz)
396 			msghdr->msg_ts -= msginfo.msgssz;
397 		else
398 			msghdr->msg_ts = 0;
399 	}
400 	if (msghdr->msg_spot != -1)
401 		panic("msghdr->msg_spot != -1");
402 	msghdr->msg_next = free_msghdrs;
403 	free_msghdrs = msghdr;
404 #ifdef MAC
405 	mac_sysvmsg_cleanup(msghdr);
406 #endif
407 }
408 
409 static void
msq_remove(struct msqid_kernel * msqkptr)410 msq_remove(struct msqid_kernel *msqkptr)
411 {
412 	struct msg *msghdr;
413 
414 	racct_sub_cred(msqkptr->cred, RACCT_NMSGQ, 1);
415 	racct_sub_cred(msqkptr->cred, RACCT_MSGQQUEUED, msqkptr->u.msg_qnum);
416 	racct_sub_cred(msqkptr->cred, RACCT_MSGQSIZE, msqkptr->u.msg_cbytes);
417 	crfree(msqkptr->cred);
418 	msqkptr->cred = NULL;
419 
420 	/* Free the message headers */
421 	msghdr = msqkptr->u.__msg_first;
422 	while (msghdr != NULL) {
423 		struct msg *msghdr_tmp;
424 
425 		/* Free the segments of each message */
426 		msqkptr->u.msg_cbytes -= msghdr->msg_ts;
427 		msqkptr->u.msg_qnum--;
428 		msghdr_tmp = msghdr;
429 		msghdr = msghdr->msg_next;
430 		msg_freehdr(msghdr_tmp);
431 	}
432 
433 	if (msqkptr->u.msg_cbytes != 0)
434 		panic("msg_cbytes is screwed up");
435 	if (msqkptr->u.msg_qnum != 0)
436 		panic("msg_qnum is screwed up");
437 
438 	msqkptr->u.msg_qbytes = 0;	/* Mark it as free */
439 
440 #ifdef MAC
441 	mac_sysvmsq_cleanup(msqkptr);
442 #endif
443 
444 	wakeup(msqkptr);
445 }
446 
447 static struct prison *
msg_find_prison(struct ucred * cred)448 msg_find_prison(struct ucred *cred)
449 {
450 	struct prison *pr, *rpr;
451 
452 	pr = cred->cr_prison;
453 	prison_lock(pr);
454 	rpr = osd_jail_get(pr, msg_prison_slot);
455 	prison_unlock(pr);
456 	return rpr;
457 }
458 
459 static int
msq_prison_cansee(struct prison * rpr,struct msqid_kernel * msqkptr)460 msq_prison_cansee(struct prison *rpr, struct msqid_kernel *msqkptr)
461 {
462 
463 	if (msqkptr->cred == NULL ||
464 	    !(rpr == msqkptr->cred->cr_prison ||
465 	      prison_ischild(rpr, msqkptr->cred->cr_prison)))
466 		return (EINVAL);
467 	return (0);
468 }
469 
470 #ifndef _SYS_SYSPROTO_H_
471 struct msgctl_args {
472 	int	msqid;
473 	int	cmd;
474 	struct	msqid_ds *buf;
475 };
476 #endif
477 int
sys_msgctl(struct thread * td,struct msgctl_args * uap)478 sys_msgctl(struct thread *td, struct msgctl_args *uap)
479 {
480 	int msqid = uap->msqid;
481 	int cmd = uap->cmd;
482 	struct msqid_ds msqbuf;
483 	int error;
484 
485 	DPRINTF(("call to msgctl(%d, %d, %p)\n", msqid, cmd, uap->buf));
486 	if (cmd == IPC_SET &&
487 	    (error = copyin(uap->buf, &msqbuf, sizeof(msqbuf))) != 0)
488 		return (error);
489 	error = kern_msgctl(td, msqid, cmd, &msqbuf);
490 	if (cmd == IPC_STAT && error == 0)
491 		error = copyout(&msqbuf, uap->buf, sizeof(struct msqid_ds));
492 	return (error);
493 }
494 
495 int
kern_msgctl(struct thread * td,int msqid,int cmd,struct msqid_ds * msqbuf)496 kern_msgctl(struct thread *td, int msqid, int cmd, struct msqid_ds *msqbuf)
497 {
498 	int rval, error, msqix;
499 	struct msqid_kernel *msqkptr;
500 	struct prison *rpr;
501 
502 	rpr = msg_find_prison(td->td_ucred);
503 	if (rpr == NULL)
504 		return (ENOSYS);
505 
506 	AUDIT_ARG_SVIPC_CMD(cmd);
507 	AUDIT_ARG_SVIPC_ID(msqid);
508 	msqix = IPCID_TO_IX(msqid);
509 
510 	if (msqix < 0 || msqix >= msginfo.msgmni) {
511 		DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqix,
512 		    msginfo.msgmni));
513 		return (EINVAL);
514 	}
515 
516 	msqkptr = &msqids[msqix];
517 
518 	mtx_lock(&msq_mtx);
519 	if (msqkptr->u.msg_qbytes == 0) {
520 		DPRINTF(("no such msqid\n"));
521 		error = EINVAL;
522 		goto done2;
523 	}
524 	if (msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) {
525 		DPRINTF(("wrong sequence number\n"));
526 		error = EINVAL;
527 		goto done2;
528 	}
529 
530 	error = msq_prison_cansee(rpr, msqkptr);
531 	if (error != 0) {
532 		DPRINTF(("requester can't see prison\n"));
533 		goto done2;
534 	}
535 
536 #ifdef MAC
537 	error = mac_sysvmsq_check_msqctl(td->td_ucred, msqkptr, cmd);
538 	if (error != 0)
539 		goto done2;
540 #endif
541 
542 	error = 0;
543 	rval = 0;
544 
545 	switch (cmd) {
546 	case IPC_RMID:
547 	{
548 #ifdef MAC
549 		struct msg *msghdr;
550 #endif
551 		if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_M)))
552 			goto done2;
553 
554 #ifdef MAC
555 		/*
556 		 * Check that the thread has MAC access permissions to
557 		 * individual msghdrs.  Note: We need to do this in a
558 		 * separate loop because the actual loop alters the
559 		 * msq/msghdr info as it progresses, and there is no going
560 		 * back if half the way through we discover that the
561 		 * thread cannot free a certain msghdr.  The msq will get
562 		 * into an inconsistent state.
563 		 */
564 		for (msghdr = msqkptr->u.__msg_first; msghdr != NULL;
565 		    msghdr = msghdr->msg_next) {
566 			error = mac_sysvmsq_check_msgrmid(td->td_ucred, msghdr);
567 			if (error != 0)
568 				goto done2;
569 		}
570 #endif
571 
572 		msq_remove(msqkptr);
573 	}
574 
575 		break;
576 
577 	case IPC_SET:
578 		AUDIT_ARG_SVIPC_PERM(&msqbuf->msg_perm);
579 		if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_M)))
580 			goto done2;
581 		if (msqbuf->msg_qbytes > msqkptr->u.msg_qbytes) {
582 			error = priv_check(td, PRIV_IPC_MSGSIZE);
583 			if (error)
584 				goto done2;
585 		}
586 		if (msqbuf->msg_qbytes > msginfo.msgmnb) {
587 			DPRINTF(("can't increase msg_qbytes beyond %d"
588 			    "(truncating)\n", msginfo.msgmnb));
589 			msqbuf->msg_qbytes = msginfo.msgmnb;	/* silently restrict qbytes to system limit */
590 		}
591 		if (msqbuf->msg_qbytes == 0) {
592 			DPRINTF(("can't reduce msg_qbytes to 0\n"));
593 			error = EINVAL;		/* non-standard errno! */
594 			goto done2;
595 		}
596 		msqkptr->u.msg_perm.uid = msqbuf->msg_perm.uid;	/* change the owner */
597 		msqkptr->u.msg_perm.gid = msqbuf->msg_perm.gid;	/* change the owner */
598 		msqkptr->u.msg_perm.mode = (msqkptr->u.msg_perm.mode & ~0777) |
599 		    (msqbuf->msg_perm.mode & 0777);
600 		msqkptr->u.msg_qbytes = msqbuf->msg_qbytes;
601 		msqkptr->u.msg_ctime = time_second;
602 		break;
603 
604 	case IPC_STAT:
605 		if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_R))) {
606 			DPRINTF(("requester doesn't have read access\n"));
607 			goto done2;
608 		}
609 		*msqbuf = msqkptr->u;
610 		if (td->td_ucred->cr_prison != msqkptr->cred->cr_prison)
611 			msqbuf->msg_perm.key = IPC_PRIVATE;
612 
613 		/*
614 		 * Try to hide the fact that the structure layout is shared by
615 		 * both the kernel and userland.  These pointers are not useful
616 		 * to userspace.
617 		 */
618 		msqbuf->__msg_first = msqbuf->__msg_last = NULL;
619 		break;
620 
621 	default:
622 		DPRINTF(("invalid command %d\n", cmd));
623 		error = EINVAL;
624 		goto done2;
625 	}
626 
627 	if (error == 0)
628 		td->td_retval[0] = rval;
629 done2:
630 	mtx_unlock(&msq_mtx);
631 	return (error);
632 }
633 
634 #ifndef _SYS_SYSPROTO_H_
635 struct msgget_args {
636 	key_t	key;
637 	int	msgflg;
638 };
639 #endif
640 
641 int
sys_msgget(struct thread * td,struct msgget_args * uap)642 sys_msgget(struct thread *td, struct msgget_args *uap)
643 {
644 	int msqid, error = 0;
645 	int key = uap->key;
646 	int msgflg = uap->msgflg;
647 	struct ucred *cred = td->td_ucred;
648 	struct msqid_kernel *msqkptr = NULL;
649 
650 	DPRINTF(("msgget(0x%x, 0%o)\n", key, msgflg));
651 
652 	if (msg_find_prison(cred) == NULL)
653 		return (ENOSYS);
654 
655 	mtx_lock(&msq_mtx);
656 	if (key != IPC_PRIVATE) {
657 		for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
658 			msqkptr = &msqids[msqid];
659 			if (msqkptr->u.msg_qbytes != 0 &&
660 			    msqkptr->cred != NULL &&
661 			    msqkptr->cred->cr_prison == cred->cr_prison &&
662 			    msqkptr->u.msg_perm.key == key)
663 				break;
664 		}
665 		if (msqid < msginfo.msgmni) {
666 			DPRINTF(("found public key\n"));
667 			if ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL)) {
668 				DPRINTF(("not exclusive\n"));
669 				error = EEXIST;
670 				goto done2;
671 			}
672 			AUDIT_ARG_SVIPC_ID(IXSEQ_TO_IPCID(msqid,
673 			    msqkptr->u.msg_perm));
674 			if ((error = ipcperm(td, &msqkptr->u.msg_perm,
675 			    msgflg & 0700))) {
676 				DPRINTF(("requester doesn't have 0%o access\n",
677 				    msgflg & 0700));
678 				goto done2;
679 			}
680 #ifdef MAC
681 			error = mac_sysvmsq_check_msqget(cred, msqkptr);
682 			if (error != 0)
683 				goto done2;
684 #endif
685 			goto found;
686 		}
687 	}
688 
689 	DPRINTF(("need to allocate the msqid_ds\n"));
690 	if (key == IPC_PRIVATE || (msgflg & IPC_CREAT)) {
691 		for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
692 			/*
693 			 * Look for an unallocated and unlocked msqid_ds.
694 			 * msqid_ds's can be locked by msgsnd or msgrcv while
695 			 * they are copying the message in/out.  We can't
696 			 * re-use the entry until they release it.
697 			 */
698 			msqkptr = &msqids[msqid];
699 			if (msqkptr->u.msg_qbytes == 0 &&
700 			    (msqkptr->u.msg_perm.mode & MSG_LOCKED) == 0)
701 				break;
702 		}
703 		if (msqid == msginfo.msgmni) {
704 			DPRINTF(("no more msqid_ds's available\n"));
705 			error = ENOSPC;
706 			goto done2;
707 		}
708 #ifdef RACCT
709 		if (racct_enable) {
710 			PROC_LOCK(td->td_proc);
711 			error = racct_add(td->td_proc, RACCT_NMSGQ, 1);
712 			PROC_UNLOCK(td->td_proc);
713 			if (error != 0) {
714 				error = ENOSPC;
715 				goto done2;
716 			}
717 		}
718 #endif
719 		DPRINTF(("msqid %d is available\n", msqid));
720 		msqkptr->u.msg_perm.key = key;
721 		msqkptr->u.msg_perm.cuid = cred->cr_uid;
722 		msqkptr->u.msg_perm.uid = cred->cr_uid;
723 		msqkptr->u.msg_perm.cgid = cred->cr_gid;
724 		msqkptr->u.msg_perm.gid = cred->cr_gid;
725 		msqkptr->u.msg_perm.mode = (msgflg & 0777);
726 		msqkptr->cred = crhold(cred);
727 		/* Make sure that the returned msqid is unique */
728 		msqkptr->u.msg_perm.seq = (msqkptr->u.msg_perm.seq + 1) & 0x7fff;
729 		msqkptr->u.__msg_first = NULL;
730 		msqkptr->u.__msg_last = NULL;
731 		msqkptr->u.msg_cbytes = 0;
732 		msqkptr->u.msg_qnum = 0;
733 		msqkptr->u.msg_qbytes = msginfo.msgmnb;
734 		msqkptr->u.msg_lspid = 0;
735 		msqkptr->u.msg_lrpid = 0;
736 		msqkptr->u.msg_stime = 0;
737 		msqkptr->u.msg_rtime = 0;
738 		msqkptr->u.msg_ctime = time_second;
739 #ifdef MAC
740 		mac_sysvmsq_create(cred, msqkptr);
741 #endif
742 		AUDIT_ARG_SVIPC_PERM(&msqkptr->u.msg_perm);
743 	} else {
744 		DPRINTF(("didn't find it and wasn't asked to create it\n"));
745 		error = ENOENT;
746 		goto done2;
747 	}
748 
749 found:
750 	/* Construct the unique msqid */
751 	td->td_retval[0] = IXSEQ_TO_IPCID(msqid, msqkptr->u.msg_perm);
752 done2:
753 	mtx_unlock(&msq_mtx);
754 	return (error);
755 }
756 
757 #ifndef _SYS_SYSPROTO_H_
758 struct msgsnd_args {
759 	int	msqid;
760 	const void	*msgp;	/* XXX msgp is actually mtext. */
761 	size_t	msgsz;
762 	int	msgflg;
763 };
764 #endif
765 int
kern_msgsnd(struct thread * td,int msqid,const void * msgp,size_t msgsz,int msgflg,long mtype)766 kern_msgsnd(struct thread *td, int msqid, const void *msgp,
767     size_t msgsz, int msgflg, long mtype)
768 {
769 	int msqix, segs_needed, error = 0;
770 	struct msqid_kernel *msqkptr;
771 	struct msg *msghdr;
772 	struct prison *rpr;
773 	short next;
774 #ifdef RACCT
775 	size_t saved_msgsz = 0;
776 #endif
777 
778 	rpr = msg_find_prison(td->td_ucred);
779 	if (rpr == NULL)
780 		return (ENOSYS);
781 
782 	mtx_lock(&msq_mtx);
783 	AUDIT_ARG_SVIPC_ID(msqid);
784 	msqix = IPCID_TO_IX(msqid);
785 
786 	if (msqix < 0 || msqix >= msginfo.msgmni) {
787 		DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqix,
788 		    msginfo.msgmni));
789 		error = EINVAL;
790 		goto done2;
791 	}
792 
793 	msqkptr = &msqids[msqix];
794 	AUDIT_ARG_SVIPC_PERM(&msqkptr->u.msg_perm);
795 	if (msqkptr->u.msg_qbytes == 0) {
796 		DPRINTF(("no such message queue id\n"));
797 		error = EINVAL;
798 		goto done2;
799 	}
800 	if (msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) {
801 		DPRINTF(("wrong sequence number\n"));
802 		error = EINVAL;
803 		goto done2;
804 	}
805 
806 	if ((error = msq_prison_cansee(rpr, msqkptr))) {
807 		DPRINTF(("requester can't see prison\n"));
808 		goto done2;
809 	}
810 
811 	if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_W))) {
812 		DPRINTF(("requester doesn't have write access\n"));
813 		goto done2;
814 	}
815 
816 #ifdef MAC
817 	error = mac_sysvmsq_check_msqsnd(td->td_ucred, msqkptr);
818 	if (error != 0)
819 		goto done2;
820 #endif
821 
822 #ifdef RACCT
823 	if (racct_enable) {
824 		PROC_LOCK(td->td_proc);
825 		if (racct_add(td->td_proc, RACCT_MSGQQUEUED, 1)) {
826 			PROC_UNLOCK(td->td_proc);
827 			error = EAGAIN;
828 			goto done2;
829 		}
830 		saved_msgsz = msgsz;
831 		if (racct_add(td->td_proc, RACCT_MSGQSIZE, msgsz)) {
832 			racct_sub(td->td_proc, RACCT_MSGQQUEUED, 1);
833 			PROC_UNLOCK(td->td_proc);
834 			error = EAGAIN;
835 			goto done2;
836 		}
837 		PROC_UNLOCK(td->td_proc);
838 	}
839 #endif
840 
841 	segs_needed = howmany(msgsz, msginfo.msgssz);
842 	DPRINTF(("msgsz=%zu, msgssz=%d, segs_needed=%d\n", msgsz,
843 	    msginfo.msgssz, segs_needed));
844 	for (;;) {
845 		int need_more_resources = 0;
846 
847 		/*
848 		 * check msgsz
849 		 * (inside this loop in case msg_qbytes changes while we sleep)
850 		 */
851 
852 		if (msgsz > msqkptr->u.msg_qbytes) {
853 			DPRINTF(("msgsz > msqkptr->u.msg_qbytes\n"));
854 			error = EINVAL;
855 			goto done3;
856 		}
857 
858 		if (msqkptr->u.msg_perm.mode & MSG_LOCKED) {
859 			DPRINTF(("msqid is locked\n"));
860 			need_more_resources = 1;
861 		}
862 		if (msgsz + msqkptr->u.msg_cbytes > msqkptr->u.msg_qbytes) {
863 			DPRINTF(("msgsz + msg_cbytes > msg_qbytes\n"));
864 			need_more_resources = 1;
865 		}
866 		if (segs_needed > nfree_msgmaps) {
867 			DPRINTF(("segs_needed > nfree_msgmaps\n"));
868 			need_more_resources = 1;
869 		}
870 		if (free_msghdrs == NULL) {
871 			DPRINTF(("no more msghdrs\n"));
872 			need_more_resources = 1;
873 		}
874 
875 		if (need_more_resources) {
876 			int we_own_it;
877 
878 			if ((msgflg & IPC_NOWAIT) != 0) {
879 				DPRINTF(("need more resources but caller "
880 				    "doesn't want to wait\n"));
881 				error = EAGAIN;
882 				goto done3;
883 			}
884 
885 			if ((msqkptr->u.msg_perm.mode & MSG_LOCKED) != 0) {
886 				DPRINTF(("we don't own the msqid_ds\n"));
887 				we_own_it = 0;
888 			} else {
889 				/* Force later arrivals to wait for our
890 				   request */
891 				DPRINTF(("we own the msqid_ds\n"));
892 				msqkptr->u.msg_perm.mode |= MSG_LOCKED;
893 				we_own_it = 1;
894 			}
895 			DPRINTF(("msgsnd:  goodnight\n"));
896 			error = msleep(msqkptr, &msq_mtx, (PZERO - 4) | PCATCH,
897 			    "msgsnd", hz);
898 			DPRINTF(("msgsnd:  good morning, error=%d\n", error));
899 			if (we_own_it)
900 				msqkptr->u.msg_perm.mode &= ~MSG_LOCKED;
901 			if (error == EWOULDBLOCK) {
902 				DPRINTF(("msgsnd:  timed out\n"));
903 				continue;
904 			}
905 			if (error != 0) {
906 				DPRINTF(("msgsnd:  interrupted system call\n"));
907 				error = EINTR;
908 				goto done3;
909 			}
910 
911 			/*
912 			 * Make sure that the msq queue still exists
913 			 */
914 
915 			if (msqkptr->u.msg_qbytes == 0) {
916 				DPRINTF(("msqid deleted\n"));
917 				error = EIDRM;
918 				goto done3;
919 			}
920 
921 		} else {
922 			DPRINTF(("got all the resources that we need\n"));
923 			break;
924 		}
925 	}
926 
927 	/*
928 	 * We have the resources that we need.
929 	 * Make sure!
930 	 */
931 
932 	if (msqkptr->u.msg_perm.mode & MSG_LOCKED)
933 		panic("msg_perm.mode & MSG_LOCKED");
934 	if (segs_needed > nfree_msgmaps)
935 		panic("segs_needed > nfree_msgmaps");
936 	if (msgsz + msqkptr->u.msg_cbytes > msqkptr->u.msg_qbytes)
937 		panic("msgsz + msg_cbytes > msg_qbytes");
938 	if (free_msghdrs == NULL)
939 		panic("no more msghdrs");
940 
941 	/*
942 	 * Re-lock the msqid_ds in case we page-fault when copying in the
943 	 * message
944 	 */
945 
946 	if ((msqkptr->u.msg_perm.mode & MSG_LOCKED) != 0)
947 		panic("msqid_ds is already locked");
948 	msqkptr->u.msg_perm.mode |= MSG_LOCKED;
949 
950 	/*
951 	 * Allocate a message header
952 	 */
953 
954 	msghdr = free_msghdrs;
955 	free_msghdrs = msghdr->msg_next;
956 	msghdr->msg_spot = -1;
957 	msghdr->msg_ts = msgsz;
958 	msghdr->msg_type = mtype;
959 #ifdef MAC
960 	/*
961 	 * XXXMAC: Should the mac_sysvmsq_check_msgmsq check follow here
962 	 * immediately?  Or, should it be checked just before the msg is
963 	 * enqueued in the msgq (as it is done now)?
964 	 */
965 	mac_sysvmsg_create(td->td_ucred, msqkptr, msghdr);
966 #endif
967 
968 	/*
969 	 * Allocate space for the message
970 	 */
971 
972 	while (segs_needed > 0) {
973 		if (nfree_msgmaps <= 0)
974 			panic("not enough msgmaps");
975 		if (free_msgmaps == -1)
976 			panic("nil free_msgmaps");
977 		next = free_msgmaps;
978 		if (next <= -1)
979 			panic("next too low #1");
980 		if (next >= msginfo.msgseg)
981 			panic("next out of range #1");
982 		DPRINTF(("allocating segment %d to message\n", next));
983 		free_msgmaps = msgmaps[next].next;
984 		nfree_msgmaps--;
985 		msgmaps[next].next = msghdr->msg_spot;
986 		msghdr->msg_spot = next;
987 		segs_needed--;
988 	}
989 
990 	/*
991 	 * Validate the message type
992 	 */
993 
994 	if (msghdr->msg_type < 1) {
995 		msg_freehdr(msghdr);
996 		msqkptr->u.msg_perm.mode &= ~MSG_LOCKED;
997 		wakeup(msqkptr);
998 		DPRINTF(("mtype (%ld) < 1\n", msghdr->msg_type));
999 		error = EINVAL;
1000 		goto done3;
1001 	}
1002 
1003 	/*
1004 	 * Copy in the message body
1005 	 */
1006 
1007 	next = msghdr->msg_spot;
1008 	while (msgsz > 0) {
1009 		size_t tlen;
1010 		if (msgsz > msginfo.msgssz)
1011 			tlen = msginfo.msgssz;
1012 		else
1013 			tlen = msgsz;
1014 		if (next <= -1)
1015 			panic("next too low #2");
1016 		if (next >= msginfo.msgseg)
1017 			panic("next out of range #2");
1018 		mtx_unlock(&msq_mtx);
1019 		if ((error = copyin(msgp, &msgpool[next * msginfo.msgssz],
1020 		    tlen)) != 0) {
1021 			mtx_lock(&msq_mtx);
1022 			DPRINTF(("error %d copying in message segment\n",
1023 			    error));
1024 			msg_freehdr(msghdr);
1025 			msqkptr->u.msg_perm.mode &= ~MSG_LOCKED;
1026 			wakeup(msqkptr);
1027 			goto done3;
1028 		}
1029 		mtx_lock(&msq_mtx);
1030 		msgsz -= tlen;
1031 		msgp = (const char *)msgp + tlen;
1032 		next = msgmaps[next].next;
1033 	}
1034 	if (next != -1)
1035 		panic("didn't use all the msg segments");
1036 
1037 	/*
1038 	 * We've got the message.  Unlock the msqid_ds.
1039 	 */
1040 
1041 	msqkptr->u.msg_perm.mode &= ~MSG_LOCKED;
1042 
1043 	/*
1044 	 * Make sure that the msqid_ds is still allocated.
1045 	 */
1046 
1047 	if (msqkptr->u.msg_qbytes == 0) {
1048 		msg_freehdr(msghdr);
1049 		wakeup(msqkptr);
1050 		error = EIDRM;
1051 		goto done3;
1052 	}
1053 
1054 #ifdef MAC
1055 	/*
1056 	 * Note: Since the task/thread allocates the msghdr and usually
1057 	 * primes it with its own MAC label, for a majority of policies, it
1058 	 * won't be necessary to check whether the msghdr has access
1059 	 * permissions to the msgq.  The mac_sysvmsq_check_msqsnd check would
1060 	 * suffice in that case.  However, this hook may be required where
1061 	 * individual policies derive a non-identical label for the msghdr
1062 	 * from the current thread label and may want to check the msghdr
1063 	 * enqueue permissions, along with read/write permissions to the
1064 	 * msgq.
1065 	 */
1066 	error = mac_sysvmsq_check_msgmsq(td->td_ucred, msghdr, msqkptr);
1067 	if (error != 0) {
1068 		msg_freehdr(msghdr);
1069 		wakeup(msqkptr);
1070 		goto done3;
1071 	}
1072 #endif
1073 
1074 	/*
1075 	 * Put the message into the queue
1076 	 */
1077 	if (msqkptr->u.__msg_first == NULL) {
1078 		msqkptr->u.__msg_first = msghdr;
1079 		msqkptr->u.__msg_last = msghdr;
1080 	} else {
1081 		msqkptr->u.__msg_last->msg_next = msghdr;
1082 		msqkptr->u.__msg_last = msghdr;
1083 	}
1084 	msqkptr->u.__msg_last->msg_next = NULL;
1085 
1086 	msqkptr->u.msg_cbytes += msghdr->msg_ts;
1087 	msqkptr->u.msg_qnum++;
1088 	msqkptr->u.msg_lspid = td->td_proc->p_pid;
1089 	msqkptr->u.msg_stime = time_second;
1090 
1091 	wakeup(msqkptr);
1092 	td->td_retval[0] = 0;
1093 done3:
1094 #ifdef RACCT
1095 	if (racct_enable && error != 0) {
1096 		PROC_LOCK(td->td_proc);
1097 		racct_sub(td->td_proc, RACCT_MSGQQUEUED, 1);
1098 		racct_sub(td->td_proc, RACCT_MSGQSIZE, saved_msgsz);
1099 		PROC_UNLOCK(td->td_proc);
1100 	}
1101 #endif
1102 done2:
1103 	mtx_unlock(&msq_mtx);
1104 	return (error);
1105 }
1106 
1107 int
sys_msgsnd(struct thread * td,struct msgsnd_args * uap)1108 sys_msgsnd(struct thread *td, struct msgsnd_args *uap)
1109 {
1110 	int error;
1111 	long mtype;
1112 
1113 	DPRINTF(("call to msgsnd(%d, %p, %zu, %d)\n", uap->msqid, uap->msgp,
1114 	    uap->msgsz, uap->msgflg));
1115 
1116 	if ((error = copyin(uap->msgp, &mtype, sizeof(mtype))) != 0) {
1117 		DPRINTF(("error %d copying the message type\n", error));
1118 		return (error);
1119 	}
1120 	return (kern_msgsnd(td, uap->msqid,
1121 	    (const char *)uap->msgp + sizeof(mtype),
1122 	    uap->msgsz, uap->msgflg, mtype));
1123 }
1124 
1125 #ifndef _SYS_SYSPROTO_H_
1126 struct msgrcv_args {
1127 	int	msqid;
1128 	void	*msgp;
1129 	size_t	msgsz;
1130 	long	msgtyp;
1131 	int	msgflg;
1132 };
1133 #endif
1134 /* XXX msgp is actually mtext. */
1135 int
kern_msgrcv(struct thread * td,int msqid,void * msgp,size_t msgsz,long msgtyp,int msgflg,long * mtype)1136 kern_msgrcv(struct thread *td, int msqid, void *msgp, size_t msgsz, long msgtyp,
1137     int msgflg, long *mtype)
1138 {
1139 	size_t len;
1140 	struct msqid_kernel *msqkptr;
1141 	struct msg *msghdr;
1142 	struct prison *rpr;
1143 	int msqix, error = 0;
1144 	short next;
1145 
1146 	rpr = msg_find_prison(td->td_ucred);
1147 	if (rpr == NULL)
1148 		return (ENOSYS);
1149 
1150 	AUDIT_ARG_SVIPC_ID(msqid);
1151 	msqix = IPCID_TO_IX(msqid);
1152 
1153 	if (msqix < 0 || msqix >= msginfo.msgmni) {
1154 		DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqix,
1155 		    msginfo.msgmni));
1156 		return (EINVAL);
1157 	}
1158 
1159 	msqkptr = &msqids[msqix];
1160 	mtx_lock(&msq_mtx);
1161 	AUDIT_ARG_SVIPC_PERM(&msqkptr->u.msg_perm);
1162 	if (msqkptr->u.msg_qbytes == 0) {
1163 		DPRINTF(("no such message queue id\n"));
1164 		error = EINVAL;
1165 		goto done2;
1166 	}
1167 	if (msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) {
1168 		DPRINTF(("wrong sequence number\n"));
1169 		error = EINVAL;
1170 		goto done2;
1171 	}
1172 
1173 	if ((error = msq_prison_cansee(rpr, msqkptr))) {
1174 		DPRINTF(("requester can't see prison\n"));
1175 		goto done2;
1176 	}
1177 
1178 	if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_R))) {
1179 		DPRINTF(("requester doesn't have read access\n"));
1180 		goto done2;
1181 	}
1182 
1183 #ifdef MAC
1184 	error = mac_sysvmsq_check_msqrcv(td->td_ucred, msqkptr);
1185 	if (error != 0)
1186 		goto done2;
1187 #endif
1188 
1189 	msghdr = NULL;
1190 	while (msghdr == NULL) {
1191 		if (msgtyp == 0) {
1192 			msghdr = msqkptr->u.__msg_first;
1193 			if (msghdr != NULL) {
1194 				if (msgsz < msghdr->msg_ts &&
1195 				    (msgflg & MSG_NOERROR) == 0) {
1196 					DPRINTF(("first message on the queue "
1197 					    "is too big (want %zu, got %d)\n",
1198 					    msgsz, msghdr->msg_ts));
1199 					error = E2BIG;
1200 					goto done2;
1201 				}
1202 #ifdef MAC
1203 				error = mac_sysvmsq_check_msgrcv(td->td_ucred,
1204 				    msghdr);
1205 				if (error != 0)
1206 					goto done2;
1207 #endif
1208 				if (msqkptr->u.__msg_first ==
1209 				    msqkptr->u.__msg_last) {
1210 					msqkptr->u.__msg_first = NULL;
1211 					msqkptr->u.__msg_last = NULL;
1212 				} else {
1213 					msqkptr->u.__msg_first = msghdr->msg_next;
1214 					if (msqkptr->u.__msg_first == NULL)
1215 						panic("msg_first/last screwed up #1");
1216 				}
1217 			}
1218 		} else {
1219 			struct msg *previous;
1220 			struct msg **prev;
1221 
1222 			previous = NULL;
1223 			prev = &(msqkptr->u.__msg_first);
1224 			while ((msghdr = *prev) != NULL) {
1225 				/*
1226 				 * Is this message's type an exact match or is
1227 				 * this message's type less than or equal to
1228 				 * the absolute value of a negative msgtyp?
1229 				 * Note that the second half of this test can
1230 				 * NEVER be true if msgtyp is positive since
1231 				 * msg_type is always positive!
1232 				 */
1233 
1234 				if (msgtyp == msghdr->msg_type ||
1235 				    msghdr->msg_type <= -msgtyp) {
1236 					DPRINTF(("found message type %ld, "
1237 					    "requested %ld\n",
1238 					    msghdr->msg_type, msgtyp));
1239 					if (msgsz < msghdr->msg_ts &&
1240 					    (msgflg & MSG_NOERROR) == 0) {
1241 						DPRINTF(("requested message "
1242 						    "on the queue is too big "
1243 						    "(want %zu, got %hu)\n",
1244 						    msgsz, msghdr->msg_ts));
1245 						error = E2BIG;
1246 						goto done2;
1247 					}
1248 #ifdef MAC
1249 					error = mac_sysvmsq_check_msgrcv(
1250 					    td->td_ucred, msghdr);
1251 					if (error != 0)
1252 						goto done2;
1253 #endif
1254 					*prev = msghdr->msg_next;
1255 					if (msghdr == msqkptr->u.__msg_last) {
1256 						if (previous == NULL) {
1257 							if (prev !=
1258 							    &msqkptr->u.__msg_first)
1259 								panic("__msg_first/last screwed up #2");
1260 							msqkptr->u.__msg_first =
1261 							    NULL;
1262 							msqkptr->u.__msg_last =
1263 							    NULL;
1264 						} else {
1265 							if (prev ==
1266 							    &msqkptr->u.__msg_first)
1267 								panic("__msg_first/last screwed up #3");
1268 							msqkptr->u.__msg_last =
1269 							    previous;
1270 						}
1271 					}
1272 					break;
1273 				}
1274 				previous = msghdr;
1275 				prev = &(msghdr->msg_next);
1276 			}
1277 		}
1278 
1279 		/*
1280 		 * We've either extracted the msghdr for the appropriate
1281 		 * message or there isn't one.
1282 		 * If there is one then bail out of this loop.
1283 		 */
1284 
1285 		if (msghdr != NULL)
1286 			break;
1287 
1288 		/*
1289 		 * Hmph!  No message found.  Does the user want to wait?
1290 		 */
1291 
1292 		if ((msgflg & IPC_NOWAIT) != 0) {
1293 			DPRINTF(("no appropriate message found (msgtyp=%ld)\n",
1294 			    msgtyp));
1295 			/* The SVID says to return ENOMSG. */
1296 			error = ENOMSG;
1297 			goto done2;
1298 		}
1299 
1300 		/*
1301 		 * Wait for something to happen
1302 		 */
1303 
1304 		DPRINTF(("msgrcv:  goodnight\n"));
1305 		error = msleep(msqkptr, &msq_mtx, (PZERO - 4) | PCATCH,
1306 		    "msgrcv", 0);
1307 		DPRINTF(("msgrcv:  good morning (error=%d)\n", error));
1308 
1309 		if (error != 0) {
1310 			DPRINTF(("msgrcv:  interrupted system call\n"));
1311 			error = EINTR;
1312 			goto done2;
1313 		}
1314 
1315 		/*
1316 		 * Make sure that the msq queue still exists
1317 		 */
1318 
1319 		if (msqkptr->u.msg_qbytes == 0 ||
1320 		    msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) {
1321 			DPRINTF(("msqid deleted\n"));
1322 			error = EIDRM;
1323 			goto done2;
1324 		}
1325 	}
1326 
1327 	/*
1328 	 * Return the message to the user.
1329 	 *
1330 	 * First, do the bookkeeping (before we risk being interrupted).
1331 	 */
1332 
1333 	msqkptr->u.msg_cbytes -= msghdr->msg_ts;
1334 	msqkptr->u.msg_qnum--;
1335 	msqkptr->u.msg_lrpid = td->td_proc->p_pid;
1336 	msqkptr->u.msg_rtime = time_second;
1337 
1338 	racct_sub_cred(msqkptr->cred, RACCT_MSGQQUEUED, 1);
1339 	racct_sub_cred(msqkptr->cred, RACCT_MSGQSIZE, msghdr->msg_ts);
1340 
1341 	/*
1342 	 * Make msgsz the actual amount that we'll be returning.
1343 	 * Note that this effectively truncates the message if it is too long
1344 	 * (since msgsz is never increased).
1345 	 */
1346 
1347 	DPRINTF(("found a message, msgsz=%zu, msg_ts=%hu\n", msgsz,
1348 	    msghdr->msg_ts));
1349 	if (msgsz > msghdr->msg_ts)
1350 		msgsz = msghdr->msg_ts;
1351 	*mtype = msghdr->msg_type;
1352 
1353 	/*
1354 	 * Return the segments to the user
1355 	 */
1356 
1357 	next = msghdr->msg_spot;
1358 	for (len = 0; len < msgsz; len += msginfo.msgssz) {
1359 		size_t tlen;
1360 
1361 		if (msgsz - len > msginfo.msgssz)
1362 			tlen = msginfo.msgssz;
1363 		else
1364 			tlen = msgsz - len;
1365 		if (next <= -1)
1366 			panic("next too low #3");
1367 		if (next >= msginfo.msgseg)
1368 			panic("next out of range #3");
1369 		mtx_unlock(&msq_mtx);
1370 		error = copyout(&msgpool[next * msginfo.msgssz], msgp, tlen);
1371 		mtx_lock(&msq_mtx);
1372 		if (error != 0) {
1373 			DPRINTF(("error (%d) copying out message segment\n",
1374 			    error));
1375 			msg_freehdr(msghdr);
1376 			wakeup(msqkptr);
1377 			goto done2;
1378 		}
1379 		msgp = (char *)msgp + tlen;
1380 		next = msgmaps[next].next;
1381 	}
1382 
1383 	/*
1384 	 * Done, return the actual number of bytes copied out.
1385 	 */
1386 
1387 	msg_freehdr(msghdr);
1388 	wakeup(msqkptr);
1389 	td->td_retval[0] = msgsz;
1390 done2:
1391 	mtx_unlock(&msq_mtx);
1392 	return (error);
1393 }
1394 
1395 int
sys_msgrcv(struct thread * td,struct msgrcv_args * uap)1396 sys_msgrcv(struct thread *td, struct msgrcv_args *uap)
1397 {
1398 	int error;
1399 	long mtype;
1400 
1401 	DPRINTF(("call to msgrcv(%d, %p, %zu, %ld, %d)\n", uap->msqid,
1402 	    uap->msgp, uap->msgsz, uap->msgtyp, uap->msgflg));
1403 
1404 	if ((error = kern_msgrcv(td, uap->msqid,
1405 	    (char *)uap->msgp + sizeof(mtype), uap->msgsz,
1406 	    uap->msgtyp, uap->msgflg, &mtype)) != 0)
1407 		return (error);
1408 	if ((error = copyout(&mtype, uap->msgp, sizeof(mtype))) != 0)
1409 		DPRINTF(("error %d copying the message type\n", error));
1410 	return (error);
1411 }
1412 
1413 static int
sysctl_msqids(SYSCTL_HANDLER_ARGS)1414 sysctl_msqids(SYSCTL_HANDLER_ARGS)
1415 {
1416 	struct msqid_kernel tmsqk;
1417 #ifdef COMPAT_FREEBSD32
1418 	struct msqid_kernel32 tmsqk32;
1419 #endif
1420 	struct prison *pr, *rpr;
1421 	void *outaddr;
1422 	size_t outsize;
1423 	int error, i;
1424 
1425 	pr = req->td->td_ucred->cr_prison;
1426 	rpr = msg_find_prison(req->td->td_ucred);
1427 	error = 0;
1428 	for (i = 0; i < msginfo.msgmni; i++) {
1429 		mtx_lock(&msq_mtx);
1430 		if (msqids[i].u.msg_qbytes == 0 || rpr == NULL ||
1431 		    msq_prison_cansee(rpr, &msqids[i]) != 0)
1432 			bzero(&tmsqk, sizeof(tmsqk));
1433 		else {
1434 			tmsqk = msqids[i];
1435 			if (tmsqk.cred->cr_prison != pr)
1436 				tmsqk.u.msg_perm.key = IPC_PRIVATE;
1437 		}
1438 		mtx_unlock(&msq_mtx);
1439 #ifdef COMPAT_FREEBSD32
1440 		if (SV_CURPROC_FLAG(SV_ILP32)) {
1441 			bzero(&tmsqk32, sizeof(tmsqk32));
1442 			freebsd32_ipcperm_out(&tmsqk.u.msg_perm,
1443 			    &tmsqk32.u.msg_perm);
1444 			/* Don't copy u.msg_first or u.msg_last */
1445 			CP(tmsqk, tmsqk32, u.msg_cbytes);
1446 			CP(tmsqk, tmsqk32, u.msg_qnum);
1447 			CP(tmsqk, tmsqk32, u.msg_qbytes);
1448 			CP(tmsqk, tmsqk32, u.msg_lspid);
1449 			CP(tmsqk, tmsqk32, u.msg_lrpid);
1450 			CP(tmsqk, tmsqk32, u.msg_stime);
1451 			CP(tmsqk, tmsqk32, u.msg_rtime);
1452 			CP(tmsqk, tmsqk32, u.msg_ctime);
1453 			/* Don't copy label or cred */
1454 			outaddr = &tmsqk32;
1455 			outsize = sizeof(tmsqk32);
1456 		} else
1457 #endif
1458 		{
1459 			/* Don't leak kernel pointers */
1460 			tmsqk.u.__msg_first = NULL;
1461 			tmsqk.u.__msg_last = NULL;
1462 			tmsqk.label = NULL;
1463 			tmsqk.cred = NULL;
1464 			/*
1465 			 * XXX: some padding also exists, but we take care to
1466 			 * allocate our pool of msqid_kernel structs with
1467 			 * zeroed memory so this should be OK.
1468 			 */
1469 			outaddr = &tmsqk;
1470 			outsize = sizeof(tmsqk);
1471 		}
1472 		error = SYSCTL_OUT(req, outaddr, outsize);
1473 		if (error != 0)
1474 			break;
1475 	}
1476 	return (error);
1477 }
1478 
1479 int
kern_get_msqids(struct thread * td,struct msqid_kernel ** res,size_t * sz)1480 kern_get_msqids(struct thread *td, struct msqid_kernel **res, size_t *sz)
1481 {
1482 	struct msqid_kernel *pmsqk;
1483 	struct prison *pr, *rpr;
1484 	int i, mi;
1485 
1486 	*sz = mi = msginfo.msgmni;
1487 	if (res == NULL)
1488 		return (0);
1489 
1490 	pr = td->td_ucred->cr_prison;
1491 	rpr = msg_find_prison(td->td_ucred);
1492 	*res = malloc(sizeof(struct msqid_kernel) * mi, M_TEMP, M_WAITOK);
1493 	for (i = 0; i < mi; i++) {
1494 		pmsqk = &(*res)[i];
1495 		mtx_lock(&msq_mtx);
1496 		if (msqids[i].u.msg_qbytes == 0 || rpr == NULL ||
1497 		    msq_prison_cansee(rpr, &msqids[i]) != 0)
1498 			bzero(pmsqk, sizeof(*pmsqk));
1499 		else {
1500 			*pmsqk = msqids[i];
1501 			if (pmsqk->cred->cr_prison != pr)
1502 				pmsqk->u.msg_perm.key = IPC_PRIVATE;
1503 		}
1504 		mtx_unlock(&msq_mtx);
1505 		pmsqk->u.__msg_first = NULL;
1506 		pmsqk->u.__msg_last = NULL;
1507 		pmsqk->label = NULL;
1508 		pmsqk->cred = NULL;
1509 	}
1510 	return (0);
1511 }
1512 
1513 SYSCTL_INT(_kern_ipc, OID_AUTO, msgmax, CTLFLAG_RD, &msginfo.msgmax, 0,
1514     "Maximum message size");
1515 SYSCTL_INT(_kern_ipc, OID_AUTO, msgmni, CTLFLAG_RDTUN, &msginfo.msgmni, 0,
1516     "Number of message queue identifiers");
1517 SYSCTL_INT(_kern_ipc, OID_AUTO, msgmnb, CTLFLAG_RDTUN, &msginfo.msgmnb, 0,
1518     "Maximum number of bytes in a queue");
1519 SYSCTL_INT(_kern_ipc, OID_AUTO, msgtql, CTLFLAG_RDTUN, &msginfo.msgtql, 0,
1520     "Maximum number of messages in the system");
1521 SYSCTL_INT(_kern_ipc, OID_AUTO, msgssz, CTLFLAG_RDTUN, &msginfo.msgssz, 0,
1522     "Size of a message segment");
1523 SYSCTL_INT(_kern_ipc, OID_AUTO, msgseg, CTLFLAG_RDTUN, &msginfo.msgseg, 0,
1524     "Number of message segments");
1525 SYSCTL_PROC(_kern_ipc, OID_AUTO, msqids,
1526     CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE,
1527     NULL, 0, sysctl_msqids, "",
1528     "Array of struct msqid_kernel for each potential message queue");
1529 
1530 static int
msg_prison_check(void * obj,void * data)1531 msg_prison_check(void *obj, void *data)
1532 {
1533 	struct prison *pr = obj;
1534 	struct prison *prpr;
1535 	struct vfsoptlist *opts = data;
1536 	int error, jsys;
1537 
1538 	/*
1539 	 * sysvmsg is a jailsys integer.
1540 	 * It must be "disable" if the parent jail is disabled.
1541 	 */
1542 	error = vfs_copyopt(opts, "sysvmsg", &jsys, sizeof(jsys));
1543 	if (error != ENOENT) {
1544 		if (error != 0)
1545 			return (error);
1546 		switch (jsys) {
1547 		case JAIL_SYS_DISABLE:
1548 			break;
1549 		case JAIL_SYS_NEW:
1550 		case JAIL_SYS_INHERIT:
1551 			prison_lock(pr->pr_parent);
1552 			prpr = osd_jail_get(pr->pr_parent, msg_prison_slot);
1553 			prison_unlock(pr->pr_parent);
1554 			if (prpr == NULL)
1555 				return (EPERM);
1556 			break;
1557 		default:
1558 			return (EINVAL);
1559 		}
1560 	}
1561 
1562 	return (0);
1563 }
1564 
1565 static int
msg_prison_set(void * obj,void * data)1566 msg_prison_set(void *obj, void *data)
1567 {
1568 	struct prison *pr = obj;
1569 	struct prison *tpr, *orpr, *nrpr, *trpr;
1570 	struct vfsoptlist *opts = data;
1571 	void *rsv;
1572 	int jsys, descend;
1573 
1574 	/*
1575 	 * sysvmsg controls which jail is the root of the associated msgs (this
1576 	 * jail or same as the parent), or if the feature is available at all.
1577 	 */
1578 	if (vfs_copyopt(opts, "sysvmsg", &jsys, sizeof(jsys)) == ENOENT)
1579 		jsys = vfs_flagopt(opts, "allow.sysvipc", NULL, 0)
1580 		    ? JAIL_SYS_INHERIT
1581 		    : vfs_flagopt(opts, "allow.nosysvipc", NULL, 0)
1582 		    ? JAIL_SYS_DISABLE
1583 		    : -1;
1584 	if (jsys == JAIL_SYS_DISABLE) {
1585 		prison_lock(pr);
1586 		orpr = osd_jail_get(pr, msg_prison_slot);
1587 		if (orpr != NULL)
1588 			osd_jail_del(pr, msg_prison_slot);
1589 		prison_unlock(pr);
1590 		if (orpr != NULL) {
1591 			if (orpr == pr)
1592 				msg_prison_cleanup(pr);
1593 			/* Disable all child jails as well. */
1594 			FOREACH_PRISON_DESCENDANT(pr, tpr, descend) {
1595 				prison_lock(tpr);
1596 				trpr = osd_jail_get(tpr, msg_prison_slot);
1597 				if (trpr != NULL) {
1598 					osd_jail_del(tpr, msg_prison_slot);
1599 					prison_unlock(tpr);
1600 					if (trpr == tpr)
1601 						msg_prison_cleanup(tpr);
1602 				} else {
1603 					prison_unlock(tpr);
1604 					descend = 0;
1605 				}
1606 			}
1607 		}
1608 	} else if (jsys != -1) {
1609 		if (jsys == JAIL_SYS_NEW)
1610 			nrpr = pr;
1611 		else {
1612 			prison_lock(pr->pr_parent);
1613 			nrpr = osd_jail_get(pr->pr_parent, msg_prison_slot);
1614 			prison_unlock(pr->pr_parent);
1615 		}
1616 		rsv = osd_reserve(msg_prison_slot);
1617 		prison_lock(pr);
1618 		orpr = osd_jail_get(pr, msg_prison_slot);
1619 		if (orpr != nrpr)
1620 			(void)osd_jail_set_reserved(pr, msg_prison_slot, rsv,
1621 			    nrpr);
1622 		else
1623 			osd_free_reserved(rsv);
1624 		prison_unlock(pr);
1625 		if (orpr != nrpr) {
1626 			if (orpr == pr)
1627 				msg_prison_cleanup(pr);
1628 			if (orpr != NULL) {
1629 				/* Change child jails matching the old root, */
1630 				FOREACH_PRISON_DESCENDANT(pr, tpr, descend) {
1631 					prison_lock(tpr);
1632 					trpr = osd_jail_get(tpr,
1633 					    msg_prison_slot);
1634 					if (trpr == orpr) {
1635 						(void)osd_jail_set(tpr,
1636 						    msg_prison_slot, nrpr);
1637 						prison_unlock(tpr);
1638 						if (trpr == tpr)
1639 							msg_prison_cleanup(tpr);
1640 					} else {
1641 						prison_unlock(tpr);
1642 						descend = 0;
1643 					}
1644 				}
1645 			}
1646 		}
1647 	}
1648 
1649 	return (0);
1650 }
1651 
1652 static int
msg_prison_get(void * obj,void * data)1653 msg_prison_get(void *obj, void *data)
1654 {
1655 	struct prison *pr = obj;
1656 	struct prison *rpr;
1657 	struct vfsoptlist *opts = data;
1658 	int error, jsys;
1659 
1660 	/* Set sysvmsg based on the jail's root prison. */
1661 	prison_lock(pr);
1662 	rpr = osd_jail_get(pr, msg_prison_slot);
1663 	prison_unlock(pr);
1664 	jsys = rpr == NULL ? JAIL_SYS_DISABLE
1665 	    : rpr == pr ? JAIL_SYS_NEW : JAIL_SYS_INHERIT;
1666 	error = vfs_setopt(opts, "sysvmsg", &jsys, sizeof(jsys));
1667 	if (error == ENOENT)
1668 		error = 0;
1669 	return (error);
1670 }
1671 
1672 static int
msg_prison_remove(void * obj,void * data __unused)1673 msg_prison_remove(void *obj, void *data __unused)
1674 {
1675 	struct prison *pr = obj;
1676 	struct prison *rpr;
1677 
1678 	prison_lock(pr);
1679 	rpr = osd_jail_get(pr, msg_prison_slot);
1680 	prison_unlock(pr);
1681 	if (rpr == pr)
1682 		msg_prison_cleanup(pr);
1683 	return (0);
1684 }
1685 
1686 static void
msg_prison_cleanup(struct prison * pr)1687 msg_prison_cleanup(struct prison *pr)
1688 {
1689 	struct msqid_kernel *msqkptr;
1690 	int i;
1691 
1692 	/* Remove any msqs that belong to this jail. */
1693 	mtx_lock(&msq_mtx);
1694 	for (i = 0; i < msginfo.msgmni; i++) {
1695 		msqkptr = &msqids[i];
1696 		if (msqkptr->u.msg_qbytes != 0 &&
1697 		    msqkptr->cred != NULL && msqkptr->cred->cr_prison == pr)
1698 			msq_remove(msqkptr);
1699 	}
1700 	mtx_unlock(&msq_mtx);
1701 }
1702 
1703 SYSCTL_JAIL_PARAM_SYS_NODE(sysvmsg, CTLFLAG_RW, "SYSV message queues");
1704 
1705 #ifdef COMPAT_FREEBSD32
1706 int
freebsd32_msgsys(struct thread * td,struct freebsd32_msgsys_args * uap)1707 freebsd32_msgsys(struct thread *td, struct freebsd32_msgsys_args *uap)
1708 {
1709 
1710 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
1711     defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
1712 	AUDIT_ARG_SVIPC_WHICH(uap->which);
1713 	switch (uap->which) {
1714 	case 0:
1715 		return (freebsd7_freebsd32_msgctl(td,
1716 		    (struct freebsd7_freebsd32_msgctl_args *)&uap->a2));
1717 	case 2:
1718 		return (freebsd32_msgsnd(td,
1719 		    (struct freebsd32_msgsnd_args *)&uap->a2));
1720 	case 3:
1721 		return (freebsd32_msgrcv(td,
1722 		    (struct freebsd32_msgrcv_args *)&uap->a2));
1723 	default:
1724 		return (sys_msgsys(td, (struct msgsys_args *)uap));
1725 	}
1726 #else
1727 	return (nosys(td, NULL));
1728 #endif
1729 }
1730 
1731 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
1732     defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
1733 int
freebsd7_freebsd32_msgctl(struct thread * td,struct freebsd7_freebsd32_msgctl_args * uap)1734 freebsd7_freebsd32_msgctl(struct thread *td,
1735     struct freebsd7_freebsd32_msgctl_args *uap)
1736 {
1737 	struct msqid_ds msqbuf;
1738 	struct msqid_ds_old32 msqbuf32;
1739 	int error;
1740 
1741 	if (uap->cmd == IPC_SET) {
1742 		error = copyin(uap->buf, &msqbuf32, sizeof(msqbuf32));
1743 		if (error)
1744 			return (error);
1745 		freebsd32_ipcperm_old_in(&msqbuf32.msg_perm, &msqbuf.msg_perm);
1746 		PTRIN_CP(msqbuf32, msqbuf, __msg_first);
1747 		PTRIN_CP(msqbuf32, msqbuf, __msg_last);
1748 		CP(msqbuf32, msqbuf, msg_cbytes);
1749 		CP(msqbuf32, msqbuf, msg_qnum);
1750 		CP(msqbuf32, msqbuf, msg_qbytes);
1751 		CP(msqbuf32, msqbuf, msg_lspid);
1752 		CP(msqbuf32, msqbuf, msg_lrpid);
1753 		CP(msqbuf32, msqbuf, msg_stime);
1754 		CP(msqbuf32, msqbuf, msg_rtime);
1755 		CP(msqbuf32, msqbuf, msg_ctime);
1756 	}
1757 	error = kern_msgctl(td, uap->msqid, uap->cmd, &msqbuf);
1758 	if (error)
1759 		return (error);
1760 	if (uap->cmd == IPC_STAT) {
1761 		bzero(&msqbuf32, sizeof(msqbuf32));
1762 		freebsd32_ipcperm_old_out(&msqbuf.msg_perm, &msqbuf32.msg_perm);
1763 		PTROUT_CP(msqbuf, msqbuf32, __msg_first);
1764 		PTROUT_CP(msqbuf, msqbuf32, __msg_last);
1765 		CP(msqbuf, msqbuf32, msg_cbytes);
1766 		CP(msqbuf, msqbuf32, msg_qnum);
1767 		CP(msqbuf, msqbuf32, msg_qbytes);
1768 		CP(msqbuf, msqbuf32, msg_lspid);
1769 		CP(msqbuf, msqbuf32, msg_lrpid);
1770 		CP(msqbuf, msqbuf32, msg_stime);
1771 		CP(msqbuf, msqbuf32, msg_rtime);
1772 		CP(msqbuf, msqbuf32, msg_ctime);
1773 		error = copyout(&msqbuf32, uap->buf, sizeof(struct msqid_ds32));
1774 	}
1775 	return (error);
1776 }
1777 #endif
1778 
1779 int
freebsd32_msgctl(struct thread * td,struct freebsd32_msgctl_args * uap)1780 freebsd32_msgctl(struct thread *td, struct freebsd32_msgctl_args *uap)
1781 {
1782 	struct msqid_ds msqbuf;
1783 	struct msqid_ds32 msqbuf32;
1784 	int error;
1785 
1786 	if (uap->cmd == IPC_SET) {
1787 		error = copyin(uap->buf, &msqbuf32, sizeof(msqbuf32));
1788 		if (error)
1789 			return (error);
1790 		freebsd32_ipcperm_in(&msqbuf32.msg_perm, &msqbuf.msg_perm);
1791 		PTRIN_CP(msqbuf32, msqbuf, __msg_first);
1792 		PTRIN_CP(msqbuf32, msqbuf, __msg_last);
1793 		CP(msqbuf32, msqbuf, msg_cbytes);
1794 		CP(msqbuf32, msqbuf, msg_qnum);
1795 		CP(msqbuf32, msqbuf, msg_qbytes);
1796 		CP(msqbuf32, msqbuf, msg_lspid);
1797 		CP(msqbuf32, msqbuf, msg_lrpid);
1798 		CP(msqbuf32, msqbuf, msg_stime);
1799 		CP(msqbuf32, msqbuf, msg_rtime);
1800 		CP(msqbuf32, msqbuf, msg_ctime);
1801 	}
1802 	error = kern_msgctl(td, uap->msqid, uap->cmd, &msqbuf);
1803 	if (error)
1804 		return (error);
1805 	if (uap->cmd == IPC_STAT) {
1806 		freebsd32_ipcperm_out(&msqbuf.msg_perm, &msqbuf32.msg_perm);
1807 		PTROUT_CP(msqbuf, msqbuf32, __msg_first);
1808 		PTROUT_CP(msqbuf, msqbuf32, __msg_last);
1809 		CP(msqbuf, msqbuf32, msg_cbytes);
1810 		CP(msqbuf, msqbuf32, msg_qnum);
1811 		CP(msqbuf, msqbuf32, msg_qbytes);
1812 		CP(msqbuf, msqbuf32, msg_lspid);
1813 		CP(msqbuf, msqbuf32, msg_lrpid);
1814 		CP(msqbuf, msqbuf32, msg_stime);
1815 		CP(msqbuf, msqbuf32, msg_rtime);
1816 		CP(msqbuf, msqbuf32, msg_ctime);
1817 		error = copyout(&msqbuf32, uap->buf, sizeof(struct msqid_ds32));
1818 	}
1819 	return (error);
1820 }
1821 
1822 int
freebsd32_msgsnd(struct thread * td,struct freebsd32_msgsnd_args * uap)1823 freebsd32_msgsnd(struct thread *td, struct freebsd32_msgsnd_args *uap)
1824 {
1825 	const void *msgp;
1826 	long mtype;
1827 	int32_t mtype32;
1828 	int error;
1829 
1830 	msgp = PTRIN(uap->msgp);
1831 	if ((error = copyin(msgp, &mtype32, sizeof(mtype32))) != 0)
1832 		return (error);
1833 	mtype = mtype32;
1834 	return (kern_msgsnd(td, uap->msqid,
1835 	    (const char *)msgp + sizeof(mtype32),
1836 	    uap->msgsz, uap->msgflg, mtype));
1837 }
1838 
1839 int
freebsd32_msgrcv(struct thread * td,struct freebsd32_msgrcv_args * uap)1840 freebsd32_msgrcv(struct thread *td, struct freebsd32_msgrcv_args *uap)
1841 {
1842 	void *msgp;
1843 	long mtype;
1844 	int32_t mtype32;
1845 	int error;
1846 
1847 	msgp = PTRIN(uap->msgp);
1848 	if ((error = kern_msgrcv(td, uap->msqid,
1849 	    (char *)msgp + sizeof(mtype32), uap->msgsz,
1850 	    uap->msgtyp, uap->msgflg, &mtype)) != 0)
1851 		return (error);
1852 	mtype32 = (int32_t)mtype;
1853 	return (copyout(&mtype32, msgp, sizeof(mtype32)));
1854 }
1855 #endif
1856 
1857 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
1858     defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
1859 
1860 /* XXX casting to (sy_call_t *) is bogus, as usual. */
1861 static sy_call_t *msgcalls[] = {
1862 	(sy_call_t *)freebsd7_msgctl, (sy_call_t *)sys_msgget,
1863 	(sy_call_t *)sys_msgsnd, (sy_call_t *)sys_msgrcv
1864 };
1865 
1866 /*
1867  * Entry point for all MSG calls.
1868  *
1869  * XXX actually varargs.
1870  * struct msgsys_args {
1871  *		int	which;
1872  *		int	a2;
1873  *		int	a3;
1874  *		int	a4;
1875  *		int	a5;
1876  *		int	a6;
1877  *	} *uap;
1878  */
1879 int
sys_msgsys(struct thread * td,struct msgsys_args * uap)1880 sys_msgsys(struct thread *td, struct msgsys_args *uap)
1881 {
1882 	int error;
1883 
1884 	AUDIT_ARG_SVIPC_WHICH(uap->which);
1885 	if (uap->which < 0 || uap->which >= nitems(msgcalls))
1886 		return (EINVAL);
1887 	error = (*msgcalls[uap->which])(td, &uap->a2);
1888 	return (error);
1889 }
1890 
1891 #ifndef CP
1892 #define CP(src, dst, fld)	do { (dst).fld = (src).fld; } while (0)
1893 #endif
1894 
1895 #ifndef _SYS_SYSPROTO_H_
1896 struct freebsd7_msgctl_args {
1897 	int	msqid;
1898 	int	cmd;
1899 	struct	msqid_ds_old *buf;
1900 };
1901 #endif
1902 int
freebsd7_msgctl(struct thread * td,struct freebsd7_msgctl_args * uap)1903 freebsd7_msgctl(struct thread *td, struct freebsd7_msgctl_args *uap)
1904 {
1905 	struct msqid_ds_old msqold;
1906 	struct msqid_ds msqbuf;
1907 	int error;
1908 
1909 	DPRINTF(("call to freebsd7_msgctl(%d, %d, %p)\n", uap->msqid, uap->cmd,
1910 	    uap->buf));
1911 	if (uap->cmd == IPC_SET) {
1912 		error = copyin(uap->buf, &msqold, sizeof(msqold));
1913 		if (error)
1914 			return (error);
1915 		ipcperm_old2new(&msqold.msg_perm, &msqbuf.msg_perm);
1916 		CP(msqold, msqbuf, __msg_first);
1917 		CP(msqold, msqbuf, __msg_last);
1918 		CP(msqold, msqbuf, msg_cbytes);
1919 		CP(msqold, msqbuf, msg_qnum);
1920 		CP(msqold, msqbuf, msg_qbytes);
1921 		CP(msqold, msqbuf, msg_lspid);
1922 		CP(msqold, msqbuf, msg_lrpid);
1923 		CP(msqold, msqbuf, msg_stime);
1924 		CP(msqold, msqbuf, msg_rtime);
1925 		CP(msqold, msqbuf, msg_ctime);
1926 	}
1927 	error = kern_msgctl(td, uap->msqid, uap->cmd, &msqbuf);
1928 	if (error)
1929 		return (error);
1930 	if (uap->cmd == IPC_STAT) {
1931 		bzero(&msqold, sizeof(msqold));
1932 		ipcperm_new2old(&msqbuf.msg_perm, &msqold.msg_perm);
1933 		CP(msqbuf, msqold, __msg_first);
1934 		CP(msqbuf, msqold, __msg_last);
1935 		CP(msqbuf, msqold, msg_cbytes);
1936 		CP(msqbuf, msqold, msg_qnum);
1937 		CP(msqbuf, msqold, msg_qbytes);
1938 		CP(msqbuf, msqold, msg_lspid);
1939 		CP(msqbuf, msqold, msg_lrpid);
1940 		CP(msqbuf, msqold, msg_stime);
1941 		CP(msqbuf, msqold, msg_rtime);
1942 		CP(msqbuf, msqold, msg_ctime);
1943 		error = copyout(&msqold, uap->buf, sizeof(struct msqid_ds_old));
1944 	}
1945 	return (error);
1946 }
1947 
1948 #undef CP
1949 
1950 #endif	/* COMPAT_FREEBSD4 || COMPAT_FREEBSD5 || COMPAT_FREEBSD6 ||
1951 	   COMPAT_FREEBSD7 */
1952