1139804Simp/*-
22729Sdfr * Implementation of SVID messages
32729Sdfr *
42729Sdfr * Author:  Daniel Boulet
52729Sdfr *
62729Sdfr * Copyright 1993 Daniel Boulet and RTMX Inc.
72729Sdfr *
82729Sdfr * This system call was implemented by Daniel Boulet under contract from RTMX.
92729Sdfr *
102729Sdfr * Redistribution and use in source forms, with and without modification,
112729Sdfr * are permitted provided that this entire comment appears intact.
122729Sdfr *
132729Sdfr * Redistribution in binary form may occur without any restrictions.
142729Sdfr * Obviously, it would be nice if you gave credit where credit is due
152729Sdfr * but requiring it would be too onerous.
162729Sdfr *
172729Sdfr * This software is provided ``AS IS'' without any warranties of any kind.
182729Sdfr */
19140614Srwatson/*-
20140614Srwatson * Copyright (c) 2003-2005 McAfee, Inc.
21140614Srwatson * All rights reserved.
22140614Srwatson *
23140614Srwatson * This software was developed for the FreeBSD Project in part by McAfee
24140614Srwatson * Research, the Security Research Division of McAfee, Inc under DARPA/SPAWAR
25140614Srwatson * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS research
26140614Srwatson * program.
27140614Srwatson *
28140614Srwatson * Redistribution and use in source and binary forms, with or without
29140614Srwatson * modification, are permitted provided that the following conditions
30140614Srwatson * are met:
31140614Srwatson * 1. Redistributions of source code must retain the above copyright
32140614Srwatson *    notice, this list of conditions and the following disclaimer.
33140614Srwatson * 2. Redistributions in binary form must reproduce the above copyright
34140614Srwatson *    notice, this list of conditions and the following disclaimer in the
35140614Srwatson *    documentation and/or other materials provided with the distribution.
36140614Srwatson *
37140614Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
38140614Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39140614Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
40140614Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
41140614Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
42140614Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
43140614Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44140614Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
45140614Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46140614Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47140614Srwatson * SUCH DAMAGE.
48140614Srwatson */
492729Sdfr
50116182Sobrien#include <sys/cdefs.h>
51116182Sobrien__FBSDID("$FreeBSD: stable/11/sys/kern/sysv_msg.c 331643 2018-03-27 18:52:27Z dim $");
52116182Sobrien
53194894Sjhb#include "opt_compat.h"
5459839Speter#include "opt_sysvipc.h"
5559839Speter
562729Sdfr#include <sys/param.h>
572729Sdfr#include <sys/systm.h>
5811626Sbde#include <sys/sysproto.h>
592729Sdfr#include <sys/kernel.h>
60164033Srwatson#include <sys/priv.h>
612729Sdfr#include <sys/proc.h>
6282607Sdillon#include <sys/lock.h>
6382607Sdillon#include <sys/mutex.h>
64129882Sphk#include <sys/module.h>
65298585Sjamie#include <sys/mount.h>
662729Sdfr#include <sys/msg.h>
67220398Strasz#include <sys/racct.h>
68298585Sjamie#include <sys/sx.h>
6969449Salfred#include <sys/syscall.h>
70140839Ssobomax#include <sys/syscallsubr.h>
7111626Sbde#include <sys/sysent.h>
7259839Speter#include <sys/sysctl.h>
7359839Speter#include <sys/malloc.h>
7468024Srwatson#include <sys/jail.h>
752729Sdfr
76163606Srwatson#include <security/mac/mac_framework.h>
77163606Srwatson
78219028SnetchildFEATURE(sysv_msg, "System V message queues support");
79219028Snetchild
8059839Speterstatic MALLOC_DEFINE(M_MSG, "msg", "SVID compatible message queues");
8159839Speter
82205323Skibstatic int msginit(void);
8392723Salfredstatic int msgunload(void);
8492723Salfredstatic int sysvmsg_modload(struct module *, int, void *);
85298585Sjamiestatic void msq_remove(struct msqid_kernel *);
86298585Sjamiestatic struct prison *msg_find_prison(struct ucred *);
87298585Sjamiestatic int msq_prison_cansee(struct prison *, struct msqid_kernel *);
88298585Sjamiestatic int msg_prison_check(void *, void *);
89298585Sjamiestatic int msg_prison_set(void *, void *);
90298585Sjamiestatic int msg_prison_get(void *, void *);
91298585Sjamiestatic int msg_prison_remove(void *, void *);
92298585Sjamiestatic void msg_prison_cleanup(struct prison *);
9310358Sjulian
94225617Skmacy
95100523Salfred#ifdef MSG_DEBUG
96100523Salfred#define DPRINTF(a)	printf a
97100523Salfred#else
98194575Srdivacky#define DPRINTF(a)	(void)0
99100523Salfred#endif
1002729Sdfr
10192723Salfredstatic void msg_freehdr(struct msg *msghdr);
1022729Sdfr
10359839Speter#ifndef MSGSSZ
10459839Speter#define MSGSSZ	8		/* Each segment must be 2^N long */
10559839Speter#endif
10659839Speter#ifndef MSGSEG
10759839Speter#define MSGSEG	2048		/* must be less than 32767 */
10859839Speter#endif
10959839Speter#define MSGMAX	(MSGSSZ*MSGSEG)
11059839Speter#ifndef MSGMNB
11159839Speter#define MSGMNB	2048		/* max # of bytes in a queue */
11259839Speter#endif
11359839Speter#ifndef MSGMNI
11459839Speter#define MSGMNI	40
11559839Speter#endif
11659839Speter#ifndef MSGTQL
11759839Speter#define MSGTQL	40
11859839Speter#endif
11959839Speter
12059839Speter/*
12159839Speter * Based on the configuration parameters described in an SVR2 (yes, two)
12259839Speter * config(1m) man page.
12359839Speter *
12459839Speter * Each message is broken up and stored in segments that are msgssz bytes
12559839Speter * long.  For efficiency reasons, this should be a power of two.  Also,
12659839Speter * it doesn't make sense if it is less than 8 or greater than about 256.
12759839Speter * Consequently, msginit in kern/sysv_msg.c checks that msgssz is a power of
12859839Speter * two between 8 and 1024 inclusive (and panic's if it isn't).
12959839Speter */
13059839Speterstruct msginfo msginfo = {
13159839Speter                MSGMAX,         /* max chars in a message */
13259839Speter                MSGMNI,         /* # of message queue identifiers */
13359839Speter                MSGMNB,         /* max chars in a queue */
13459839Speter                MSGTQL,         /* max messages in system */
13559839Speter                MSGSSZ,         /* size of a message segment */
13659839Speter                		/* (must be small power of 2 greater than 4) */
13759839Speter                MSGSEG          /* number of message segments */
13859839Speter};
13959839Speter
14059839Speter/*
14159839Speter * macros to convert between msqid_ds's and msqid's.
14259839Speter * (specific to this implementation)
14359839Speter */
14459839Speter#define MSQID(ix,ds)	((ix) & 0xffff | (((ds).msg_perm.seq << 16) & 0xffff0000))
14559839Speter#define MSQID_IX(id)	((id) & 0xffff)
14659839Speter#define MSQID_SEQ(id)	(((id) >> 16) & 0xffff)
14759839Speter
14859839Speter/*
14959839Speter * The rest of this file is specific to this particular implementation.
15059839Speter */
15159839Speter
15259839Speterstruct msgmap {
15359839Speter	short	next;		/* next segment in buffer */
15459839Speter    				/* -1 -> available */
15559839Speter    				/* 0..(MSGSEG-1) -> index of next segment */
15659839Speter};
15759839Speter
15859839Speter#define MSG_LOCKED	01000	/* Is this msqid_ds locked? */
15959839Speter
16012819Sphkstatic int nfree_msgmaps;	/* # of free map entries */
16112819Sphkstatic short free_msgmaps;	/* head of linked list of free map entries */
16259839Speterstatic struct msg *free_msghdrs;/* list of free msg headers */
16359839Speterstatic char *msgpool;		/* MSGMAX byte long msg buffer pool */
16459839Speterstatic struct msgmap *msgmaps;	/* MSGSEG msgmap structures */
16559839Speterstatic struct msg *msghdrs;	/* MSGTQL msg headers */
166137613Srwatsonstatic struct msqid_kernel *msqids;	/* MSGMNI msqid_kernel struct's */
167101772Salfredstatic struct mtx msq_mtx;	/* global mutex for message queues. */
168298585Sjamiestatic unsigned msg_prison_slot;/* prison OSD slot */
1692729Sdfr
170205323Skibstatic struct syscall_helper_data msg_syscalls[] = {
171205323Skib	SYSCALL_INIT_HELPER(msgctl),
172205323Skib	SYSCALL_INIT_HELPER(msgget),
173205323Skib	SYSCALL_INIT_HELPER(msgsnd),
174205323Skib	SYSCALL_INIT_HELPER(msgrcv),
175205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
176205323Skib    defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
177205323Skib	SYSCALL_INIT_HELPER(msgsys),
178225617Skmacy	SYSCALL_INIT_HELPER_COMPAT(freebsd7_msgctl),
179205323Skib#endif
180205323Skib	SYSCALL_INIT_LAST
181205323Skib};
182205323Skib
183205323Skib#ifdef COMPAT_FREEBSD32
184205323Skib#include <compat/freebsd32/freebsd32.h>
185205323Skib#include <compat/freebsd32/freebsd32_ipc.h>
186205323Skib#include <compat/freebsd32/freebsd32_proto.h>
187205323Skib#include <compat/freebsd32/freebsd32_signal.h>
188205323Skib#include <compat/freebsd32/freebsd32_syscall.h>
189205323Skib#include <compat/freebsd32/freebsd32_util.h>
190205323Skib
191205323Skibstatic struct syscall_helper_data msg32_syscalls[] = {
192205323Skib	SYSCALL32_INIT_HELPER(freebsd32_msgctl),
193205323Skib	SYSCALL32_INIT_HELPER(freebsd32_msgsnd),
194205323Skib	SYSCALL32_INIT_HELPER(freebsd32_msgrcv),
195225617Skmacy	SYSCALL32_INIT_HELPER_COMPAT(msgget),
196205323Skib	SYSCALL32_INIT_HELPER(freebsd32_msgsys),
197205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
198205323Skib    defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
199205323Skib	SYSCALL32_INIT_HELPER(freebsd7_freebsd32_msgctl),
200205323Skib#endif
201205323Skib	SYSCALL_INIT_LAST
202205323Skib};
203205323Skib#endif
204205323Skib
205205323Skibstatic int
20669449Salfredmsginit()
2072729Sdfr{
208298585Sjamie	struct prison *pr;
209298661Scem	void **rsv;
210205323Skib	int i, error;
211298585Sjamie	osd_method_t methods[PR_MAXMETHOD] = {
212298585Sjamie	    [PR_METHOD_CHECK] =		msg_prison_check,
213298585Sjamie	    [PR_METHOD_SET] =		msg_prison_set,
214298585Sjamie	    [PR_METHOD_GET] =		msg_prison_get,
215298585Sjamie	    [PR_METHOD_REMOVE] =	msg_prison_remove,
216298585Sjamie	};
2172729Sdfr
21883765Smr	msginfo.msgmax = msginfo.msgseg * msginfo.msgssz;
219111119Simp	msgpool = malloc(msginfo.msgmax, M_MSG, M_WAITOK);
220111119Simp	msgmaps = malloc(sizeof(struct msgmap) * msginfo.msgseg, M_MSG, M_WAITOK);
221111119Simp	msghdrs = malloc(sizeof(struct msg) * msginfo.msgtql, M_MSG, M_WAITOK);
222137613Srwatson	msqids = malloc(sizeof(struct msqid_kernel) * msginfo.msgmni, M_MSG,
223329177Sbrooks	    M_WAITOK | M_ZERO);
22459839Speter
2252729Sdfr	/*
2262729Sdfr	 * msginfo.msgssz should be a power of two for efficiency reasons.
2272729Sdfr	 * It is also pretty silly if msginfo.msgssz is less than 8
2282729Sdfr	 * or greater than about 256 so ...
2292729Sdfr	 */
2302729Sdfr
2312729Sdfr	i = 8;
2322729Sdfr	while (i < 1024 && i != msginfo.msgssz)
2332729Sdfr		i <<= 1;
2342729Sdfr    	if (i != msginfo.msgssz) {
235100523Salfred		DPRINTF(("msginfo.msgssz=%d (0x%x)\n", msginfo.msgssz,
236100523Salfred		    msginfo.msgssz));
2372729Sdfr		panic("msginfo.msgssz not a small power of 2");
2382729Sdfr	}
2392729Sdfr
2402729Sdfr	if (msginfo.msgseg > 32767) {
241100523Salfred		DPRINTF(("msginfo.msgseg=%d\n", msginfo.msgseg));
2422729Sdfr		panic("msginfo.msgseg > 32767");
2432729Sdfr	}
2442729Sdfr
2452729Sdfr	for (i = 0; i < msginfo.msgseg; i++) {
2462729Sdfr		if (i > 0)
2472729Sdfr			msgmaps[i-1].next = i;
2482729Sdfr		msgmaps[i].next = -1;	/* implies entry is available */
2492729Sdfr	}
2502729Sdfr	free_msgmaps = 0;
2512729Sdfr	nfree_msgmaps = msginfo.msgseg;
2522729Sdfr
2532729Sdfr	for (i = 0; i < msginfo.msgtql; i++) {
2542729Sdfr		msghdrs[i].msg_type = 0;
2552729Sdfr		if (i > 0)
2562729Sdfr			msghdrs[i-1].msg_next = &msghdrs[i];
2572729Sdfr		msghdrs[i].msg_next = NULL;
258140614Srwatson#ifdef MAC
259172930Srwatson		mac_sysvmsg_init(&msghdrs[i]);
260140614Srwatson#endif
2612729Sdfr    	}
2622729Sdfr	free_msghdrs = &msghdrs[0];
2632729Sdfr
2642729Sdfr	for (i = 0; i < msginfo.msgmni; i++) {
265137613Srwatson		msqids[i].u.msg_qbytes = 0;	/* implies entry is available */
266137613Srwatson		msqids[i].u.msg_perm.seq = 0;	/* reset to a known value */
267137613Srwatson		msqids[i].u.msg_perm.mode = 0;
268140614Srwatson#ifdef MAC
269172930Srwatson		mac_sysvmsq_init(&msqids[i]);
270140614Srwatson#endif
2712729Sdfr	}
272101772Salfred	mtx_init(&msq_mtx, "msq", NULL, MTX_DEF);
273205323Skib
274298585Sjamie	/* Set current prisons according to their allow.sysvipc. */
275298585Sjamie	msg_prison_slot = osd_jail_register(NULL, methods);
276298585Sjamie	rsv = osd_reserve(msg_prison_slot);
277298585Sjamie	prison_lock(&prison0);
278298585Sjamie	(void)osd_jail_set_reserved(&prison0, msg_prison_slot, rsv, &prison0);
279298585Sjamie	prison_unlock(&prison0);
280298585Sjamie	rsv = NULL;
281298585Sjamie	sx_slock(&allprison_lock);
282298585Sjamie	TAILQ_FOREACH(pr, &allprison, pr_list) {
283298585Sjamie		if (rsv == NULL)
284298585Sjamie			rsv = osd_reserve(msg_prison_slot);
285298585Sjamie		prison_lock(pr);
286298585Sjamie		if ((pr->pr_allow & PR_ALLOW_SYSVIPC) && pr->pr_ref > 0) {
287298585Sjamie			(void)osd_jail_set_reserved(pr, msg_prison_slot, rsv,
288298585Sjamie			    &prison0);
289298585Sjamie			rsv = NULL;
290298585Sjamie		}
291298585Sjamie		prison_unlock(pr);
292298585Sjamie	}
293298585Sjamie	if (rsv != NULL)
294298585Sjamie		osd_free_reserved(rsv);
295298585Sjamie	sx_sunlock(&allprison_lock);
296298585Sjamie
297273707Smjg	error = syscall_helper_register(msg_syscalls, SY_THR_STATIC_KLD);
298205323Skib	if (error != 0)
299205323Skib		return (error);
300205323Skib#ifdef COMPAT_FREEBSD32
301273707Smjg	error = syscall32_helper_register(msg32_syscalls, SY_THR_STATIC_KLD);
302205323Skib	if (error != 0)
303205323Skib		return (error);
304205323Skib#endif
305205323Skib	return (0);
3062729Sdfr}
3072729Sdfr
30869449Salfredstatic int
30969449Salfredmsgunload()
31069449Salfred{
311137613Srwatson	struct msqid_kernel *msqkptr;
31269449Salfred	int msqid;
313140614Srwatson#ifdef MAC
314140614Srwatson	int i;
315140614Srwatson#endif
31669449Salfred
317205323Skib	syscall_helper_unregister(msg_syscalls);
318205323Skib#ifdef COMPAT_FREEBSD32
319205323Skib	syscall32_helper_unregister(msg32_syscalls);
320205323Skib#endif
321205323Skib
32269449Salfred	for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
323137613Srwatson		msqkptr = &msqids[msqid];
324137613Srwatson		if (msqkptr->u.msg_qbytes != 0 ||
325137613Srwatson		    (msqkptr->u.msg_perm.mode & MSG_LOCKED) != 0)
32669449Salfred			break;
32769449Salfred	}
32869449Salfred	if (msqid != msginfo.msgmni)
32969449Salfred		return (EBUSY);
33069449Salfred
331298585Sjamie	if (msg_prison_slot != 0)
332298585Sjamie		osd_jail_deregister(msg_prison_slot);
333140614Srwatson#ifdef MAC
334140614Srwatson	for (i = 0; i < msginfo.msgtql; i++)
335172930Srwatson		mac_sysvmsg_destroy(&msghdrs[i]);
336140614Srwatson	for (msqid = 0; msqid < msginfo.msgmni; msqid++)
337172930Srwatson		mac_sysvmsq_destroy(&msqids[msqid]);
338140614Srwatson#endif
33969449Salfred	free(msgpool, M_MSG);
34069449Salfred	free(msgmaps, M_MSG);
34169449Salfred	free(msghdrs, M_MSG);
34269449Salfred	free(msqids, M_MSG);
343101772Salfred	mtx_destroy(&msq_mtx);
34469449Salfred	return (0);
34569449Salfred}
34669449Salfred
34769449Salfred
34869449Salfredstatic int
34969449Salfredsysvmsg_modload(struct module *module, int cmd, void *arg)
35069449Salfred{
35169449Salfred	int error = 0;
35269449Salfred
35369449Salfred	switch (cmd) {
35469449Salfred	case MOD_LOAD:
355205323Skib		error = msginit();
356205323Skib		if (error != 0)
357205323Skib			msgunload();
35869449Salfred		break;
35969449Salfred	case MOD_UNLOAD:
36069449Salfred		error = msgunload();
36169449Salfred		break;
36269449Salfred	case MOD_SHUTDOWN:
36369449Salfred		break;
36469449Salfred	default:
36569449Salfred		error = EINVAL;
36669449Salfred		break;
36769449Salfred	}
36869449Salfred	return (error);
36969449Salfred}
37069449Salfred
37171038Sdesstatic moduledata_t sysvmsg_mod = {
37271038Sdes	"sysvmsg",
37369449Salfred	&sysvmsg_modload,
37469449Salfred	NULL
37569449Salfred};
37669449Salfred
377194832SjhbDECLARE_MODULE(sysvmsg, sysvmsg_mod, SI_SUB_SYSV_MSG, SI_ORDER_FIRST);
37871038SdesMODULE_VERSION(sysvmsg, 1);
37969449Salfred
3802729Sdfrstatic void
3812729Sdfrmsg_freehdr(msghdr)
3822729Sdfr	struct msg *msghdr;
3832729Sdfr{
3842729Sdfr	while (msghdr->msg_ts > 0) {
3852729Sdfr		short next;
3862729Sdfr		if (msghdr->msg_spot < 0 || msghdr->msg_spot >= msginfo.msgseg)
3872729Sdfr			panic("msghdr->msg_spot out of range");
3882729Sdfr		next = msgmaps[msghdr->msg_spot].next;
3892729Sdfr		msgmaps[msghdr->msg_spot].next = free_msgmaps;
3902729Sdfr		free_msgmaps = msghdr->msg_spot;
3912729Sdfr		nfree_msgmaps++;
3922729Sdfr		msghdr->msg_spot = next;
3932729Sdfr		if (msghdr->msg_ts >= msginfo.msgssz)
3942729Sdfr			msghdr->msg_ts -= msginfo.msgssz;
3952729Sdfr		else
3962729Sdfr			msghdr->msg_ts = 0;
3972729Sdfr	}
3982729Sdfr	if (msghdr->msg_spot != -1)
3992729Sdfr		panic("msghdr->msg_spot != -1");
4002729Sdfr	msghdr->msg_next = free_msghdrs;
4012729Sdfr	free_msghdrs = msghdr;
402140614Srwatson#ifdef MAC
403172930Srwatson	mac_sysvmsg_cleanup(msghdr);
404140614Srwatson#endif
4052729Sdfr}
4062729Sdfr
407298585Sjamiestatic void
408298585Sjamiemsq_remove(struct msqid_kernel *msqkptr)
409298585Sjamie{
410298585Sjamie	struct msg *msghdr;
411298585Sjamie
412298585Sjamie	racct_sub_cred(msqkptr->cred, RACCT_NMSGQ, 1);
413298585Sjamie	racct_sub_cred(msqkptr->cred, RACCT_MSGQQUEUED, msqkptr->u.msg_qnum);
414298585Sjamie	racct_sub_cred(msqkptr->cred, RACCT_MSGQSIZE, msqkptr->u.msg_cbytes);
415298585Sjamie	crfree(msqkptr->cred);
416298585Sjamie	msqkptr->cred = NULL;
417298585Sjamie
418298585Sjamie	/* Free the message headers */
419298585Sjamie	msghdr = msqkptr->u.msg_first;
420298585Sjamie	while (msghdr != NULL) {
421298585Sjamie		struct msg *msghdr_tmp;
422298585Sjamie
423298585Sjamie		/* Free the segments of each message */
424298585Sjamie		msqkptr->u.msg_cbytes -= msghdr->msg_ts;
425298585Sjamie		msqkptr->u.msg_qnum--;
426298585Sjamie		msghdr_tmp = msghdr;
427298585Sjamie		msghdr = msghdr->msg_next;
428298585Sjamie		msg_freehdr(msghdr_tmp);
429298585Sjamie	}
430298585Sjamie
431298585Sjamie	if (msqkptr->u.msg_cbytes != 0)
432298585Sjamie		panic("msg_cbytes is screwed up");
433298585Sjamie	if (msqkptr->u.msg_qnum != 0)
434298585Sjamie		panic("msg_qnum is screwed up");
435298585Sjamie
436298585Sjamie	msqkptr->u.msg_qbytes = 0;	/* Mark it as free */
437298585Sjamie
438298585Sjamie#ifdef MAC
439298585Sjamie	mac_sysvmsq_cleanup(msqkptr);
440298585Sjamie#endif
441298585Sjamie
442298585Sjamie	wakeup(msqkptr);
443298585Sjamie}
444298585Sjamie
445298585Sjamiestatic struct prison *
446298585Sjamiemsg_find_prison(struct ucred *cred)
447298585Sjamie{
448298585Sjamie	struct prison *pr, *rpr;
449298585Sjamie
450298585Sjamie	pr = cred->cr_prison;
451298585Sjamie	prison_lock(pr);
452298585Sjamie	rpr = osd_jail_get(pr, msg_prison_slot);
453298585Sjamie	prison_unlock(pr);
454298585Sjamie	return rpr;
455298585Sjamie}
456298585Sjamie
457298585Sjamiestatic int
458298585Sjamiemsq_prison_cansee(struct prison *rpr, struct msqid_kernel *msqkptr)
459298585Sjamie{
460298585Sjamie
461298585Sjamie	if (msqkptr->cred == NULL ||
462298585Sjamie	    !(rpr == msqkptr->cred->cr_prison ||
463298585Sjamie	      prison_ischild(rpr, msqkptr->cred->cr_prison)))
464298585Sjamie		return (EINVAL);
465298585Sjamie	return (0);
466298585Sjamie}
467298585Sjamie
46812866Speter#ifndef _SYS_SYSPROTO_H_
4692729Sdfrstruct msgctl_args {
4702729Sdfr	int	msqid;
4712729Sdfr	int	cmd;
47212866Speter	struct	msqid_ds *buf;
4732729Sdfr};
47412866Speter#endif
47512866Speterint
476331643Sdimsys_msgctl(struct thread *td, struct msgctl_args *uap)
4772729Sdfr{
4782729Sdfr	int msqid = uap->msqid;
4792729Sdfr	int cmd = uap->cmd;
4802729Sdfr	struct msqid_ds msqbuf;
481140839Ssobomax	int error;
482140839Ssobomax
483165403Sjkim	DPRINTF(("call to msgctl(%d, %d, %p)\n", msqid, cmd, uap->buf));
484140839Ssobomax	if (cmd == IPC_SET &&
485140839Ssobomax	    (error = copyin(uap->buf, &msqbuf, sizeof(msqbuf))) != 0)
486140839Ssobomax		return (error);
487141471Sjhb	error = kern_msgctl(td, msqid, cmd, &msqbuf);
488140839Ssobomax	if (cmd == IPC_STAT && error == 0)
489141471Sjhb		error = copyout(&msqbuf, uap->buf, sizeof(struct msqid_ds));
490140839Ssobomax	return (error);
491140839Ssobomax}
492140839Ssobomax
493140839Ssobomaxint
494141471Sjhbkern_msgctl(td, msqid, cmd, msqbuf)
495140839Ssobomax	struct thread *td;
496140839Ssobomax	int msqid;
497140839Ssobomax	int cmd;
498140839Ssobomax	struct msqid_ds *msqbuf;
499140839Ssobomax{
500140839Ssobomax	int rval, error, msqix;
501331643Sdim	struct msqid_kernel *msqkptr;
502298585Sjamie	struct prison *rpr;
5032729Sdfr
504298585Sjamie	rpr = msg_find_prison(td->td_ucred);
505298585Sjamie	if (rpr == NULL)
50691703Sjhb		return (ENOSYS);
50791703Sjhb
508140839Ssobomax	msqix = IPCID_TO_IX(msqid);
5092729Sdfr
510140839Ssobomax	if (msqix < 0 || msqix >= msginfo.msgmni) {
511140839Ssobomax		DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqix,
512100523Salfred		    msginfo.msgmni));
513101772Salfred		return (EINVAL);
5142729Sdfr	}
5152729Sdfr
516140839Ssobomax	msqkptr = &msqids[msqix];
5172729Sdfr
518101772Salfred	mtx_lock(&msq_mtx);
519137613Srwatson	if (msqkptr->u.msg_qbytes == 0) {
520100523Salfred		DPRINTF(("no such msqid\n"));
52182607Sdillon		error = EINVAL;
52282607Sdillon		goto done2;
5232729Sdfr	}
524140839Ssobomax	if (msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) {
525100523Salfred		DPRINTF(("wrong sequence number\n"));
52682607Sdillon		error = EINVAL;
52782607Sdillon		goto done2;
5282729Sdfr	}
529298585Sjamie
530298585Sjamie	error = msq_prison_cansee(rpr, msqkptr);
531298585Sjamie	if (error != 0) {
532298585Sjamie		DPRINTF(("requester can't see prison\n"));
533298585Sjamie		goto done2;
534298585Sjamie	}
535298585Sjamie
536140614Srwatson#ifdef MAC
537172930Srwatson	error = mac_sysvmsq_check_msqctl(td->td_ucred, msqkptr, cmd);
538162468Srwatson	if (error != 0)
539140614Srwatson		goto done2;
540140614Srwatson#endif
5412729Sdfr
54282607Sdillon	error = 0;
5432729Sdfr	rval = 0;
5442729Sdfr
5452729Sdfr	switch (cmd) {
5462729Sdfr
5472729Sdfr	case IPC_RMID:
5482729Sdfr	{
549298585Sjamie#ifdef MAC
5502729Sdfr		struct msg *msghdr;
551298585Sjamie#endif
552137613Srwatson		if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_M)))
55382607Sdillon			goto done2;
554137613Srwatson
555140614Srwatson#ifdef MAC
556140614Srwatson		/*
557140614Srwatson		 * Check that the thread has MAC access permissions to
558140614Srwatson		 * individual msghdrs.  Note: We need to do this in a
559140614Srwatson		 * separate loop because the actual loop alters the
560140614Srwatson		 * msq/msghdr info as it progresses, and there is no going
561140614Srwatson		 * back if half the way through we discover that the
562140614Srwatson		 * thread cannot free a certain msghdr.  The msq will get
563140614Srwatson		 * into an inconsistent state.
564140614Srwatson		 */
565140614Srwatson		for (msghdr = msqkptr->u.msg_first; msghdr != NULL;
566140614Srwatson		    msghdr = msghdr->msg_next) {
567172930Srwatson			error = mac_sysvmsq_check_msgrmid(td->td_ucred, msghdr);
568162468Srwatson			if (error != 0)
569140614Srwatson				goto done2;
570140614Srwatson		}
571140614Srwatson#endif
572140614Srwatson
573298585Sjamie		msq_remove(msqkptr);
5742729Sdfr	}
5752729Sdfr
5762729Sdfr		break;
5772729Sdfr
5782729Sdfr	case IPC_SET:
579137613Srwatson		if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_M)))
58082607Sdillon			goto done2;
581140839Ssobomax		if (msqbuf->msg_qbytes > msqkptr->u.msg_qbytes) {
582170587Srwatson			error = priv_check(td, PRIV_IPC_MSGSIZE);
58382607Sdillon			if (error)
58482607Sdillon				goto done2;
58543426Sphk		}
586140839Ssobomax		if (msqbuf->msg_qbytes > msginfo.msgmnb) {
587100523Salfred			DPRINTF(("can't increase msg_qbytes beyond %d"
588100523Salfred			    "(truncating)\n", msginfo.msgmnb));
589140839Ssobomax			msqbuf->msg_qbytes = msginfo.msgmnb;	/* silently restrict qbytes to system limit */
5902729Sdfr		}
591140839Ssobomax		if (msqbuf->msg_qbytes == 0) {
592100523Salfred			DPRINTF(("can't reduce msg_qbytes to 0\n"));
59382607Sdillon			error = EINVAL;		/* non-standard errno! */
59482607Sdillon			goto done2;
5952729Sdfr		}
596140839Ssobomax		msqkptr->u.msg_perm.uid = msqbuf->msg_perm.uid;	/* change the owner */
597140839Ssobomax		msqkptr->u.msg_perm.gid = msqbuf->msg_perm.gid;	/* change the owner */
598137613Srwatson		msqkptr->u.msg_perm.mode = (msqkptr->u.msg_perm.mode & ~0777) |
599140839Ssobomax		    (msqbuf->msg_perm.mode & 0777);
600140839Ssobomax		msqkptr->u.msg_qbytes = msqbuf->msg_qbytes;
601137613Srwatson		msqkptr->u.msg_ctime = time_second;
6022729Sdfr		break;
6032729Sdfr
6042729Sdfr	case IPC_STAT:
605137613Srwatson		if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_R))) {
606100523Salfred			DPRINTF(("requester doesn't have read access\n"));
60782607Sdillon			goto done2;
6082729Sdfr		}
609141471Sjhb		*msqbuf = msqkptr->u;
610298585Sjamie		if (td->td_ucred->cr_prison != msqkptr->cred->cr_prison)
611298585Sjamie			msqbuf->msg_perm.key = IPC_PRIVATE;
6122729Sdfr		break;
6132729Sdfr
6142729Sdfr	default:
615100523Salfred		DPRINTF(("invalid command %d\n", cmd));
61682607Sdillon		error = EINVAL;
61782607Sdillon		goto done2;
6182729Sdfr	}
6192729Sdfr
62082607Sdillon	if (error == 0)
62183366Sjulian		td->td_retval[0] = rval;
62282607Sdillondone2:
623101772Salfred	mtx_unlock(&msq_mtx);
624141471Sjhb	return (error);
6252729Sdfr}
6262729Sdfr
62712866Speter#ifndef _SYS_SYSPROTO_H_
6282729Sdfrstruct msgget_args {
6292729Sdfr	key_t	key;
6302729Sdfr	int	msgflg;
6312729Sdfr};
63212866Speter#endif
633225617Skmacy
63412866Speterint
635331643Sdimsys_msgget(struct thread *td, struct msgget_args *uap)
6362729Sdfr{
63782607Sdillon	int msqid, error = 0;
6382729Sdfr	int key = uap->key;
6392729Sdfr	int msgflg = uap->msgflg;
64091703Sjhb	struct ucred *cred = td->td_ucred;
641331643Sdim	struct msqid_kernel *msqkptr = NULL;
6422729Sdfr
643100523Salfred	DPRINTF(("msgget(0x%x, 0%o)\n", key, msgflg));
6442729Sdfr
645298585Sjamie	if (msg_find_prison(cred) == NULL)
64691703Sjhb		return (ENOSYS);
64791703Sjhb
648101772Salfred	mtx_lock(&msq_mtx);
6492729Sdfr	if (key != IPC_PRIVATE) {
6502729Sdfr		for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
651137613Srwatson			msqkptr = &msqids[msqid];
652137613Srwatson			if (msqkptr->u.msg_qbytes != 0 &&
653298585Sjamie			    msqkptr->cred != NULL &&
654298585Sjamie			    msqkptr->cred->cr_prison == cred->cr_prison &&
655137613Srwatson			    msqkptr->u.msg_perm.key == key)
6562729Sdfr				break;
6572729Sdfr		}
6582729Sdfr		if (msqid < msginfo.msgmni) {
659100523Salfred			DPRINTF(("found public key\n"));
6602729Sdfr			if ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL)) {
661100523Salfred				DPRINTF(("not exclusive\n"));
66282607Sdillon				error = EEXIST;
66382607Sdillon				goto done2;
6642729Sdfr			}
665137613Srwatson			if ((error = ipcperm(td, &msqkptr->u.msg_perm,
666137613Srwatson			    msgflg & 0700))) {
667100523Salfred				DPRINTF(("requester doesn't have 0%o access\n",
668100523Salfred				    msgflg & 0700));
66982607Sdillon				goto done2;
6702729Sdfr			}
671140614Srwatson#ifdef MAC
672172930Srwatson			error = mac_sysvmsq_check_msqget(cred, msqkptr);
673162468Srwatson			if (error != 0)
674140614Srwatson				goto done2;
675140614Srwatson#endif
6762729Sdfr			goto found;
6772729Sdfr		}
6782729Sdfr	}
6792729Sdfr
680100523Salfred	DPRINTF(("need to allocate the msqid_ds\n"));
6812729Sdfr	if (key == IPC_PRIVATE || (msgflg & IPC_CREAT)) {
6822729Sdfr		for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
6832729Sdfr			/*
6842729Sdfr			 * Look for an unallocated and unlocked msqid_ds.
6852729Sdfr			 * msqid_ds's can be locked by msgsnd or msgrcv while
6862729Sdfr			 * they are copying the message in/out.  We can't
6872729Sdfr			 * re-use the entry until they release it.
6882729Sdfr			 */
689137613Srwatson			msqkptr = &msqids[msqid];
690137613Srwatson			if (msqkptr->u.msg_qbytes == 0 &&
691137613Srwatson			    (msqkptr->u.msg_perm.mode & MSG_LOCKED) == 0)
6922729Sdfr				break;
6932729Sdfr		}
6942729Sdfr		if (msqid == msginfo.msgmni) {
695100523Salfred			DPRINTF(("no more msqid_ds's available\n"));
69682607Sdillon			error = ENOSPC;
69782607Sdillon			goto done2;
6982729Sdfr		}
699223825Strasz#ifdef RACCT
700282213Strasz		if (racct_enable) {
701282213Strasz			PROC_LOCK(td->td_proc);
702282213Strasz			error = racct_add(td->td_proc, RACCT_NMSGQ, 1);
703282213Strasz			PROC_UNLOCK(td->td_proc);
704282213Strasz			if (error != 0) {
705282213Strasz				error = ENOSPC;
706282213Strasz				goto done2;
707282213Strasz			}
708220398Strasz		}
709223825Strasz#endif
710100523Salfred		DPRINTF(("msqid %d is available\n", msqid));
711137613Srwatson		msqkptr->u.msg_perm.key = key;
712137613Srwatson		msqkptr->u.msg_perm.cuid = cred->cr_uid;
713137613Srwatson		msqkptr->u.msg_perm.uid = cred->cr_uid;
714137613Srwatson		msqkptr->u.msg_perm.cgid = cred->cr_gid;
715137613Srwatson		msqkptr->u.msg_perm.gid = cred->cr_gid;
716137613Srwatson		msqkptr->u.msg_perm.mode = (msgflg & 0777);
717220399Strasz		msqkptr->cred = crhold(cred);
7182729Sdfr		/* Make sure that the returned msqid is unique */
719137613Srwatson		msqkptr->u.msg_perm.seq = (msqkptr->u.msg_perm.seq + 1) & 0x7fff;
720137613Srwatson		msqkptr->u.msg_first = NULL;
721137613Srwatson		msqkptr->u.msg_last = NULL;
722137613Srwatson		msqkptr->u.msg_cbytes = 0;
723137613Srwatson		msqkptr->u.msg_qnum = 0;
724137613Srwatson		msqkptr->u.msg_qbytes = msginfo.msgmnb;
725137613Srwatson		msqkptr->u.msg_lspid = 0;
726137613Srwatson		msqkptr->u.msg_lrpid = 0;
727137613Srwatson		msqkptr->u.msg_stime = 0;
728137613Srwatson		msqkptr->u.msg_rtime = 0;
729137613Srwatson		msqkptr->u.msg_ctime = time_second;
730140614Srwatson#ifdef MAC
731172930Srwatson		mac_sysvmsq_create(cred, msqkptr);
732140614Srwatson#endif
7332729Sdfr	} else {
734100523Salfred		DPRINTF(("didn't find it and wasn't asked to create it\n"));
73582607Sdillon		error = ENOENT;
73682607Sdillon		goto done2;
7372729Sdfr	}
7382729Sdfr
7392729Sdfrfound:
7402729Sdfr	/* Construct the unique msqid */
741137613Srwatson	td->td_retval[0] = IXSEQ_TO_IPCID(msqid, msqkptr->u.msg_perm);
74282607Sdillondone2:
743101772Salfred	mtx_unlock(&msq_mtx);
74482607Sdillon	return (error);
7452729Sdfr}
7462729Sdfr
74712866Speter#ifndef _SYS_SYSPROTO_H_
7482729Sdfrstruct msgsnd_args {
7492729Sdfr	int	msqid;
750331643Sdim	const void	*msgp;	/* XXX msgp is actually mtext. */
7512729Sdfr	size_t	msgsz;
7522729Sdfr	int	msgflg;
7532729Sdfr};
75412866Speter#endif
75512866Speterint
756331643Sdimkern_msgsnd(struct thread *td, int msqid, const void *msgp,
757331643Sdim    size_t msgsz, int msgflg, long mtype)
7582729Sdfr{
759165403Sjkim	int msqix, segs_needed, error = 0;
760331643Sdim	struct msqid_kernel *msqkptr;
761331643Sdim	struct msg *msghdr;
762298585Sjamie	struct prison *rpr;
7632729Sdfr	short next;
764223825Strasz#ifdef RACCT
765220398Strasz	size_t saved_msgsz;
766223825Strasz#endif
7672729Sdfr
768298585Sjamie	rpr = msg_find_prison(td->td_ucred);
769298585Sjamie	if (rpr == NULL)
77091703Sjhb		return (ENOSYS);
77191703Sjhb
772101772Salfred	mtx_lock(&msq_mtx);
773165403Sjkim	msqix = IPCID_TO_IX(msqid);
7742729Sdfr
775165403Sjkim	if (msqix < 0 || msqix >= msginfo.msgmni) {
776165403Sjkim		DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqix,
777100523Salfred		    msginfo.msgmni));
77882607Sdillon		error = EINVAL;
77982607Sdillon		goto done2;
7802729Sdfr	}
7812729Sdfr
782165403Sjkim	msqkptr = &msqids[msqix];
783137613Srwatson	if (msqkptr->u.msg_qbytes == 0) {
784100523Salfred		DPRINTF(("no such message queue id\n"));
78582607Sdillon		error = EINVAL;
78682607Sdillon		goto done2;
7872729Sdfr	}
788165403Sjkim	if (msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) {
789100523Salfred		DPRINTF(("wrong sequence number\n"));
79082607Sdillon		error = EINVAL;
79182607Sdillon		goto done2;
7922729Sdfr	}
7932729Sdfr
794298585Sjamie	if ((error = msq_prison_cansee(rpr, msqkptr))) {
795298585Sjamie		DPRINTF(("requester can't see prison\n"));
796298585Sjamie		goto done2;
797298585Sjamie	}
798298585Sjamie
799137613Srwatson	if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_W))) {
800100523Salfred		DPRINTF(("requester doesn't have write access\n"));
80182607Sdillon		goto done2;
8022729Sdfr	}
8032729Sdfr
804140614Srwatson#ifdef MAC
805172930Srwatson	error = mac_sysvmsq_check_msqsnd(td->td_ucred, msqkptr);
806162468Srwatson	if (error != 0)
807140614Srwatson		goto done2;
808140614Srwatson#endif
809140614Srwatson
810223825Strasz#ifdef RACCT
811282213Strasz	if (racct_enable) {
812282213Strasz		PROC_LOCK(td->td_proc);
813282213Strasz		if (racct_add(td->td_proc, RACCT_MSGQQUEUED, 1)) {
814282213Strasz			PROC_UNLOCK(td->td_proc);
815282213Strasz			error = EAGAIN;
816282213Strasz			goto done2;
817282213Strasz		}
818282213Strasz		saved_msgsz = msgsz;
819282213Strasz		if (racct_add(td->td_proc, RACCT_MSGQSIZE, msgsz)) {
820282213Strasz			racct_sub(td->td_proc, RACCT_MSGQQUEUED, 1);
821282213Strasz			PROC_UNLOCK(td->td_proc);
822282213Strasz			error = EAGAIN;
823282213Strasz			goto done2;
824282213Strasz		}
825220398Strasz		PROC_UNLOCK(td->td_proc);
826220398Strasz	}
827223825Strasz#endif
828220398Strasz
829298649Spfg	segs_needed = howmany(msgsz, msginfo.msgssz);
830165403Sjkim	DPRINTF(("msgsz=%zu, msgssz=%d, segs_needed=%d\n", msgsz,
831165403Sjkim	    msginfo.msgssz, segs_needed));
8322729Sdfr	for (;;) {
8332729Sdfr		int need_more_resources = 0;
8342729Sdfr
8352729Sdfr		/*
8362729Sdfr		 * check msgsz
8372729Sdfr		 * (inside this loop in case msg_qbytes changes while we sleep)
8382729Sdfr		 */
8392729Sdfr
840137613Srwatson		if (msgsz > msqkptr->u.msg_qbytes) {
841137613Srwatson			DPRINTF(("msgsz > msqkptr->u.msg_qbytes\n"));
84282607Sdillon			error = EINVAL;
843220398Strasz			goto done3;
8442729Sdfr		}
8452729Sdfr
846137613Srwatson		if (msqkptr->u.msg_perm.mode & MSG_LOCKED) {
847100523Salfred			DPRINTF(("msqid is locked\n"));
8482729Sdfr			need_more_resources = 1;
8492729Sdfr		}
850137613Srwatson		if (msgsz + msqkptr->u.msg_cbytes > msqkptr->u.msg_qbytes) {
851100523Salfred			DPRINTF(("msgsz + msg_cbytes > msg_qbytes\n"));
8522729Sdfr			need_more_resources = 1;
8532729Sdfr		}
8542729Sdfr		if (segs_needed > nfree_msgmaps) {
855100523Salfred			DPRINTF(("segs_needed > nfree_msgmaps\n"));
8562729Sdfr			need_more_resources = 1;
8572729Sdfr		}
8582729Sdfr		if (free_msghdrs == NULL) {
859100523Salfred			DPRINTF(("no more msghdrs\n"));
8602729Sdfr			need_more_resources = 1;
8612729Sdfr		}
8622729Sdfr
8632729Sdfr		if (need_more_resources) {
8642729Sdfr			int we_own_it;
8652729Sdfr
8662729Sdfr			if ((msgflg & IPC_NOWAIT) != 0) {
867100523Salfred				DPRINTF(("need more resources but caller "
868100523Salfred				    "doesn't want to wait\n"));
86982607Sdillon				error = EAGAIN;
870220398Strasz				goto done3;
8712729Sdfr			}
8722729Sdfr
873137613Srwatson			if ((msqkptr->u.msg_perm.mode & MSG_LOCKED) != 0) {
874100523Salfred				DPRINTF(("we don't own the msqid_ds\n"));
8752729Sdfr				we_own_it = 0;
8762729Sdfr			} else {
8772729Sdfr				/* Force later arrivals to wait for our
8782729Sdfr				   request */
879100523Salfred				DPRINTF(("we own the msqid_ds\n"));
880137613Srwatson				msqkptr->u.msg_perm.mode |= MSG_LOCKED;
8812729Sdfr				we_own_it = 1;
8822729Sdfr			}
883164368Sjkim			DPRINTF(("msgsnd:  goodnight\n"));
884137613Srwatson			error = msleep(msqkptr, &msq_mtx, (PZERO - 4) | PCATCH,
885164368Sjkim			    "msgsnd", hz);
886164368Sjkim			DPRINTF(("msgsnd:  good morning, error=%d\n", error));
8872729Sdfr			if (we_own_it)
888137613Srwatson				msqkptr->u.msg_perm.mode &= ~MSG_LOCKED;
889164368Sjkim			if (error == EWOULDBLOCK) {
890164368Sjkim				DPRINTF(("msgsnd:  timed out\n"));
891164368Sjkim				continue;
892164368Sjkim			}
89382607Sdillon			if (error != 0) {
894100523Salfred				DPRINTF(("msgsnd:  interrupted system call\n"));
89582607Sdillon				error = EINTR;
896220398Strasz				goto done3;
8972729Sdfr			}
8982729Sdfr
8992729Sdfr			/*
9002729Sdfr			 * Make sure that the msq queue still exists
9012729Sdfr			 */
9022729Sdfr
903137613Srwatson			if (msqkptr->u.msg_qbytes == 0) {
904100523Salfred				DPRINTF(("msqid deleted\n"));
90582607Sdillon				error = EIDRM;
906220398Strasz				goto done3;
9072729Sdfr			}
9082729Sdfr
9092729Sdfr		} else {
910100523Salfred			DPRINTF(("got all the resources that we need\n"));
9112729Sdfr			break;
9122729Sdfr		}
9132729Sdfr	}
9142729Sdfr
9152729Sdfr	/*
9162729Sdfr	 * We have the resources that we need.
9172729Sdfr	 * Make sure!
9182729Sdfr	 */
9192729Sdfr
920137613Srwatson	if (msqkptr->u.msg_perm.mode & MSG_LOCKED)
9212729Sdfr		panic("msg_perm.mode & MSG_LOCKED");
9222729Sdfr	if (segs_needed > nfree_msgmaps)
9232729Sdfr		panic("segs_needed > nfree_msgmaps");
924137613Srwatson	if (msgsz + msqkptr->u.msg_cbytes > msqkptr->u.msg_qbytes)
9252729Sdfr		panic("msgsz + msg_cbytes > msg_qbytes");
9262729Sdfr	if (free_msghdrs == NULL)
9272729Sdfr		panic("no more msghdrs");
9282729Sdfr
9292729Sdfr	/*
9302729Sdfr	 * Re-lock the msqid_ds in case we page-fault when copying in the
9312729Sdfr	 * message
9322729Sdfr	 */
9332729Sdfr
934137613Srwatson	if ((msqkptr->u.msg_perm.mode & MSG_LOCKED) != 0)
9352729Sdfr		panic("msqid_ds is already locked");
936137613Srwatson	msqkptr->u.msg_perm.mode |= MSG_LOCKED;
9372729Sdfr
9382729Sdfr	/*
9392729Sdfr	 * Allocate a message header
9402729Sdfr	 */
9412729Sdfr
9422729Sdfr	msghdr = free_msghdrs;
9432729Sdfr	free_msghdrs = msghdr->msg_next;
9442729Sdfr	msghdr->msg_spot = -1;
9452729Sdfr	msghdr->msg_ts = msgsz;
946165403Sjkim	msghdr->msg_type = mtype;
947140614Srwatson#ifdef MAC
948140614Srwatson	/*
949172930Srwatson	 * XXXMAC: Should the mac_sysvmsq_check_msgmsq check follow here
950140614Srwatson	 * immediately?  Or, should it be checked just before the msg is
951140614Srwatson	 * enqueued in the msgq (as it is done now)?
952140614Srwatson	 */
953172930Srwatson	mac_sysvmsg_create(td->td_ucred, msqkptr, msghdr);
954140614Srwatson#endif
9552729Sdfr
9562729Sdfr	/*
9572729Sdfr	 * Allocate space for the message
9582729Sdfr	 */
9592729Sdfr
9602729Sdfr	while (segs_needed > 0) {
9612729Sdfr		if (nfree_msgmaps <= 0)
9622729Sdfr			panic("not enough msgmaps");
9632729Sdfr		if (free_msgmaps == -1)
9642729Sdfr			panic("nil free_msgmaps");
9652729Sdfr		next = free_msgmaps;
9662729Sdfr		if (next <= -1)
9672729Sdfr			panic("next too low #1");
9682729Sdfr		if (next >= msginfo.msgseg)
9692729Sdfr			panic("next out of range #1");
970100523Salfred		DPRINTF(("allocating segment %d to message\n", next));
9712729Sdfr		free_msgmaps = msgmaps[next].next;
9722729Sdfr		nfree_msgmaps--;
9732729Sdfr		msgmaps[next].next = msghdr->msg_spot;
9742729Sdfr		msghdr->msg_spot = next;
9752729Sdfr		segs_needed--;
9762729Sdfr	}
9772729Sdfr
9782729Sdfr	/*
9792729Sdfr	 * Validate the message type
9802729Sdfr	 */
9812729Sdfr
9822729Sdfr	if (msghdr->msg_type < 1) {
9832729Sdfr		msg_freehdr(msghdr);
984137613Srwatson		msqkptr->u.msg_perm.mode &= ~MSG_LOCKED;
985137613Srwatson		wakeup(msqkptr);
986165403Sjkim		DPRINTF(("mtype (%ld) < 1\n", msghdr->msg_type));
98782607Sdillon		error = EINVAL;
988220398Strasz		goto done3;
9892729Sdfr	}
9902729Sdfr
9912729Sdfr	/*
9922729Sdfr	 * Copy in the message body
9932729Sdfr	 */
9942729Sdfr
9952729Sdfr	next = msghdr->msg_spot;
9962729Sdfr	while (msgsz > 0) {
9972729Sdfr		size_t tlen;
9982729Sdfr		if (msgsz > msginfo.msgssz)
9992729Sdfr			tlen = msginfo.msgssz;
10002729Sdfr		else
10012729Sdfr			tlen = msgsz;
10022729Sdfr		if (next <= -1)
10032729Sdfr			panic("next too low #2");
10042729Sdfr		if (next >= msginfo.msgseg)
10052729Sdfr			panic("next out of range #2");
1006101772Salfred		mtx_unlock(&msq_mtx);
1007165403Sjkim		if ((error = copyin(msgp, &msgpool[next * msginfo.msgssz],
10082729Sdfr		    tlen)) != 0) {
1009101772Salfred			mtx_lock(&msq_mtx);
1010100523Salfred			DPRINTF(("error %d copying in message segment\n",
1011100523Salfred			    error));
10122729Sdfr			msg_freehdr(msghdr);
1013137613Srwatson			msqkptr->u.msg_perm.mode &= ~MSG_LOCKED;
1014137613Srwatson			wakeup(msqkptr);
1015220398Strasz			goto done3;
10162729Sdfr		}
1017101772Salfred		mtx_lock(&msq_mtx);
10182729Sdfr		msgsz -= tlen;
1019165403Sjkim		msgp = (const char *)msgp + tlen;
10202729Sdfr		next = msgmaps[next].next;
10212729Sdfr	}
10222729Sdfr	if (next != -1)
10232729Sdfr		panic("didn't use all the msg segments");
10242729Sdfr
10252729Sdfr	/*
10262729Sdfr	 * We've got the message.  Unlock the msqid_ds.
10272729Sdfr	 */
10282729Sdfr
1029137613Srwatson	msqkptr->u.msg_perm.mode &= ~MSG_LOCKED;
10302729Sdfr
10312729Sdfr	/*
10322729Sdfr	 * Make sure that the msqid_ds is still allocated.
10332729Sdfr	 */
10342729Sdfr
1035137613Srwatson	if (msqkptr->u.msg_qbytes == 0) {
10362729Sdfr		msg_freehdr(msghdr);
1037137613Srwatson		wakeup(msqkptr);
103882607Sdillon		error = EIDRM;
1039220398Strasz		goto done3;
10402729Sdfr	}
10412729Sdfr
1042140614Srwatson#ifdef MAC
10432729Sdfr	/*
1044140614Srwatson	 * Note: Since the task/thread allocates the msghdr and usually
1045140614Srwatson	 * primes it with its own MAC label, for a majority of policies, it
1046140614Srwatson	 * won't be necessary to check whether the msghdr has access
1047172930Srwatson	 * permissions to the msgq.  The mac_sysvmsq_check_msqsnd check would
1048140614Srwatson	 * suffice in that case.  However, this hook may be required where
1049140614Srwatson	 * individual policies derive a non-identical label for the msghdr
1050140614Srwatson	 * from the current thread label and may want to check the msghdr
1051140614Srwatson	 * enqueue permissions, along with read/write permissions to the
1052140614Srwatson	 * msgq.
1053140614Srwatson	 */
1054172930Srwatson	error = mac_sysvmsq_check_msgmsq(td->td_ucred, msghdr, msqkptr);
1055140614Srwatson	if (error != 0) {
1056140614Srwatson		msg_freehdr(msghdr);
1057140614Srwatson		wakeup(msqkptr);
1058220398Strasz		goto done3;
1059140614Srwatson	}
1060140614Srwatson#endif
1061140614Srwatson
1062140614Srwatson	/*
10632729Sdfr	 * Put the message into the queue
10642729Sdfr	 */
1065137613Srwatson	if (msqkptr->u.msg_first == NULL) {
1066137613Srwatson		msqkptr->u.msg_first = msghdr;
1067137613Srwatson		msqkptr->u.msg_last = msghdr;
10682729Sdfr	} else {
1069137613Srwatson		msqkptr->u.msg_last->msg_next = msghdr;
1070137613Srwatson		msqkptr->u.msg_last = msghdr;
10712729Sdfr	}
1072137613Srwatson	msqkptr->u.msg_last->msg_next = NULL;
10732729Sdfr
1074137613Srwatson	msqkptr->u.msg_cbytes += msghdr->msg_ts;
1075137613Srwatson	msqkptr->u.msg_qnum++;
1076137613Srwatson	msqkptr->u.msg_lspid = td->td_proc->p_pid;
1077137613Srwatson	msqkptr->u.msg_stime = time_second;
10782729Sdfr
1079137613Srwatson	wakeup(msqkptr);
108083366Sjulian	td->td_retval[0] = 0;
1081220398Straszdone3:
1082223825Strasz#ifdef RACCT
1083282213Strasz	if (racct_enable && error != 0) {
1084220398Strasz		PROC_LOCK(td->td_proc);
1085220398Strasz		racct_sub(td->td_proc, RACCT_MSGQQUEUED, 1);
1086220398Strasz		racct_sub(td->td_proc, RACCT_MSGQSIZE, saved_msgsz);
1087220398Strasz		PROC_UNLOCK(td->td_proc);
1088220398Strasz	}
1089223825Strasz#endif
109082607Sdillondone2:
1091101772Salfred	mtx_unlock(&msq_mtx);
109282607Sdillon	return (error);
10932729Sdfr}
10942729Sdfr
1095165403Sjkimint
1096331643Sdimsys_msgsnd(struct thread *td, struct msgsnd_args *uap)
1097165403Sjkim{
1098165403Sjkim	int error;
1099165403Sjkim	long mtype;
1100165403Sjkim
1101165403Sjkim	DPRINTF(("call to msgsnd(%d, %p, %zu, %d)\n", uap->msqid, uap->msgp,
1102165403Sjkim	    uap->msgsz, uap->msgflg));
1103165403Sjkim
1104165403Sjkim	if ((error = copyin(uap->msgp, &mtype, sizeof(mtype))) != 0) {
1105165403Sjkim		DPRINTF(("error %d copying the message type\n", error));
1106165403Sjkim		return (error);
1107165403Sjkim	}
1108165403Sjkim	return (kern_msgsnd(td, uap->msqid,
1109165403Sjkim	    (const char *)uap->msgp + sizeof(mtype),
1110165403Sjkim	    uap->msgsz, uap->msgflg, mtype));
1111165403Sjkim}
1112165403Sjkim
111312866Speter#ifndef _SYS_SYSPROTO_H_
11142729Sdfrstruct msgrcv_args {
11152729Sdfr	int	msqid;
11162729Sdfr	void	*msgp;
11172729Sdfr	size_t	msgsz;
11182729Sdfr	long	msgtyp;
11192729Sdfr	int	msgflg;
11202729Sdfr};
112112866Speter#endif
1122331643Sdim/* XXX msgp is actually mtext. */
112312866Speterint
1124331643Sdimkern_msgrcv(struct thread *td, int msqid, void *msgp, size_t msgsz, long msgtyp,
1125331643Sdim    int msgflg, long *mtype)
11262729Sdfr{
11272729Sdfr	size_t len;
1128331643Sdim	struct msqid_kernel *msqkptr;
1129331643Sdim	struct msg *msghdr;
1130298585Sjamie	struct prison *rpr;
1131165403Sjkim	int msqix, error = 0;
11322729Sdfr	short next;
11332729Sdfr
1134298585Sjamie	rpr = msg_find_prison(td->td_ucred);
1135298585Sjamie	if (rpr == NULL)
113691703Sjhb		return (ENOSYS);
113791703Sjhb
1138165403Sjkim	msqix = IPCID_TO_IX(msqid);
11392729Sdfr
1140165403Sjkim	if (msqix < 0 || msqix >= msginfo.msgmni) {
1141165403Sjkim		DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqix,
1142100523Salfred		    msginfo.msgmni));
1143101772Salfred		return (EINVAL);
11442729Sdfr	}
11452729Sdfr
1146165403Sjkim	msqkptr = &msqids[msqix];
1147101772Salfred	mtx_lock(&msq_mtx);
1148137613Srwatson	if (msqkptr->u.msg_qbytes == 0) {
1149100523Salfred		DPRINTF(("no such message queue id\n"));
115082607Sdillon		error = EINVAL;
115182607Sdillon		goto done2;
11522729Sdfr	}
1153165403Sjkim	if (msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) {
1154100523Salfred		DPRINTF(("wrong sequence number\n"));
115582607Sdillon		error = EINVAL;
115682607Sdillon		goto done2;
11572729Sdfr	}
11582729Sdfr
1159298585Sjamie	if ((error = msq_prison_cansee(rpr, msqkptr))) {
1160298585Sjamie		DPRINTF(("requester can't see prison\n"));
1161298585Sjamie		goto done2;
1162298585Sjamie	}
1163298585Sjamie
1164137613Srwatson	if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_R))) {
1165100523Salfred		DPRINTF(("requester doesn't have read access\n"));
116682607Sdillon		goto done2;
11672729Sdfr	}
11682729Sdfr
1169140614Srwatson#ifdef MAC
1170172930Srwatson	error = mac_sysvmsq_check_msqrcv(td->td_ucred, msqkptr);
1171162468Srwatson	if (error != 0)
1172140614Srwatson		goto done2;
1173140614Srwatson#endif
1174140614Srwatson
11752729Sdfr	msghdr = NULL;
11762729Sdfr	while (msghdr == NULL) {
11772729Sdfr		if (msgtyp == 0) {
1178137613Srwatson			msghdr = msqkptr->u.msg_first;
11792729Sdfr			if (msghdr != NULL) {
11802729Sdfr				if (msgsz < msghdr->msg_ts &&
11812729Sdfr				    (msgflg & MSG_NOERROR) == 0) {
1182100523Salfred					DPRINTF(("first message on the queue "
1183165403Sjkim					    "is too big (want %zu, got %d)\n",
1184100523Salfred					    msgsz, msghdr->msg_ts));
118582607Sdillon					error = E2BIG;
118682607Sdillon					goto done2;
11872729Sdfr				}
1188140614Srwatson#ifdef MAC
1189172930Srwatson				error = mac_sysvmsq_check_msgrcv(td->td_ucred,
1190140614Srwatson				    msghdr);
1191162468Srwatson				if (error != 0)
1192140614Srwatson					goto done2;
1193140614Srwatson#endif
1194137613Srwatson				if (msqkptr->u.msg_first == msqkptr->u.msg_last) {
1195137613Srwatson					msqkptr->u.msg_first = NULL;
1196137613Srwatson					msqkptr->u.msg_last = NULL;
11972729Sdfr				} else {
1198137613Srwatson					msqkptr->u.msg_first = msghdr->msg_next;
1199137613Srwatson					if (msqkptr->u.msg_first == NULL)
12002729Sdfr						panic("msg_first/last screwed up #1");
12012729Sdfr				}
12022729Sdfr			}
12032729Sdfr		} else {
12042729Sdfr			struct msg *previous;
12052729Sdfr			struct msg **prev;
12062729Sdfr
12072729Sdfr			previous = NULL;
1208137613Srwatson			prev = &(msqkptr->u.msg_first);
12092729Sdfr			while ((msghdr = *prev) != NULL) {
12102729Sdfr				/*
12112729Sdfr				 * Is this message's type an exact match or is
12122729Sdfr				 * this message's type less than or equal to
12132729Sdfr				 * the absolute value of a negative msgtyp?
12142729Sdfr				 * Note that the second half of this test can
12152729Sdfr				 * NEVER be true if msgtyp is positive since
12162729Sdfr				 * msg_type is always positive!
12172729Sdfr				 */
12182729Sdfr
12192729Sdfr				if (msgtyp == msghdr->msg_type ||
12202729Sdfr				    msghdr->msg_type <= -msgtyp) {
1221165403Sjkim					DPRINTF(("found message type %ld, "
1222165403Sjkim					    "requested %ld\n",
1223100523Salfred					    msghdr->msg_type, msgtyp));
12242729Sdfr					if (msgsz < msghdr->msg_ts &&
12252729Sdfr					    (msgflg & MSG_NOERROR) == 0) {
1226100523Salfred						DPRINTF(("requested message "
1227100523Salfred						    "on the queue is too big "
1228165403Sjkim						    "(want %zu, got %hu)\n",
1229100523Salfred						    msgsz, msghdr->msg_ts));
123082607Sdillon						error = E2BIG;
123182607Sdillon						goto done2;
12322729Sdfr					}
1233140614Srwatson#ifdef MAC
1234172930Srwatson					error = mac_sysvmsq_check_msgrcv(
1235140614Srwatson					    td->td_ucred, msghdr);
1236162468Srwatson					if (error != 0)
1237140614Srwatson						goto done2;
1238140614Srwatson#endif
12392729Sdfr					*prev = msghdr->msg_next;
1240137613Srwatson					if (msghdr == msqkptr->u.msg_last) {
12412729Sdfr						if (previous == NULL) {
12422729Sdfr							if (prev !=
1243137613Srwatson							    &msqkptr->u.msg_first)
12442729Sdfr								panic("msg_first/last screwed up #2");
1245137613Srwatson							msqkptr->u.msg_first =
12462729Sdfr							    NULL;
1247137613Srwatson							msqkptr->u.msg_last =
12482729Sdfr							    NULL;
12492729Sdfr						} else {
12502729Sdfr							if (prev ==
1251137613Srwatson							    &msqkptr->u.msg_first)
12522729Sdfr								panic("msg_first/last screwed up #3");
1253137613Srwatson							msqkptr->u.msg_last =
12542729Sdfr							    previous;
12552729Sdfr						}
12562729Sdfr					}
12572729Sdfr					break;
12582729Sdfr				}
12592729Sdfr				previous = msghdr;
12602729Sdfr				prev = &(msghdr->msg_next);
12612729Sdfr			}
12622729Sdfr		}
12632729Sdfr
12642729Sdfr		/*
12652729Sdfr		 * We've either extracted the msghdr for the appropriate
12662729Sdfr		 * message or there isn't one.
12672729Sdfr		 * If there is one then bail out of this loop.
12682729Sdfr		 */
12692729Sdfr
12702729Sdfr		if (msghdr != NULL)
12712729Sdfr			break;
12722729Sdfr
12732729Sdfr		/*
12742729Sdfr		 * Hmph!  No message found.  Does the user want to wait?
12752729Sdfr		 */
12762729Sdfr
12772729Sdfr		if ((msgflg & IPC_NOWAIT) != 0) {
1278165403Sjkim			DPRINTF(("no appropriate message found (msgtyp=%ld)\n",
1279100523Salfred			    msgtyp));
12802729Sdfr			/* The SVID says to return ENOMSG. */
128182607Sdillon			error = ENOMSG;
128282607Sdillon			goto done2;
12832729Sdfr		}
12842729Sdfr
12852729Sdfr		/*
12862729Sdfr		 * Wait for something to happen
12872729Sdfr		 */
12882729Sdfr
1289100523Salfred		DPRINTF(("msgrcv:  goodnight\n"));
1290137613Srwatson		error = msleep(msqkptr, &msq_mtx, (PZERO - 4) | PCATCH,
1291164368Sjkim		    "msgrcv", 0);
1292100523Salfred		DPRINTF(("msgrcv:  good morning (error=%d)\n", error));
12932729Sdfr
129482607Sdillon		if (error != 0) {
1295164368Sjkim			DPRINTF(("msgrcv:  interrupted system call\n"));
129682607Sdillon			error = EINTR;
129782607Sdillon			goto done2;
12982729Sdfr		}
12992729Sdfr
13002729Sdfr		/*
13012729Sdfr		 * Make sure that the msq queue still exists
13022729Sdfr		 */
13032729Sdfr
1304137613Srwatson		if (msqkptr->u.msg_qbytes == 0 ||
1305165403Sjkim		    msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) {
1306100523Salfred			DPRINTF(("msqid deleted\n"));
130782607Sdillon			error = EIDRM;
130882607Sdillon			goto done2;
13092729Sdfr		}
13102729Sdfr	}
13112729Sdfr
13122729Sdfr	/*
13132729Sdfr	 * Return the message to the user.
13142729Sdfr	 *
13152729Sdfr	 * First, do the bookkeeping (before we risk being interrupted).
13162729Sdfr	 */
13172729Sdfr
1318137613Srwatson	msqkptr->u.msg_cbytes -= msghdr->msg_ts;
1319137613Srwatson	msqkptr->u.msg_qnum--;
1320137613Srwatson	msqkptr->u.msg_lrpid = td->td_proc->p_pid;
1321137613Srwatson	msqkptr->u.msg_rtime = time_second;
13222729Sdfr
1323220398Strasz	racct_sub_cred(msqkptr->cred, RACCT_MSGQQUEUED, 1);
1324220398Strasz	racct_sub_cred(msqkptr->cred, RACCT_MSGQSIZE, msghdr->msg_ts);
1325220398Strasz
13262729Sdfr	/*
13272729Sdfr	 * Make msgsz the actual amount that we'll be returning.
13282729Sdfr	 * Note that this effectively truncates the message if it is too long
13292729Sdfr	 * (since msgsz is never increased).
13302729Sdfr	 */
13312729Sdfr
1332165403Sjkim	DPRINTF(("found a message, msgsz=%zu, msg_ts=%hu\n", msgsz,
1333100523Salfred	    msghdr->msg_ts));
13342729Sdfr	if (msgsz > msghdr->msg_ts)
13352729Sdfr		msgsz = msghdr->msg_ts;
1336165403Sjkim	*mtype = msghdr->msg_type;
13372729Sdfr
13382729Sdfr	/*
13392729Sdfr	 * Return the segments to the user
13402729Sdfr	 */
13412729Sdfr
13422729Sdfr	next = msghdr->msg_spot;
13432729Sdfr	for (len = 0; len < msgsz; len += msginfo.msgssz) {
13442729Sdfr		size_t tlen;
13452729Sdfr
134645921Ssada		if (msgsz - len > msginfo.msgssz)
13472729Sdfr			tlen = msginfo.msgssz;
13482729Sdfr		else
134945921Ssada			tlen = msgsz - len;
13502729Sdfr		if (next <= -1)
13512729Sdfr			panic("next too low #3");
13522729Sdfr		if (next >= msginfo.msgseg)
13532729Sdfr			panic("next out of range #3");
1354101772Salfred		mtx_unlock(&msq_mtx);
1355165403Sjkim		error = copyout(&msgpool[next * msginfo.msgssz], msgp, tlen);
1356101772Salfred		mtx_lock(&msq_mtx);
135782607Sdillon		if (error != 0) {
1358100523Salfred			DPRINTF(("error (%d) copying out message segment\n",
1359100523Salfred			    error));
13602729Sdfr			msg_freehdr(msghdr);
1361137613Srwatson			wakeup(msqkptr);
136282607Sdillon			goto done2;
13632729Sdfr		}
1364165403Sjkim		msgp = (char *)msgp + tlen;
13652729Sdfr		next = msgmaps[next].next;
13662729Sdfr	}
13672729Sdfr
13682729Sdfr	/*
13692729Sdfr	 * Done, return the actual number of bytes copied out.
13702729Sdfr	 */
13712729Sdfr
13722729Sdfr	msg_freehdr(msghdr);
1373137613Srwatson	wakeup(msqkptr);
137483366Sjulian	td->td_retval[0] = msgsz;
137582607Sdillondone2:
1376101772Salfred	mtx_unlock(&msq_mtx);
137782607Sdillon	return (error);
13782729Sdfr}
137977461Sdd
1380165403Sjkimint
1381331643Sdimsys_msgrcv(struct thread *td, struct msgrcv_args *uap)
1382165403Sjkim{
1383165403Sjkim	int error;
1384165403Sjkim	long mtype;
1385165403Sjkim
1386165403Sjkim	DPRINTF(("call to msgrcv(%d, %p, %zu, %ld, %d)\n", uap->msqid,
1387165403Sjkim	    uap->msgp, uap->msgsz, uap->msgtyp, uap->msgflg));
1388165403Sjkim
1389165403Sjkim	if ((error = kern_msgrcv(td, uap->msqid,
1390165403Sjkim	    (char *)uap->msgp + sizeof(mtype), uap->msgsz,
1391165403Sjkim	    uap->msgtyp, uap->msgflg, &mtype)) != 0)
1392165403Sjkim		return (error);
1393165403Sjkim	if ((error = copyout(&mtype, uap->msgp, sizeof(mtype))) != 0)
1394165403Sjkim		DPRINTF(("error %d copying the message type\n", error));
1395165403Sjkim	return (error);
1396165403Sjkim}
1397165403Sjkim
139877461Sddstatic int
139977461Sddsysctl_msqids(SYSCTL_HANDLER_ARGS)
140077461Sdd{
1401298656Sjamie	struct msqid_kernel tmsqk;
1402329177Sbrooks#ifdef COMPAT_FREEBSD32
1403329177Sbrooks	struct msqid_kernel32 tmsqk32;
1404329177Sbrooks#endif
1405298656Sjamie	struct prison *pr, *rpr;
1406329177Sbrooks	void *outaddr;
1407329177Sbrooks	size_t outsize;
1408298585Sjamie	int error, i;
140977461Sdd
1410298656Sjamie	pr = req->td->td_ucred->cr_prison;
1411298585Sjamie	rpr = msg_find_prison(req->td->td_ucred);
1412298656Sjamie	error = 0;
1413298585Sjamie	for (i = 0; i < msginfo.msgmni; i++) {
1414298656Sjamie		mtx_lock(&msq_mtx);
1415298656Sjamie		if (msqids[i].u.msg_qbytes == 0 || rpr == NULL ||
1416298656Sjamie		    msq_prison_cansee(rpr, &msqids[i]) != 0)
1417298656Sjamie			bzero(&tmsqk, sizeof(tmsqk));
1418298656Sjamie		else {
1419298656Sjamie			tmsqk = msqids[i];
1420298656Sjamie			if (tmsqk.cred->cr_prison != pr)
1421298656Sjamie				tmsqk.u.msg_perm.key = IPC_PRIVATE;
1422298585Sjamie		}
1423298656Sjamie		mtx_unlock(&msq_mtx);
1424329177Sbrooks#ifdef COMPAT_FREEBSD32
1425329177Sbrooks		if (SV_CURPROC_FLAG(SV_ILP32)) {
1426329177Sbrooks			bzero(&tmsqk32, sizeof(tmsqk32));
1427329177Sbrooks			freebsd32_ipcperm_out(&tmsqk.u.msg_perm,
1428329177Sbrooks			    &tmsqk32.u.msg_perm);
1429329177Sbrooks			/* Don't copy u.msg_first or u.msg_last */
1430329177Sbrooks			CP(tmsqk, tmsqk32, u.msg_cbytes);
1431329177Sbrooks			CP(tmsqk, tmsqk32, u.msg_qnum);
1432329177Sbrooks			CP(tmsqk, tmsqk32, u.msg_qbytes);
1433329177Sbrooks			CP(tmsqk, tmsqk32, u.msg_lspid);
1434329177Sbrooks			CP(tmsqk, tmsqk32, u.msg_lrpid);
1435329177Sbrooks			CP(tmsqk, tmsqk32, u.msg_stime);
1436329177Sbrooks			CP(tmsqk, tmsqk32, u.msg_rtime);
1437329177Sbrooks			CP(tmsqk, tmsqk32, u.msg_ctime);
1438329177Sbrooks			/* Don't copy label or cred */
1439329177Sbrooks			outaddr = &tmsqk32;
1440329177Sbrooks			outsize = sizeof(tmsqk32);
1441329177Sbrooks		} else
1442329177Sbrooks#endif
1443329177Sbrooks		{
1444329177Sbrooks			/* Don't leak kernel pointers */
1445329177Sbrooks			tmsqk.u.msg_first = NULL;
1446329177Sbrooks			tmsqk.u.msg_last = NULL;
1447329177Sbrooks			tmsqk.label = NULL;
1448329177Sbrooks			tmsqk.cred = NULL;
1449329177Sbrooks			/*
1450329177Sbrooks			 * XXX: some padding also exists, but we take care to
1451329177Sbrooks			 * allocate our pool of msqid_kernel structs with
1452329177Sbrooks			 * zeroed memory so this should be OK.
1453329177Sbrooks			 */
1454329177Sbrooks			outaddr = &tmsqk;
1455329177Sbrooks			outsize = sizeof(tmsqk);
1456329177Sbrooks		}
1457329177Sbrooks		error = SYSCTL_OUT(req, outaddr, outsize);
1458298656Sjamie		if (error != 0)
1459298656Sjamie			break;
1460298585Sjamie	}
1461298585Sjamie	return (error);
146277461Sdd}
146377461Sdd
1464141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgmax, CTLFLAG_RD, &msginfo.msgmax, 0,
1465141710Scsjp    "Maximum message size");
1466141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgmni, CTLFLAG_RDTUN, &msginfo.msgmni, 0,
1467141710Scsjp    "Number of message queue identifiers");
1468141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgmnb, CTLFLAG_RDTUN, &msginfo.msgmnb, 0,
1469141710Scsjp    "Maximum number of bytes in a queue");
1470141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgtql, CTLFLAG_RDTUN, &msginfo.msgtql, 0,
1471141710Scsjp    "Maximum number of messages in the system");
1472141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgssz, CTLFLAG_RDTUN, &msginfo.msgssz, 0,
1473141710Scsjp    "Size of a message segment");
1474141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgseg, CTLFLAG_RDTUN, &msginfo.msgseg, 0,
1475141710Scsjp    "Number of message segments");
1476298656SjamieSYSCTL_PROC(_kern_ipc, OID_AUTO, msqids,
1477298656Sjamie    CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE,
1478329739Sbrooks    NULL, 0, sysctl_msqids, "",
1479329739Sbrooks    "Array of struct msqid_kernel for each potential message queue");
1480194894Sjhb
1481298585Sjamiestatic int
1482298585Sjamiemsg_prison_check(void *obj, void *data)
1483298585Sjamie{
1484298585Sjamie	struct prison *pr = obj;
1485298585Sjamie	struct prison *prpr;
1486298585Sjamie	struct vfsoptlist *opts = data;
1487298585Sjamie	int error, jsys;
1488298585Sjamie
1489298585Sjamie	/*
1490298585Sjamie	 * sysvmsg is a jailsys integer.
1491298585Sjamie	 * It must be "disable" if the parent jail is disabled.
1492298585Sjamie	 */
1493298585Sjamie	error = vfs_copyopt(opts, "sysvmsg", &jsys, sizeof(jsys));
1494298585Sjamie	if (error != ENOENT) {
1495298585Sjamie		if (error != 0)
1496298585Sjamie			return (error);
1497298585Sjamie		switch (jsys) {
1498298585Sjamie		case JAIL_SYS_DISABLE:
1499298585Sjamie			break;
1500298585Sjamie		case JAIL_SYS_NEW:
1501298585Sjamie		case JAIL_SYS_INHERIT:
1502298585Sjamie			prison_lock(pr->pr_parent);
1503298585Sjamie			prpr = osd_jail_get(pr->pr_parent, msg_prison_slot);
1504298585Sjamie			prison_unlock(pr->pr_parent);
1505298585Sjamie			if (prpr == NULL)
1506298585Sjamie				return (EPERM);
1507298585Sjamie			break;
1508298585Sjamie		default:
1509298585Sjamie			return (EINVAL);
1510298585Sjamie		}
1511298585Sjamie	}
1512298585Sjamie
1513298585Sjamie	return (0);
1514298585Sjamie}
1515298585Sjamie
1516298585Sjamiestatic int
1517298585Sjamiemsg_prison_set(void *obj, void *data)
1518298585Sjamie{
1519298585Sjamie	struct prison *pr = obj;
1520298585Sjamie	struct prison *tpr, *orpr, *nrpr, *trpr;
1521298585Sjamie	struct vfsoptlist *opts = data;
1522298585Sjamie	void *rsv;
1523298585Sjamie	int jsys, descend;
1524298585Sjamie
1525298585Sjamie	/*
1526298585Sjamie	 * sysvmsg controls which jail is the root of the associated msgs (this
1527298585Sjamie	 * jail or same as the parent), or if the feature is available at all.
1528298585Sjamie	 */
1529298585Sjamie	if (vfs_copyopt(opts, "sysvmsg", &jsys, sizeof(jsys)) == ENOENT)
1530298585Sjamie		jsys = vfs_flagopt(opts, "allow.sysvipc", NULL, 0)
1531298585Sjamie		    ? JAIL_SYS_INHERIT
1532298585Sjamie		    : vfs_flagopt(opts, "allow.nosysvipc", NULL, 0)
1533298585Sjamie		    ? JAIL_SYS_DISABLE
1534298585Sjamie		    : -1;
1535298585Sjamie	if (jsys == JAIL_SYS_DISABLE) {
1536298585Sjamie		prison_lock(pr);
1537298585Sjamie		orpr = osd_jail_get(pr, msg_prison_slot);
1538298585Sjamie		if (orpr != NULL)
1539298585Sjamie			osd_jail_del(pr, msg_prison_slot);
1540298585Sjamie		prison_unlock(pr);
1541298585Sjamie		if (orpr != NULL) {
1542298585Sjamie			if (orpr == pr)
1543298585Sjamie				msg_prison_cleanup(pr);
1544298585Sjamie			/* Disable all child jails as well. */
1545298585Sjamie			FOREACH_PRISON_DESCENDANT(pr, tpr, descend) {
1546298585Sjamie				prison_lock(tpr);
1547298585Sjamie				trpr = osd_jail_get(tpr, msg_prison_slot);
1548298585Sjamie				if (trpr != NULL) {
1549298585Sjamie					osd_jail_del(tpr, msg_prison_slot);
1550298585Sjamie					prison_unlock(tpr);
1551298585Sjamie					if (trpr == tpr)
1552298585Sjamie						msg_prison_cleanup(tpr);
1553298585Sjamie				} else {
1554298585Sjamie					prison_unlock(tpr);
1555298585Sjamie					descend = 0;
1556298585Sjamie				}
1557298585Sjamie			}
1558298585Sjamie		}
1559298585Sjamie	} else if (jsys != -1) {
1560298585Sjamie		if (jsys == JAIL_SYS_NEW)
1561298585Sjamie			nrpr = pr;
1562298585Sjamie		else {
1563298585Sjamie			prison_lock(pr->pr_parent);
1564298585Sjamie			nrpr = osd_jail_get(pr->pr_parent, msg_prison_slot);
1565298585Sjamie			prison_unlock(pr->pr_parent);
1566298585Sjamie		}
1567298585Sjamie		rsv = osd_reserve(msg_prison_slot);
1568298585Sjamie		prison_lock(pr);
1569298585Sjamie		orpr = osd_jail_get(pr, msg_prison_slot);
1570298585Sjamie		if (orpr != nrpr)
1571298585Sjamie			(void)osd_jail_set_reserved(pr, msg_prison_slot, rsv,
1572298585Sjamie			    nrpr);
1573298585Sjamie		else
1574298585Sjamie			osd_free_reserved(rsv);
1575298585Sjamie		prison_unlock(pr);
1576298585Sjamie		if (orpr != nrpr) {
1577298585Sjamie			if (orpr == pr)
1578298585Sjamie				msg_prison_cleanup(pr);
1579298585Sjamie			if (orpr != NULL) {
1580298585Sjamie				/* Change child jails matching the old root, */
1581298585Sjamie				FOREACH_PRISON_DESCENDANT(pr, tpr, descend) {
1582298585Sjamie					prison_lock(tpr);
1583298585Sjamie					trpr = osd_jail_get(tpr,
1584298585Sjamie					    msg_prison_slot);
1585298585Sjamie					if (trpr == orpr) {
1586298585Sjamie						(void)osd_jail_set(tpr,
1587298585Sjamie						    msg_prison_slot, nrpr);
1588298585Sjamie						prison_unlock(tpr);
1589298585Sjamie						if (trpr == tpr)
1590298585Sjamie							msg_prison_cleanup(tpr);
1591298585Sjamie					} else {
1592298585Sjamie						prison_unlock(tpr);
1593298585Sjamie						descend = 0;
1594298585Sjamie					}
1595298585Sjamie				}
1596298585Sjamie			}
1597298585Sjamie		}
1598298585Sjamie	}
1599298585Sjamie
1600298585Sjamie	return (0);
1601298585Sjamie}
1602298585Sjamie
1603298585Sjamiestatic int
1604298585Sjamiemsg_prison_get(void *obj, void *data)
1605298585Sjamie{
1606298585Sjamie	struct prison *pr = obj;
1607298585Sjamie	struct prison *rpr;
1608298585Sjamie	struct vfsoptlist *opts = data;
1609298585Sjamie	int error, jsys;
1610298585Sjamie
1611298585Sjamie	/* Set sysvmsg based on the jail's root prison. */
1612298585Sjamie	prison_lock(pr);
1613298585Sjamie	rpr = osd_jail_get(pr, msg_prison_slot);
1614298585Sjamie	prison_unlock(pr);
1615298585Sjamie	jsys = rpr == NULL ? JAIL_SYS_DISABLE
1616298585Sjamie	    : rpr == pr ? JAIL_SYS_NEW : JAIL_SYS_INHERIT;
1617298585Sjamie	error = vfs_setopt(opts, "sysvmsg", &jsys, sizeof(jsys));
1618298585Sjamie	if (error == ENOENT)
1619298585Sjamie		error = 0;
1620298585Sjamie	return (error);
1621298585Sjamie}
1622298585Sjamie
1623298585Sjamiestatic int
1624298585Sjamiemsg_prison_remove(void *obj, void *data __unused)
1625298585Sjamie{
1626298585Sjamie	struct prison *pr = obj;
1627298585Sjamie	struct prison *rpr;
1628298585Sjamie
1629298585Sjamie	prison_lock(pr);
1630298585Sjamie	rpr = osd_jail_get(pr, msg_prison_slot);
1631298585Sjamie	prison_unlock(pr);
1632298585Sjamie	if (rpr == pr)
1633298585Sjamie		msg_prison_cleanup(pr);
1634298585Sjamie	return (0);
1635298585Sjamie}
1636298585Sjamie
1637298585Sjamiestatic void
1638298585Sjamiemsg_prison_cleanup(struct prison *pr)
1639298585Sjamie{
1640298585Sjamie	struct msqid_kernel *msqkptr;
1641298585Sjamie	int i;
1642298585Sjamie
1643298585Sjamie	/* Remove any msqs that belong to this jail. */
1644298585Sjamie	mtx_lock(&msq_mtx);
1645298585Sjamie	for (i = 0; i < msginfo.msgmni; i++) {
1646298585Sjamie		msqkptr = &msqids[i];
1647298585Sjamie		if (msqkptr->u.msg_qbytes != 0 &&
1648298585Sjamie		    msqkptr->cred != NULL && msqkptr->cred->cr_prison == pr)
1649298585Sjamie			msq_remove(msqkptr);
1650298585Sjamie	}
1651298585Sjamie	mtx_unlock(&msq_mtx);
1652298585Sjamie}
1653298585Sjamie
1654298585SjamieSYSCTL_JAIL_PARAM_SYS_NODE(sysvmsg, CTLFLAG_RW, "SYSV message queues");
1655298585Sjamie
1656205323Skib#ifdef COMPAT_FREEBSD32
1657205323Skibint
1658205323Skibfreebsd32_msgsys(struct thread *td, struct freebsd32_msgsys_args *uap)
1659205323Skib{
1660205323Skib
1661194894Sjhb#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
1662194894Sjhb    defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
1663205323Skib	switch (uap->which) {
1664205323Skib	case 0:
1665205323Skib		return (freebsd7_freebsd32_msgctl(td,
1666205323Skib		    (struct freebsd7_freebsd32_msgctl_args *)&uap->a2));
1667205323Skib	case 2:
1668205323Skib		return (freebsd32_msgsnd(td,
1669205323Skib		    (struct freebsd32_msgsnd_args *)&uap->a2));
1670205323Skib	case 3:
1671205323Skib		return (freebsd32_msgrcv(td,
1672205323Skib		    (struct freebsd32_msgrcv_args *)&uap->a2));
1673205323Skib	default:
1674225617Skmacy		return (sys_msgsys(td, (struct msgsys_args *)uap));
1675205323Skib	}
1676205323Skib#else
1677205323Skib	return (nosys(td, NULL));
1678205323Skib#endif
1679205323Skib}
1680194894Sjhb
1681205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
1682205323Skib    defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
1683205323Skibint
1684205323Skibfreebsd7_freebsd32_msgctl(struct thread *td,
1685205323Skib    struct freebsd7_freebsd32_msgctl_args *uap)
1686205323Skib{
1687205323Skib	struct msqid_ds msqbuf;
1688205323Skib	struct msqid_ds32_old msqbuf32;
1689205323Skib	int error;
1690205323Skib
1691205323Skib	if (uap->cmd == IPC_SET) {
1692205323Skib		error = copyin(uap->buf, &msqbuf32, sizeof(msqbuf32));
1693205323Skib		if (error)
1694205323Skib			return (error);
1695205323Skib		freebsd32_ipcperm_old_in(&msqbuf32.msg_perm, &msqbuf.msg_perm);
1696205323Skib		PTRIN_CP(msqbuf32, msqbuf, msg_first);
1697205323Skib		PTRIN_CP(msqbuf32, msqbuf, msg_last);
1698205323Skib		CP(msqbuf32, msqbuf, msg_cbytes);
1699205323Skib		CP(msqbuf32, msqbuf, msg_qnum);
1700205323Skib		CP(msqbuf32, msqbuf, msg_qbytes);
1701205323Skib		CP(msqbuf32, msqbuf, msg_lspid);
1702205323Skib		CP(msqbuf32, msqbuf, msg_lrpid);
1703205323Skib		CP(msqbuf32, msqbuf, msg_stime);
1704205323Skib		CP(msqbuf32, msqbuf, msg_rtime);
1705205323Skib		CP(msqbuf32, msqbuf, msg_ctime);
1706205323Skib	}
1707205323Skib	error = kern_msgctl(td, uap->msqid, uap->cmd, &msqbuf);
1708205323Skib	if (error)
1709205323Skib		return (error);
1710205323Skib	if (uap->cmd == IPC_STAT) {
1711205323Skib		bzero(&msqbuf32, sizeof(msqbuf32));
1712205323Skib		freebsd32_ipcperm_old_out(&msqbuf.msg_perm, &msqbuf32.msg_perm);
1713205323Skib		PTROUT_CP(msqbuf, msqbuf32, msg_first);
1714205323Skib		PTROUT_CP(msqbuf, msqbuf32, msg_last);
1715205323Skib		CP(msqbuf, msqbuf32, msg_cbytes);
1716205323Skib		CP(msqbuf, msqbuf32, msg_qnum);
1717205323Skib		CP(msqbuf, msqbuf32, msg_qbytes);
1718205323Skib		CP(msqbuf, msqbuf32, msg_lspid);
1719205323Skib		CP(msqbuf, msqbuf32, msg_lrpid);
1720205323Skib		CP(msqbuf, msqbuf32, msg_stime);
1721205323Skib		CP(msqbuf, msqbuf32, msg_rtime);
1722205323Skib		CP(msqbuf, msqbuf32, msg_ctime);
1723205323Skib		error = copyout(&msqbuf32, uap->buf, sizeof(struct msqid_ds32));
1724205323Skib	}
1725205323Skib	return (error);
1726205323Skib}
1727205323Skib#endif
1728205323Skib
1729205323Skibint
1730205323Skibfreebsd32_msgctl(struct thread *td, struct freebsd32_msgctl_args *uap)
1731205323Skib{
1732205323Skib	struct msqid_ds msqbuf;
1733205323Skib	struct msqid_ds32 msqbuf32;
1734205323Skib	int error;
1735205323Skib
1736205323Skib	if (uap->cmd == IPC_SET) {
1737205323Skib		error = copyin(uap->buf, &msqbuf32, sizeof(msqbuf32));
1738205323Skib		if (error)
1739205323Skib			return (error);
1740205323Skib		freebsd32_ipcperm_in(&msqbuf32.msg_perm, &msqbuf.msg_perm);
1741205323Skib		PTRIN_CP(msqbuf32, msqbuf, msg_first);
1742205323Skib		PTRIN_CP(msqbuf32, msqbuf, msg_last);
1743205323Skib		CP(msqbuf32, msqbuf, msg_cbytes);
1744205323Skib		CP(msqbuf32, msqbuf, msg_qnum);
1745205323Skib		CP(msqbuf32, msqbuf, msg_qbytes);
1746205323Skib		CP(msqbuf32, msqbuf, msg_lspid);
1747205323Skib		CP(msqbuf32, msqbuf, msg_lrpid);
1748205323Skib		CP(msqbuf32, msqbuf, msg_stime);
1749205323Skib		CP(msqbuf32, msqbuf, msg_rtime);
1750205323Skib		CP(msqbuf32, msqbuf, msg_ctime);
1751205323Skib	}
1752205323Skib	error = kern_msgctl(td, uap->msqid, uap->cmd, &msqbuf);
1753205323Skib	if (error)
1754205323Skib		return (error);
1755205323Skib	if (uap->cmd == IPC_STAT) {
1756205323Skib		freebsd32_ipcperm_out(&msqbuf.msg_perm, &msqbuf32.msg_perm);
1757205323Skib		PTROUT_CP(msqbuf, msqbuf32, msg_first);
1758205323Skib		PTROUT_CP(msqbuf, msqbuf32, msg_last);
1759205323Skib		CP(msqbuf, msqbuf32, msg_cbytes);
1760205323Skib		CP(msqbuf, msqbuf32, msg_qnum);
1761205323Skib		CP(msqbuf, msqbuf32, msg_qbytes);
1762205323Skib		CP(msqbuf, msqbuf32, msg_lspid);
1763205323Skib		CP(msqbuf, msqbuf32, msg_lrpid);
1764205323Skib		CP(msqbuf, msqbuf32, msg_stime);
1765205323Skib		CP(msqbuf, msqbuf32, msg_rtime);
1766205323Skib		CP(msqbuf, msqbuf32, msg_ctime);
1767205323Skib		error = copyout(&msqbuf32, uap->buf, sizeof(struct msqid_ds32));
1768205323Skib	}
1769205323Skib	return (error);
1770205323Skib}
1771205323Skib
1772205323Skibint
1773205323Skibfreebsd32_msgsnd(struct thread *td, struct freebsd32_msgsnd_args *uap)
1774205323Skib{
1775205323Skib	const void *msgp;
1776205323Skib	long mtype;
1777205323Skib	int32_t mtype32;
1778205323Skib	int error;
1779205323Skib
1780205323Skib	msgp = PTRIN(uap->msgp);
1781205323Skib	if ((error = copyin(msgp, &mtype32, sizeof(mtype32))) != 0)
1782205323Skib		return (error);
1783205323Skib	mtype = mtype32;
1784205323Skib	return (kern_msgsnd(td, uap->msqid,
1785205323Skib	    (const char *)msgp + sizeof(mtype32),
1786205323Skib	    uap->msgsz, uap->msgflg, mtype));
1787205323Skib}
1788205323Skib
1789205323Skibint
1790205323Skibfreebsd32_msgrcv(struct thread *td, struct freebsd32_msgrcv_args *uap)
1791205323Skib{
1792205323Skib	void *msgp;
1793205323Skib	long mtype;
1794205323Skib	int32_t mtype32;
1795205323Skib	int error;
1796205323Skib
1797205323Skib	msgp = PTRIN(uap->msgp);
1798205323Skib	if ((error = kern_msgrcv(td, uap->msqid,
1799205323Skib	    (char *)msgp + sizeof(mtype32), uap->msgsz,
1800205323Skib	    uap->msgtyp, uap->msgflg, &mtype)) != 0)
1801205323Skib		return (error);
1802205323Skib	mtype32 = (int32_t)mtype;
1803205323Skib	return (copyout(&mtype32, msgp, sizeof(mtype32)));
1804205323Skib}
1805205323Skib#endif
1806205323Skib
1807205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
1808205323Skib    defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
1809205323Skib
1810194894Sjhb/* XXX casting to (sy_call_t *) is bogus, as usual. */
1811194894Sjhbstatic sy_call_t *msgcalls[] = {
1812225617Skmacy	(sy_call_t *)freebsd7_msgctl, (sy_call_t *)sys_msgget,
1813225617Skmacy	(sy_call_t *)sys_msgsnd, (sy_call_t *)sys_msgrcv
1814194894Sjhb};
1815194894Sjhb
1816194894Sjhb/*
1817194894Sjhb * Entry point for all MSG calls.
1818331643Sdim *
1819331643Sdim * XXX actually varargs.
1820331643Sdim * struct msgsys_args {
1821331643Sdim *		int	which;
1822331643Sdim *		int	a2;
1823331643Sdim *		int	a3;
1824331643Sdim *		int	a4;
1825331643Sdim *		int	a5;
1826331643Sdim *		int	a6;
1827331643Sdim *	} *uap;
1828194894Sjhb */
1829194894Sjhbint
1830331643Sdimsys_msgsys(struct thread *td, struct msgsys_args *uap)
1831194894Sjhb{
1832194894Sjhb	int error;
1833194894Sjhb
1834298354Spfg	if (uap->which < 0 || uap->which >= nitems(msgcalls))
1835194894Sjhb		return (EINVAL);
1836194894Sjhb	error = (*msgcalls[uap->which])(td, &uap->a2);
1837194894Sjhb	return (error);
1838194894Sjhb}
1839194910Sjhb
1840205323Skib#ifndef CP
1841194910Sjhb#define CP(src, dst, fld)	do { (dst).fld = (src).fld; } while (0)
1842205323Skib#endif
1843194910Sjhb
1844194910Sjhb#ifndef _SYS_SYSPROTO_H_
1845194910Sjhbstruct freebsd7_msgctl_args {
1846194910Sjhb	int	msqid;
1847194910Sjhb	int	cmd;
1848194910Sjhb	struct	msqid_ds_old *buf;
1849194910Sjhb};
1850194910Sjhb#endif
1851194910Sjhbint
1852331643Sdimfreebsd7_msgctl(struct thread *td, struct freebsd7_msgctl_args *uap)
1853194910Sjhb{
1854194910Sjhb	struct msqid_ds_old msqold;
1855194910Sjhb	struct msqid_ds msqbuf;
1856194910Sjhb	int error;
1857194910Sjhb
1858194910Sjhb	DPRINTF(("call to freebsd7_msgctl(%d, %d, %p)\n", uap->msqid, uap->cmd,
1859194910Sjhb	    uap->buf));
1860194910Sjhb	if (uap->cmd == IPC_SET) {
1861194910Sjhb		error = copyin(uap->buf, &msqold, sizeof(msqold));
1862194910Sjhb		if (error)
1863194910Sjhb			return (error);
1864194910Sjhb		ipcperm_old2new(&msqold.msg_perm, &msqbuf.msg_perm);
1865194910Sjhb		CP(msqold, msqbuf, msg_first);
1866194910Sjhb		CP(msqold, msqbuf, msg_last);
1867194910Sjhb		CP(msqold, msqbuf, msg_cbytes);
1868194910Sjhb		CP(msqold, msqbuf, msg_qnum);
1869194910Sjhb		CP(msqold, msqbuf, msg_qbytes);
1870194910Sjhb		CP(msqold, msqbuf, msg_lspid);
1871194910Sjhb		CP(msqold, msqbuf, msg_lrpid);
1872194910Sjhb		CP(msqold, msqbuf, msg_stime);
1873194910Sjhb		CP(msqold, msqbuf, msg_rtime);
1874194910Sjhb		CP(msqold, msqbuf, msg_ctime);
1875194910Sjhb	}
1876194910Sjhb	error = kern_msgctl(td, uap->msqid, uap->cmd, &msqbuf);
1877194910Sjhb	if (error)
1878194910Sjhb		return (error);
1879194910Sjhb	if (uap->cmd == IPC_STAT) {
1880194910Sjhb		bzero(&msqold, sizeof(msqold));
1881194910Sjhb		ipcperm_new2old(&msqbuf.msg_perm, &msqold.msg_perm);
1882194910Sjhb		CP(msqbuf, msqold, msg_first);
1883194910Sjhb		CP(msqbuf, msqold, msg_last);
1884194910Sjhb		CP(msqbuf, msqold, msg_cbytes);
1885194910Sjhb		CP(msqbuf, msqold, msg_qnum);
1886194910Sjhb		CP(msqbuf, msqold, msg_qbytes);
1887194910Sjhb		CP(msqbuf, msqold, msg_lspid);
1888194910Sjhb		CP(msqbuf, msqold, msg_lrpid);
1889194910Sjhb		CP(msqbuf, msqold, msg_stime);
1890194910Sjhb		CP(msqbuf, msqold, msg_rtime);
1891194910Sjhb		CP(msqbuf, msqold, msg_ctime);
1892194910Sjhb		error = copyout(&msqold, uap->buf, sizeof(struct msqid_ds_old));
1893194910Sjhb	}
1894194910Sjhb	return (error);
1895194910Sjhb}
1896194910Sjhb
1897194910Sjhb#undef CP
1898194910Sjhb
1899194894Sjhb#endif	/* COMPAT_FREEBSD4 || COMPAT_FREEBSD5 || COMPAT_FREEBSD6 ||
1900194894Sjhb	   COMPAT_FREEBSD7 */
1901