]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/kern/sysv_msg.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / kern / sysv_msg.c
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  * Copyright (c) 2003-2005 McAfee, Inc.
21  * All rights reserved.
22  *
23  * This software was developed for the FreeBSD Project in part by McAfee
24  * Research, the Security Research Division of McAfee, Inc under DARPA/SPAWAR
25  * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS research
26  * program.
27  *
28  * Redistribution and use in source and binary forms, with or without
29  * modification, are permitted provided that the following conditions
30  * are met:
31  * 1. Redistributions of source code must retain the above copyright
32  *    notice, this list of conditions and the following disclaimer.
33  * 2. Redistributions in binary form must reproduce the above copyright
34  *    notice, this list of conditions and the following disclaimer in the
35  *    documentation and/or other materials provided with the distribution.
36  *
37  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
38  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
40  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
41  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
42  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
43  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
45  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  */
49
50 #include <sys/cdefs.h>
51 __FBSDID("$FreeBSD$");
52
53 #include "opt_compat.h"
54 #include "opt_sysvipc.h"
55
56 #include <sys/param.h>
57 #include <sys/systm.h>
58 #include <sys/sysproto.h>
59 #include <sys/kernel.h>
60 #include <sys/priv.h>
61 #include <sys/proc.h>
62 #include <sys/lock.h>
63 #include <sys/mutex.h>
64 #include <sys/module.h>
65 #include <sys/msg.h>
66 #include <sys/syscall.h>
67 #include <sys/syscallsubr.h>
68 #include <sys/sysent.h>
69 #include <sys/sysctl.h>
70 #include <sys/malloc.h>
71 #include <sys/jail.h>
72
73 #include <security/mac/mac_framework.h>
74
75 static MALLOC_DEFINE(M_MSG, "msg", "SVID compatible message queues");
76
77 static int msginit(void);
78 static int msgunload(void);
79 static int sysvmsg_modload(struct module *, int, void *);
80
81 #ifdef MSG_DEBUG
82 #define DPRINTF(a)      printf a
83 #else
84 #define DPRINTF(a)      (void)0
85 #endif
86
87 static void msg_freehdr(struct msg *msghdr);
88
89 #ifndef MSGSSZ
90 #define MSGSSZ  8               /* Each segment must be 2^N long */
91 #endif
92 #ifndef MSGSEG
93 #define MSGSEG  2048            /* must be less than 32767 */
94 #endif
95 #define MSGMAX  (MSGSSZ*MSGSEG)
96 #ifndef MSGMNB
97 #define MSGMNB  2048            /* max # of bytes in a queue */
98 #endif
99 #ifndef MSGMNI
100 #define MSGMNI  40
101 #endif
102 #ifndef MSGTQL
103 #define MSGTQL  40
104 #endif
105
106 /*
107  * Based on the configuration parameters described in an SVR2 (yes, two)
108  * config(1m) man page.
109  *
110  * Each message is broken up and stored in segments that are msgssz bytes
111  * long.  For efficiency reasons, this should be a power of two.  Also,
112  * it doesn't make sense if it is less than 8 or greater than about 256.
113  * Consequently, msginit in kern/sysv_msg.c checks that msgssz is a power of
114  * two between 8 and 1024 inclusive (and panic's if it isn't).
115  */
116 struct msginfo msginfo = {
117                 MSGMAX,         /* max chars in a message */
118                 MSGMNI,         /* # of message queue identifiers */
119                 MSGMNB,         /* max chars in a queue */
120                 MSGTQL,         /* max messages in system */
121                 MSGSSZ,         /* size of a message segment */
122                                 /* (must be small power of 2 greater than 4) */
123                 MSGSEG          /* number of message segments */
124 };
125
126 /*
127  * macros to convert between msqid_ds's and msqid's.
128  * (specific to this implementation)
129  */
130 #define MSQID(ix,ds)    ((ix) & 0xffff | (((ds).msg_perm.seq << 16) & 0xffff0000))
131 #define MSQID_IX(id)    ((id) & 0xffff)
132 #define MSQID_SEQ(id)   (((id) >> 16) & 0xffff)
133
134 /*
135  * The rest of this file is specific to this particular implementation.
136  */
137
138 struct msgmap {
139         short   next;           /* next segment in buffer */
140                                 /* -1 -> available */
141                                 /* 0..(MSGSEG-1) -> index of next segment */
142 };
143
144 #define MSG_LOCKED      01000   /* Is this msqid_ds locked? */
145
146 static int nfree_msgmaps;       /* # of free map entries */
147 static short free_msgmaps;      /* head of linked list of free map entries */
148 static struct msg *free_msghdrs;/* list of free msg headers */
149 static char *msgpool;           /* MSGMAX byte long msg buffer pool */
150 static struct msgmap *msgmaps;  /* MSGSEG msgmap structures */
151 static struct msg *msghdrs;     /* MSGTQL msg headers */
152 static struct msqid_kernel *msqids;     /* MSGMNI msqid_kernel struct's */
153 static struct mtx msq_mtx;      /* global mutex for message queues. */
154
155 static struct syscall_helper_data msg_syscalls[] = {
156         SYSCALL_INIT_HELPER(msgctl),
157         SYSCALL_INIT_HELPER(msgget),
158         SYSCALL_INIT_HELPER(msgsnd),
159         SYSCALL_INIT_HELPER(msgrcv),
160 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
161     defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
162         SYSCALL_INIT_HELPER(msgsys),
163         SYSCALL_INIT_HELPER(freebsd7_msgctl),
164 #endif
165         SYSCALL_INIT_LAST
166 };
167
168 #ifdef COMPAT_FREEBSD32
169 #include <compat/freebsd32/freebsd32.h>
170 #include <compat/freebsd32/freebsd32_ipc.h>
171 #include <compat/freebsd32/freebsd32_proto.h>
172 #include <compat/freebsd32/freebsd32_signal.h>
173 #include <compat/freebsd32/freebsd32_syscall.h>
174 #include <compat/freebsd32/freebsd32_util.h>
175
176 static struct syscall_helper_data msg32_syscalls[] = {
177         SYSCALL32_INIT_HELPER(freebsd32_msgctl),
178         SYSCALL32_INIT_HELPER(freebsd32_msgsnd),
179         SYSCALL32_INIT_HELPER(freebsd32_msgrcv),
180         SYSCALL32_INIT_HELPER(msgget),
181         SYSCALL32_INIT_HELPER(freebsd32_msgsys),
182 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
183     defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
184         SYSCALL32_INIT_HELPER(freebsd7_freebsd32_msgctl),
185 #endif
186         SYSCALL_INIT_LAST
187 };
188 #endif
189
190 static int
191 msginit()
192 {
193         int i, error;
194
195         TUNABLE_INT_FETCH("kern.ipc.msgseg", &msginfo.msgseg);
196         TUNABLE_INT_FETCH("kern.ipc.msgssz", &msginfo.msgssz);
197         msginfo.msgmax = msginfo.msgseg * msginfo.msgssz;
198         TUNABLE_INT_FETCH("kern.ipc.msgmni", &msginfo.msgmni);
199         TUNABLE_INT_FETCH("kern.ipc.msgmnb", &msginfo.msgmnb);
200         TUNABLE_INT_FETCH("kern.ipc.msgtql", &msginfo.msgtql);
201
202         msgpool = malloc(msginfo.msgmax, M_MSG, M_WAITOK);
203         if (msgpool == NULL)
204                 panic("msgpool is NULL");
205         msgmaps = malloc(sizeof(struct msgmap) * msginfo.msgseg, M_MSG, M_WAITOK);
206         if (msgmaps == NULL)
207                 panic("msgmaps is NULL");
208         msghdrs = malloc(sizeof(struct msg) * msginfo.msgtql, M_MSG, M_WAITOK);
209         if (msghdrs == NULL)
210                 panic("msghdrs is NULL");
211         msqids = malloc(sizeof(struct msqid_kernel) * msginfo.msgmni, M_MSG,
212             M_WAITOK);
213         if (msqids == NULL)
214                 panic("msqids is NULL");
215
216         /*
217          * msginfo.msgssz should be a power of two for efficiency reasons.
218          * It is also pretty silly if msginfo.msgssz is less than 8
219          * or greater than about 256 so ...
220          */
221
222         i = 8;
223         while (i < 1024 && i != msginfo.msgssz)
224                 i <<= 1;
225         if (i != msginfo.msgssz) {
226                 DPRINTF(("msginfo.msgssz=%d (0x%x)\n", msginfo.msgssz,
227                     msginfo.msgssz));
228                 panic("msginfo.msgssz not a small power of 2");
229         }
230
231         if (msginfo.msgseg > 32767) {
232                 DPRINTF(("msginfo.msgseg=%d\n", msginfo.msgseg));
233                 panic("msginfo.msgseg > 32767");
234         }
235
236         if (msgmaps == NULL)
237                 panic("msgmaps is NULL");
238
239         for (i = 0; i < msginfo.msgseg; i++) {
240                 if (i > 0)
241                         msgmaps[i-1].next = i;
242                 msgmaps[i].next = -1;   /* implies entry is available */
243         }
244         free_msgmaps = 0;
245         nfree_msgmaps = msginfo.msgseg;
246
247         if (msghdrs == NULL)
248                 panic("msghdrs is NULL");
249
250         for (i = 0; i < msginfo.msgtql; i++) {
251                 msghdrs[i].msg_type = 0;
252                 if (i > 0)
253                         msghdrs[i-1].msg_next = &msghdrs[i];
254                 msghdrs[i].msg_next = NULL;
255 #ifdef MAC
256                 mac_sysvmsg_init(&msghdrs[i]);
257 #endif
258         }
259         free_msghdrs = &msghdrs[0];
260
261         if (msqids == NULL)
262                 panic("msqids is NULL");
263
264         for (i = 0; i < msginfo.msgmni; i++) {
265                 msqids[i].u.msg_qbytes = 0;     /* implies entry is available */
266                 msqids[i].u.msg_perm.seq = 0;   /* reset to a known value */
267                 msqids[i].u.msg_perm.mode = 0;
268 #ifdef MAC
269                 mac_sysvmsq_init(&msqids[i]);
270 #endif
271         }
272         mtx_init(&msq_mtx, "msq", NULL, MTX_DEF);
273
274         error = syscall_helper_register(msg_syscalls);
275         if (error != 0)
276                 return (error);
277 #ifdef COMPAT_FREEBSD32
278         error = syscall32_helper_register(msg32_syscalls);
279         if (error != 0)
280                 return (error);
281 #endif
282         return (0);
283 }
284
285 static int
286 msgunload()
287 {
288         struct msqid_kernel *msqkptr;
289         int msqid;
290 #ifdef MAC
291         int i;
292 #endif
293
294         syscall_helper_unregister(msg_syscalls);
295 #ifdef COMPAT_FREEBSD32
296         syscall32_helper_unregister(msg32_syscalls);
297 #endif
298
299         for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
300                 /*
301                  * Look for an unallocated and unlocked msqid_ds.
302                  * msqid_ds's can be locked by msgsnd or msgrcv while
303                  * they are copying the message in/out.  We can't
304                  * re-use the entry until they release it.
305                  */
306                 msqkptr = &msqids[msqid];
307                 if (msqkptr->u.msg_qbytes != 0 ||
308                     (msqkptr->u.msg_perm.mode & MSG_LOCKED) != 0)
309                         break;
310         }
311         if (msqid != msginfo.msgmni)
312                 return (EBUSY);
313
314 #ifdef MAC
315         for (i = 0; i < msginfo.msgtql; i++)
316                 mac_sysvmsg_destroy(&msghdrs[i]);
317         for (msqid = 0; msqid < msginfo.msgmni; msqid++)
318                 mac_sysvmsq_destroy(&msqids[msqid]);
319 #endif
320         free(msgpool, M_MSG);
321         free(msgmaps, M_MSG);
322         free(msghdrs, M_MSG);
323         free(msqids, M_MSG);
324         mtx_destroy(&msq_mtx);
325         return (0);
326 }
327
328
329 static int
330 sysvmsg_modload(struct module *module, int cmd, void *arg)
331 {
332         int error = 0;
333
334         switch (cmd) {
335         case MOD_LOAD:
336                 error = msginit();
337                 if (error != 0)
338                         msgunload();
339                 break;
340         case MOD_UNLOAD:
341                 error = msgunload();
342                 break;
343         case MOD_SHUTDOWN:
344                 break;
345         default:
346                 error = EINVAL;
347                 break;
348         }
349         return (error);
350 }
351
352 static moduledata_t sysvmsg_mod = {
353         "sysvmsg",
354         &sysvmsg_modload,
355         NULL
356 };
357
358 DECLARE_MODULE(sysvmsg, sysvmsg_mod, SI_SUB_SYSV_MSG, SI_ORDER_FIRST);
359 MODULE_VERSION(sysvmsg, 1);
360
361 static void
362 msg_freehdr(msghdr)
363         struct msg *msghdr;
364 {
365         while (msghdr->msg_ts > 0) {
366                 short next;
367                 if (msghdr->msg_spot < 0 || msghdr->msg_spot >= msginfo.msgseg)
368                         panic("msghdr->msg_spot out of range");
369                 next = msgmaps[msghdr->msg_spot].next;
370                 msgmaps[msghdr->msg_spot].next = free_msgmaps;
371                 free_msgmaps = msghdr->msg_spot;
372                 nfree_msgmaps++;
373                 msghdr->msg_spot = next;
374                 if (msghdr->msg_ts >= msginfo.msgssz)
375                         msghdr->msg_ts -= msginfo.msgssz;
376                 else
377                         msghdr->msg_ts = 0;
378         }
379         if (msghdr->msg_spot != -1)
380                 panic("msghdr->msg_spot != -1");
381         msghdr->msg_next = free_msghdrs;
382         free_msghdrs = msghdr;
383 #ifdef MAC
384         mac_sysvmsg_cleanup(msghdr);
385 #endif
386 }
387
388 #ifndef _SYS_SYSPROTO_H_
389 struct msgctl_args {
390         int     msqid;
391         int     cmd;
392         struct  msqid_ds *buf;
393 };
394 #endif
395 int
396 msgctl(td, uap)
397         struct thread *td;
398         register struct msgctl_args *uap;
399 {
400         int msqid = uap->msqid;
401         int cmd = uap->cmd;
402         struct msqid_ds msqbuf;
403         int error;
404
405         DPRINTF(("call to msgctl(%d, %d, %p)\n", msqid, cmd, uap->buf));
406         if (cmd == IPC_SET &&
407             (error = copyin(uap->buf, &msqbuf, sizeof(msqbuf))) != 0)
408                 return (error);
409         error = kern_msgctl(td, msqid, cmd, &msqbuf);
410         if (cmd == IPC_STAT && error == 0)
411                 error = copyout(&msqbuf, uap->buf, sizeof(struct msqid_ds));
412         return (error);
413 }
414
415 int
416 kern_msgctl(td, msqid, cmd, msqbuf)
417         struct thread *td;
418         int msqid;
419         int cmd;
420         struct msqid_ds *msqbuf;
421 {
422         int rval, error, msqix;
423         register struct msqid_kernel *msqkptr;
424
425         if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
426                 return (ENOSYS);
427
428         msqix = IPCID_TO_IX(msqid);
429
430         if (msqix < 0 || msqix >= msginfo.msgmni) {
431                 DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqix,
432                     msginfo.msgmni));
433                 return (EINVAL);
434         }
435
436         msqkptr = &msqids[msqix];
437
438         mtx_lock(&msq_mtx);
439         if (msqkptr->u.msg_qbytes == 0) {
440                 DPRINTF(("no such msqid\n"));
441                 error = EINVAL;
442                 goto done2;
443         }
444         if (msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) {
445                 DPRINTF(("wrong sequence number\n"));
446                 error = EINVAL;
447                 goto done2;
448         }
449 #ifdef MAC
450         error = mac_sysvmsq_check_msqctl(td->td_ucred, msqkptr, cmd);
451         if (error != 0)
452                 goto done2;
453 #endif
454
455         error = 0;
456         rval = 0;
457
458         switch (cmd) {
459
460         case IPC_RMID:
461         {
462                 struct msg *msghdr;
463                 if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_M)))
464                         goto done2;
465
466 #ifdef MAC
467                 /*
468                  * Check that the thread has MAC access permissions to
469                  * individual msghdrs.  Note: We need to do this in a
470                  * separate loop because the actual loop alters the
471                  * msq/msghdr info as it progresses, and there is no going
472                  * back if half the way through we discover that the
473                  * thread cannot free a certain msghdr.  The msq will get
474                  * into an inconsistent state.
475                  */
476                 for (msghdr = msqkptr->u.msg_first; msghdr != NULL;
477                     msghdr = msghdr->msg_next) {
478                         error = mac_sysvmsq_check_msgrmid(td->td_ucred, msghdr);
479                         if (error != 0)
480                                 goto done2;
481                 }
482 #endif
483
484                 /* Free the message headers */
485                 msghdr = msqkptr->u.msg_first;
486                 while (msghdr != NULL) {
487                         struct msg *msghdr_tmp;
488
489                         /* Free the segments of each message */
490                         msqkptr->u.msg_cbytes -= msghdr->msg_ts;
491                         msqkptr->u.msg_qnum--;
492                         msghdr_tmp = msghdr;
493                         msghdr = msghdr->msg_next;
494                         msg_freehdr(msghdr_tmp);
495                 }
496
497                 if (msqkptr->u.msg_cbytes != 0)
498                         panic("msg_cbytes is screwed up");
499                 if (msqkptr->u.msg_qnum != 0)
500                         panic("msg_qnum is screwed up");
501
502                 msqkptr->u.msg_qbytes = 0;      /* Mark it as free */
503
504 #ifdef MAC
505                 mac_sysvmsq_cleanup(msqkptr);
506 #endif
507
508                 wakeup(msqkptr);
509         }
510
511                 break;
512
513         case IPC_SET:
514                 if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_M)))
515                         goto done2;
516                 if (msqbuf->msg_qbytes > msqkptr->u.msg_qbytes) {
517                         error = priv_check(td, PRIV_IPC_MSGSIZE);
518                         if (error)
519                                 goto done2;
520                 }
521                 if (msqbuf->msg_qbytes > msginfo.msgmnb) {
522                         DPRINTF(("can't increase msg_qbytes beyond %d"
523                             "(truncating)\n", msginfo.msgmnb));
524                         msqbuf->msg_qbytes = msginfo.msgmnb;    /* silently restrict qbytes to system limit */
525                 }
526                 if (msqbuf->msg_qbytes == 0) {
527                         DPRINTF(("can't reduce msg_qbytes to 0\n"));
528                         error = EINVAL;         /* non-standard errno! */
529                         goto done2;
530                 }
531                 msqkptr->u.msg_perm.uid = msqbuf->msg_perm.uid; /* change the owner */
532                 msqkptr->u.msg_perm.gid = msqbuf->msg_perm.gid; /* change the owner */
533                 msqkptr->u.msg_perm.mode = (msqkptr->u.msg_perm.mode & ~0777) |
534                     (msqbuf->msg_perm.mode & 0777);
535                 msqkptr->u.msg_qbytes = msqbuf->msg_qbytes;
536                 msqkptr->u.msg_ctime = time_second;
537                 break;
538
539         case IPC_STAT:
540                 if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_R))) {
541                         DPRINTF(("requester doesn't have read access\n"));
542                         goto done2;
543                 }
544                 *msqbuf = msqkptr->u;
545                 break;
546
547         default:
548                 DPRINTF(("invalid command %d\n", cmd));
549                 error = EINVAL;
550                 goto done2;
551         }
552
553         if (error == 0)
554                 td->td_retval[0] = rval;
555 done2:
556         mtx_unlock(&msq_mtx);
557         return (error);
558 }
559
560 #ifndef _SYS_SYSPROTO_H_
561 struct msgget_args {
562         key_t   key;
563         int     msgflg;
564 };
565 #endif
566 int
567 msgget(td, uap)
568         struct thread *td;
569         register struct msgget_args *uap;
570 {
571         int msqid, error = 0;
572         int key = uap->key;
573         int msgflg = uap->msgflg;
574         struct ucred *cred = td->td_ucred;
575         register struct msqid_kernel *msqkptr = NULL;
576
577         DPRINTF(("msgget(0x%x, 0%o)\n", key, msgflg));
578
579         if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
580                 return (ENOSYS);
581
582         mtx_lock(&msq_mtx);
583         if (key != IPC_PRIVATE) {
584                 for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
585                         msqkptr = &msqids[msqid];
586                         if (msqkptr->u.msg_qbytes != 0 &&
587                             msqkptr->u.msg_perm.key == key)
588                                 break;
589                 }
590                 if (msqid < msginfo.msgmni) {
591                         DPRINTF(("found public key\n"));
592                         if ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL)) {
593                                 DPRINTF(("not exclusive\n"));
594                                 error = EEXIST;
595                                 goto done2;
596                         }
597                         if ((error = ipcperm(td, &msqkptr->u.msg_perm,
598                             msgflg & 0700))) {
599                                 DPRINTF(("requester doesn't have 0%o access\n",
600                                     msgflg & 0700));
601                                 goto done2;
602                         }
603 #ifdef MAC
604                         error = mac_sysvmsq_check_msqget(cred, msqkptr);
605                         if (error != 0)
606                                 goto done2;
607 #endif
608                         goto found;
609                 }
610         }
611
612         DPRINTF(("need to allocate the msqid_ds\n"));
613         if (key == IPC_PRIVATE || (msgflg & IPC_CREAT)) {
614                 for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
615                         /*
616                          * Look for an unallocated and unlocked msqid_ds.
617                          * msqid_ds's can be locked by msgsnd or msgrcv while
618                          * they are copying the message in/out.  We can't
619                          * re-use the entry until they release it.
620                          */
621                         msqkptr = &msqids[msqid];
622                         if (msqkptr->u.msg_qbytes == 0 &&
623                             (msqkptr->u.msg_perm.mode & MSG_LOCKED) == 0)
624                                 break;
625                 }
626                 if (msqid == msginfo.msgmni) {
627                         DPRINTF(("no more msqid_ds's available\n"));
628                         error = ENOSPC;
629                         goto done2;
630                 }
631                 DPRINTF(("msqid %d is available\n", msqid));
632                 msqkptr->u.msg_perm.key = key;
633                 msqkptr->u.msg_perm.cuid = cred->cr_uid;
634                 msqkptr->u.msg_perm.uid = cred->cr_uid;
635                 msqkptr->u.msg_perm.cgid = cred->cr_gid;
636                 msqkptr->u.msg_perm.gid = cred->cr_gid;
637                 msqkptr->u.msg_perm.mode = (msgflg & 0777);
638                 /* Make sure that the returned msqid is unique */
639                 msqkptr->u.msg_perm.seq = (msqkptr->u.msg_perm.seq + 1) & 0x7fff;
640                 msqkptr->u.msg_first = NULL;
641                 msqkptr->u.msg_last = NULL;
642                 msqkptr->u.msg_cbytes = 0;
643                 msqkptr->u.msg_qnum = 0;
644                 msqkptr->u.msg_qbytes = msginfo.msgmnb;
645                 msqkptr->u.msg_lspid = 0;
646                 msqkptr->u.msg_lrpid = 0;
647                 msqkptr->u.msg_stime = 0;
648                 msqkptr->u.msg_rtime = 0;
649                 msqkptr->u.msg_ctime = time_second;
650 #ifdef MAC
651                 mac_sysvmsq_create(cred, msqkptr);
652 #endif
653         } else {
654                 DPRINTF(("didn't find it and wasn't asked to create it\n"));
655                 error = ENOENT;
656                 goto done2;
657         }
658
659 found:
660         /* Construct the unique msqid */
661         td->td_retval[0] = IXSEQ_TO_IPCID(msqid, msqkptr->u.msg_perm);
662 done2:
663         mtx_unlock(&msq_mtx);
664         return (error);
665 }
666
667 #ifndef _SYS_SYSPROTO_H_
668 struct msgsnd_args {
669         int     msqid;
670         const void      *msgp;
671         size_t  msgsz;
672         int     msgflg;
673 };
674 #endif
675 int
676 kern_msgsnd(td, msqid, msgp, msgsz, msgflg, mtype)
677         struct thread *td;
678         int msqid;
679         const void *msgp;       /* XXX msgp is actually mtext. */
680         size_t msgsz;
681         int msgflg;
682         long mtype;
683 {
684         int msqix, segs_needed, error = 0;
685         register struct msqid_kernel *msqkptr;
686         register struct msg *msghdr;
687         short next;
688
689         if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
690                 return (ENOSYS);
691
692         mtx_lock(&msq_mtx);
693         msqix = IPCID_TO_IX(msqid);
694
695         if (msqix < 0 || msqix >= msginfo.msgmni) {
696                 DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqix,
697                     msginfo.msgmni));
698                 error = EINVAL;
699                 goto done2;
700         }
701
702         msqkptr = &msqids[msqix];
703         if (msqkptr->u.msg_qbytes == 0) {
704                 DPRINTF(("no such message queue id\n"));
705                 error = EINVAL;
706                 goto done2;
707         }
708         if (msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) {
709                 DPRINTF(("wrong sequence number\n"));
710                 error = EINVAL;
711                 goto done2;
712         }
713
714         if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_W))) {
715                 DPRINTF(("requester doesn't have write access\n"));
716                 goto done2;
717         }
718
719 #ifdef MAC
720         error = mac_sysvmsq_check_msqsnd(td->td_ucred, msqkptr);
721         if (error != 0)
722                 goto done2;
723 #endif
724
725         segs_needed = (msgsz + msginfo.msgssz - 1) / msginfo.msgssz;
726         DPRINTF(("msgsz=%zu, msgssz=%d, segs_needed=%d\n", msgsz,
727             msginfo.msgssz, segs_needed));
728         for (;;) {
729                 int need_more_resources = 0;
730
731                 /*
732                  * check msgsz
733                  * (inside this loop in case msg_qbytes changes while we sleep)
734                  */
735
736                 if (msgsz > msqkptr->u.msg_qbytes) {
737                         DPRINTF(("msgsz > msqkptr->u.msg_qbytes\n"));
738                         error = EINVAL;
739                         goto done2;
740                 }
741
742                 if (msqkptr->u.msg_perm.mode & MSG_LOCKED) {
743                         DPRINTF(("msqid is locked\n"));
744                         need_more_resources = 1;
745                 }
746                 if (msgsz + msqkptr->u.msg_cbytes > msqkptr->u.msg_qbytes) {
747                         DPRINTF(("msgsz + msg_cbytes > msg_qbytes\n"));
748                         need_more_resources = 1;
749                 }
750                 if (segs_needed > nfree_msgmaps) {
751                         DPRINTF(("segs_needed > nfree_msgmaps\n"));
752                         need_more_resources = 1;
753                 }
754                 if (free_msghdrs == NULL) {
755                         DPRINTF(("no more msghdrs\n"));
756                         need_more_resources = 1;
757                 }
758
759                 if (need_more_resources) {
760                         int we_own_it;
761
762                         if ((msgflg & IPC_NOWAIT) != 0) {
763                                 DPRINTF(("need more resources but caller "
764                                     "doesn't want to wait\n"));
765                                 error = EAGAIN;
766                                 goto done2;
767                         }
768
769                         if ((msqkptr->u.msg_perm.mode & MSG_LOCKED) != 0) {
770                                 DPRINTF(("we don't own the msqid_ds\n"));
771                                 we_own_it = 0;
772                         } else {
773                                 /* Force later arrivals to wait for our
774                                    request */
775                                 DPRINTF(("we own the msqid_ds\n"));
776                                 msqkptr->u.msg_perm.mode |= MSG_LOCKED;
777                                 we_own_it = 1;
778                         }
779                         DPRINTF(("msgsnd:  goodnight\n"));
780                         error = msleep(msqkptr, &msq_mtx, (PZERO - 4) | PCATCH,
781                             "msgsnd", hz);
782                         DPRINTF(("msgsnd:  good morning, error=%d\n", error));
783                         if (we_own_it)
784                                 msqkptr->u.msg_perm.mode &= ~MSG_LOCKED;
785                         if (error == EWOULDBLOCK) {
786                                 DPRINTF(("msgsnd:  timed out\n"));
787                                 continue;
788                         }
789                         if (error != 0) {
790                                 DPRINTF(("msgsnd:  interrupted system call\n"));
791                                 error = EINTR;
792                                 goto done2;
793                         }
794
795                         /*
796                          * Make sure that the msq queue still exists
797                          */
798
799                         if (msqkptr->u.msg_qbytes == 0) {
800                                 DPRINTF(("msqid deleted\n"));
801                                 error = EIDRM;
802                                 goto done2;
803                         }
804
805                 } else {
806                         DPRINTF(("got all the resources that we need\n"));
807                         break;
808                 }
809         }
810
811         /*
812          * We have the resources that we need.
813          * Make sure!
814          */
815
816         if (msqkptr->u.msg_perm.mode & MSG_LOCKED)
817                 panic("msg_perm.mode & MSG_LOCKED");
818         if (segs_needed > nfree_msgmaps)
819                 panic("segs_needed > nfree_msgmaps");
820         if (msgsz + msqkptr->u.msg_cbytes > msqkptr->u.msg_qbytes)
821                 panic("msgsz + msg_cbytes > msg_qbytes");
822         if (free_msghdrs == NULL)
823                 panic("no more msghdrs");
824
825         /*
826          * Re-lock the msqid_ds in case we page-fault when copying in the
827          * message
828          */
829
830         if ((msqkptr->u.msg_perm.mode & MSG_LOCKED) != 0)
831                 panic("msqid_ds is already locked");
832         msqkptr->u.msg_perm.mode |= MSG_LOCKED;
833
834         /*
835          * Allocate a message header
836          */
837
838         msghdr = free_msghdrs;
839         free_msghdrs = msghdr->msg_next;
840         msghdr->msg_spot = -1;
841         msghdr->msg_ts = msgsz;
842         msghdr->msg_type = mtype;
843 #ifdef MAC
844         /*
845          * XXXMAC: Should the mac_sysvmsq_check_msgmsq check follow here
846          * immediately?  Or, should it be checked just before the msg is
847          * enqueued in the msgq (as it is done now)?
848          */
849         mac_sysvmsg_create(td->td_ucred, msqkptr, msghdr);
850 #endif
851
852         /*
853          * Allocate space for the message
854          */
855
856         while (segs_needed > 0) {
857                 if (nfree_msgmaps <= 0)
858                         panic("not enough msgmaps");
859                 if (free_msgmaps == -1)
860                         panic("nil free_msgmaps");
861                 next = free_msgmaps;
862                 if (next <= -1)
863                         panic("next too low #1");
864                 if (next >= msginfo.msgseg)
865                         panic("next out of range #1");
866                 DPRINTF(("allocating segment %d to message\n", next));
867                 free_msgmaps = msgmaps[next].next;
868                 nfree_msgmaps--;
869                 msgmaps[next].next = msghdr->msg_spot;
870                 msghdr->msg_spot = next;
871                 segs_needed--;
872         }
873
874         /*
875          * Validate the message type
876          */
877
878         if (msghdr->msg_type < 1) {
879                 msg_freehdr(msghdr);
880                 msqkptr->u.msg_perm.mode &= ~MSG_LOCKED;
881                 wakeup(msqkptr);
882                 DPRINTF(("mtype (%ld) < 1\n", msghdr->msg_type));
883                 error = EINVAL;
884                 goto done2;
885         }
886
887         /*
888          * Copy in the message body
889          */
890
891         next = msghdr->msg_spot;
892         while (msgsz > 0) {
893                 size_t tlen;
894                 if (msgsz > msginfo.msgssz)
895                         tlen = msginfo.msgssz;
896                 else
897                         tlen = msgsz;
898                 if (next <= -1)
899                         panic("next too low #2");
900                 if (next >= msginfo.msgseg)
901                         panic("next out of range #2");
902                 mtx_unlock(&msq_mtx);
903                 if ((error = copyin(msgp, &msgpool[next * msginfo.msgssz],
904                     tlen)) != 0) {
905                         mtx_lock(&msq_mtx);
906                         DPRINTF(("error %d copying in message segment\n",
907                             error));
908                         msg_freehdr(msghdr);
909                         msqkptr->u.msg_perm.mode &= ~MSG_LOCKED;
910                         wakeup(msqkptr);
911                         goto done2;
912                 }
913                 mtx_lock(&msq_mtx);
914                 msgsz -= tlen;
915                 msgp = (const char *)msgp + tlen;
916                 next = msgmaps[next].next;
917         }
918         if (next != -1)
919                 panic("didn't use all the msg segments");
920
921         /*
922          * We've got the message.  Unlock the msqid_ds.
923          */
924
925         msqkptr->u.msg_perm.mode &= ~MSG_LOCKED;
926
927         /*
928          * Make sure that the msqid_ds is still allocated.
929          */
930
931         if (msqkptr->u.msg_qbytes == 0) {
932                 msg_freehdr(msghdr);
933                 wakeup(msqkptr);
934                 error = EIDRM;
935                 goto done2;
936         }
937
938 #ifdef MAC
939         /*
940          * Note: Since the task/thread allocates the msghdr and usually
941          * primes it with its own MAC label, for a majority of policies, it
942          * won't be necessary to check whether the msghdr has access
943          * permissions to the msgq.  The mac_sysvmsq_check_msqsnd check would
944          * suffice in that case.  However, this hook may be required where
945          * individual policies derive a non-identical label for the msghdr
946          * from the current thread label and may want to check the msghdr
947          * enqueue permissions, along with read/write permissions to the
948          * msgq.
949          */
950         error = mac_sysvmsq_check_msgmsq(td->td_ucred, msghdr, msqkptr);
951         if (error != 0) {
952                 msg_freehdr(msghdr);
953                 wakeup(msqkptr);
954                 goto done2;
955         }
956 #endif
957
958         /*
959          * Put the message into the queue
960          */
961         if (msqkptr->u.msg_first == NULL) {
962                 msqkptr->u.msg_first = msghdr;
963                 msqkptr->u.msg_last = msghdr;
964         } else {
965                 msqkptr->u.msg_last->msg_next = msghdr;
966                 msqkptr->u.msg_last = msghdr;
967         }
968         msqkptr->u.msg_last->msg_next = NULL;
969
970         msqkptr->u.msg_cbytes += msghdr->msg_ts;
971         msqkptr->u.msg_qnum++;
972         msqkptr->u.msg_lspid = td->td_proc->p_pid;
973         msqkptr->u.msg_stime = time_second;
974
975         wakeup(msqkptr);
976         td->td_retval[0] = 0;
977 done2:
978         mtx_unlock(&msq_mtx);
979         return (error);
980 }
981
982 int
983 msgsnd(td, uap)
984         struct thread *td;
985         register struct msgsnd_args *uap;
986 {
987         int error;
988         long mtype;
989
990         DPRINTF(("call to msgsnd(%d, %p, %zu, %d)\n", uap->msqid, uap->msgp,
991             uap->msgsz, uap->msgflg));
992
993         if ((error = copyin(uap->msgp, &mtype, sizeof(mtype))) != 0) {
994                 DPRINTF(("error %d copying the message type\n", error));
995                 return (error);
996         }
997         return (kern_msgsnd(td, uap->msqid,
998             (const char *)uap->msgp + sizeof(mtype),
999             uap->msgsz, uap->msgflg, mtype));
1000 }
1001
1002 #ifndef _SYS_SYSPROTO_H_
1003 struct msgrcv_args {
1004         int     msqid;
1005         void    *msgp;
1006         size_t  msgsz;
1007         long    msgtyp;
1008         int     msgflg;
1009 };
1010 #endif
1011 int
1012 kern_msgrcv(td, msqid, msgp, msgsz, msgtyp, msgflg, mtype)
1013         struct thread *td;
1014         int msqid;
1015         void *msgp;     /* XXX msgp is actually mtext. */
1016         size_t msgsz;
1017         long msgtyp;
1018         int msgflg;
1019         long *mtype;
1020 {
1021         size_t len;
1022         register struct msqid_kernel *msqkptr;
1023         register struct msg *msghdr;
1024         int msqix, error = 0;
1025         short next;
1026
1027         if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
1028                 return (ENOSYS);
1029
1030         msqix = IPCID_TO_IX(msqid);
1031
1032         if (msqix < 0 || msqix >= msginfo.msgmni) {
1033                 DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqix,
1034                     msginfo.msgmni));
1035                 return (EINVAL);
1036         }
1037
1038         msqkptr = &msqids[msqix];
1039         mtx_lock(&msq_mtx);
1040         if (msqkptr->u.msg_qbytes == 0) {
1041                 DPRINTF(("no such message queue id\n"));
1042                 error = EINVAL;
1043                 goto done2;
1044         }
1045         if (msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) {
1046                 DPRINTF(("wrong sequence number\n"));
1047                 error = EINVAL;
1048                 goto done2;
1049         }
1050
1051         if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_R))) {
1052                 DPRINTF(("requester doesn't have read access\n"));
1053                 goto done2;
1054         }
1055
1056 #ifdef MAC
1057         error = mac_sysvmsq_check_msqrcv(td->td_ucred, msqkptr);
1058         if (error != 0)
1059                 goto done2;
1060 #endif
1061
1062         msghdr = NULL;
1063         while (msghdr == NULL) {
1064                 if (msgtyp == 0) {
1065                         msghdr = msqkptr->u.msg_first;
1066                         if (msghdr != NULL) {
1067                                 if (msgsz < msghdr->msg_ts &&
1068                                     (msgflg & MSG_NOERROR) == 0) {
1069                                         DPRINTF(("first message on the queue "
1070                                             "is too big (want %zu, got %d)\n",
1071                                             msgsz, msghdr->msg_ts));
1072                                         error = E2BIG;
1073                                         goto done2;
1074                                 }
1075 #ifdef MAC
1076                                 error = mac_sysvmsq_check_msgrcv(td->td_ucred,
1077                                     msghdr);
1078                                 if (error != 0)
1079                                         goto done2;
1080 #endif
1081                                 if (msqkptr->u.msg_first == msqkptr->u.msg_last) {
1082                                         msqkptr->u.msg_first = NULL;
1083                                         msqkptr->u.msg_last = NULL;
1084                                 } else {
1085                                         msqkptr->u.msg_first = msghdr->msg_next;
1086                                         if (msqkptr->u.msg_first == NULL)
1087                                                 panic("msg_first/last screwed up #1");
1088                                 }
1089                         }
1090                 } else {
1091                         struct msg *previous;
1092                         struct msg **prev;
1093
1094                         previous = NULL;
1095                         prev = &(msqkptr->u.msg_first);
1096                         while ((msghdr = *prev) != NULL) {
1097                                 /*
1098                                  * Is this message's type an exact match or is
1099                                  * this message's type less than or equal to
1100                                  * the absolute value of a negative msgtyp?
1101                                  * Note that the second half of this test can
1102                                  * NEVER be true if msgtyp is positive since
1103                                  * msg_type is always positive!
1104                                  */
1105
1106                                 if (msgtyp == msghdr->msg_type ||
1107                                     msghdr->msg_type <= -msgtyp) {
1108                                         DPRINTF(("found message type %ld, "
1109                                             "requested %ld\n",
1110                                             msghdr->msg_type, msgtyp));
1111                                         if (msgsz < msghdr->msg_ts &&
1112                                             (msgflg & MSG_NOERROR) == 0) {
1113                                                 DPRINTF(("requested message "
1114                                                     "on the queue is too big "
1115                                                     "(want %zu, got %hu)\n",
1116                                                     msgsz, msghdr->msg_ts));
1117                                                 error = E2BIG;
1118                                                 goto done2;
1119                                         }
1120 #ifdef MAC
1121                                         error = mac_sysvmsq_check_msgrcv(
1122                                             td->td_ucred, msghdr);
1123                                         if (error != 0)
1124                                                 goto done2;
1125 #endif
1126                                         *prev = msghdr->msg_next;
1127                                         if (msghdr == msqkptr->u.msg_last) {
1128                                                 if (previous == NULL) {
1129                                                         if (prev !=
1130                                                             &msqkptr->u.msg_first)
1131                                                                 panic("msg_first/last screwed up #2");
1132                                                         msqkptr->u.msg_first =
1133                                                             NULL;
1134                                                         msqkptr->u.msg_last =
1135                                                             NULL;
1136                                                 } else {
1137                                                         if (prev ==
1138                                                             &msqkptr->u.msg_first)
1139                                                                 panic("msg_first/last screwed up #3");
1140                                                         msqkptr->u.msg_last =
1141                                                             previous;
1142                                                 }
1143                                         }
1144                                         break;
1145                                 }
1146                                 previous = msghdr;
1147                                 prev = &(msghdr->msg_next);
1148                         }
1149                 }
1150
1151                 /*
1152                  * We've either extracted the msghdr for the appropriate
1153                  * message or there isn't one.
1154                  * If there is one then bail out of this loop.
1155                  */
1156
1157                 if (msghdr != NULL)
1158                         break;
1159
1160                 /*
1161                  * Hmph!  No message found.  Does the user want to wait?
1162                  */
1163
1164                 if ((msgflg & IPC_NOWAIT) != 0) {
1165                         DPRINTF(("no appropriate message found (msgtyp=%ld)\n",
1166                             msgtyp));
1167                         /* The SVID says to return ENOMSG. */
1168                         error = ENOMSG;
1169                         goto done2;
1170                 }
1171
1172                 /*
1173                  * Wait for something to happen
1174                  */
1175
1176                 DPRINTF(("msgrcv:  goodnight\n"));
1177                 error = msleep(msqkptr, &msq_mtx, (PZERO - 4) | PCATCH,
1178                     "msgrcv", 0);
1179                 DPRINTF(("msgrcv:  good morning (error=%d)\n", error));
1180
1181                 if (error != 0) {
1182                         DPRINTF(("msgrcv:  interrupted system call\n"));
1183                         error = EINTR;
1184                         goto done2;
1185                 }
1186
1187                 /*
1188                  * Make sure that the msq queue still exists
1189                  */
1190
1191                 if (msqkptr->u.msg_qbytes == 0 ||
1192                     msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) {
1193                         DPRINTF(("msqid deleted\n"));
1194                         error = EIDRM;
1195                         goto done2;
1196                 }
1197         }
1198
1199         /*
1200          * Return the message to the user.
1201          *
1202          * First, do the bookkeeping (before we risk being interrupted).
1203          */
1204
1205         msqkptr->u.msg_cbytes -= msghdr->msg_ts;
1206         msqkptr->u.msg_qnum--;
1207         msqkptr->u.msg_lrpid = td->td_proc->p_pid;
1208         msqkptr->u.msg_rtime = time_second;
1209
1210         /*
1211          * Make msgsz the actual amount that we'll be returning.
1212          * Note that this effectively truncates the message if it is too long
1213          * (since msgsz is never increased).
1214          */
1215
1216         DPRINTF(("found a message, msgsz=%zu, msg_ts=%hu\n", msgsz,
1217             msghdr->msg_ts));
1218         if (msgsz > msghdr->msg_ts)
1219                 msgsz = msghdr->msg_ts;
1220         *mtype = msghdr->msg_type;
1221
1222         /*
1223          * Return the segments to the user
1224          */
1225
1226         next = msghdr->msg_spot;
1227         for (len = 0; len < msgsz; len += msginfo.msgssz) {
1228                 size_t tlen;
1229
1230                 if (msgsz - len > msginfo.msgssz)
1231                         tlen = msginfo.msgssz;
1232                 else
1233                         tlen = msgsz - len;
1234                 if (next <= -1)
1235                         panic("next too low #3");
1236                 if (next >= msginfo.msgseg)
1237                         panic("next out of range #3");
1238                 mtx_unlock(&msq_mtx);
1239                 error = copyout(&msgpool[next * msginfo.msgssz], msgp, tlen);
1240                 mtx_lock(&msq_mtx);
1241                 if (error != 0) {
1242                         DPRINTF(("error (%d) copying out message segment\n",
1243                             error));
1244                         msg_freehdr(msghdr);
1245                         wakeup(msqkptr);
1246                         goto done2;
1247                 }
1248                 msgp = (char *)msgp + tlen;
1249                 next = msgmaps[next].next;
1250         }
1251
1252         /*
1253          * Done, return the actual number of bytes copied out.
1254          */
1255
1256         msg_freehdr(msghdr);
1257         wakeup(msqkptr);
1258         td->td_retval[0] = msgsz;
1259 done2:
1260         mtx_unlock(&msq_mtx);
1261         return (error);
1262 }
1263
1264 int
1265 msgrcv(td, uap)
1266         struct thread *td;
1267         register struct msgrcv_args *uap;
1268 {
1269         int error;
1270         long mtype;
1271
1272         DPRINTF(("call to msgrcv(%d, %p, %zu, %ld, %d)\n", uap->msqid,
1273             uap->msgp, uap->msgsz, uap->msgtyp, uap->msgflg));
1274
1275         if ((error = kern_msgrcv(td, uap->msqid,
1276             (char *)uap->msgp + sizeof(mtype), uap->msgsz,
1277             uap->msgtyp, uap->msgflg, &mtype)) != 0)
1278                 return (error);
1279         if ((error = copyout(&mtype, uap->msgp, sizeof(mtype))) != 0)
1280                 DPRINTF(("error %d copying the message type\n", error));
1281         return (error);
1282 }
1283
1284 static int
1285 sysctl_msqids(SYSCTL_HANDLER_ARGS)
1286 {
1287
1288         return (SYSCTL_OUT(req, msqids,
1289             sizeof(struct msqid_kernel) * msginfo.msgmni));
1290 }
1291
1292 SYSCTL_INT(_kern_ipc, OID_AUTO, msgmax, CTLFLAG_RD, &msginfo.msgmax, 0,
1293     "Maximum message size");
1294 SYSCTL_INT(_kern_ipc, OID_AUTO, msgmni, CTLFLAG_RDTUN, &msginfo.msgmni, 0,
1295     "Number of message queue identifiers");
1296 SYSCTL_INT(_kern_ipc, OID_AUTO, msgmnb, CTLFLAG_RDTUN, &msginfo.msgmnb, 0,
1297     "Maximum number of bytes in a queue");
1298 SYSCTL_INT(_kern_ipc, OID_AUTO, msgtql, CTLFLAG_RDTUN, &msginfo.msgtql, 0,
1299     "Maximum number of messages in the system");
1300 SYSCTL_INT(_kern_ipc, OID_AUTO, msgssz, CTLFLAG_RDTUN, &msginfo.msgssz, 0,
1301     "Size of a message segment");
1302 SYSCTL_INT(_kern_ipc, OID_AUTO, msgseg, CTLFLAG_RDTUN, &msginfo.msgseg, 0,
1303     "Number of message segments");
1304 SYSCTL_PROC(_kern_ipc, OID_AUTO, msqids, CTLFLAG_RD,
1305     NULL, 0, sysctl_msqids, "", "Message queue IDs");
1306
1307 #ifdef COMPAT_FREEBSD32
1308 int
1309 freebsd32_msgsys(struct thread *td, struct freebsd32_msgsys_args *uap)
1310 {
1311
1312 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
1313     defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
1314         switch (uap->which) {
1315         case 0:
1316                 return (freebsd7_freebsd32_msgctl(td,
1317                     (struct freebsd7_freebsd32_msgctl_args *)&uap->a2));
1318         case 2:
1319                 return (freebsd32_msgsnd(td,
1320                     (struct freebsd32_msgsnd_args *)&uap->a2));
1321         case 3:
1322                 return (freebsd32_msgrcv(td,
1323                     (struct freebsd32_msgrcv_args *)&uap->a2));
1324         default:
1325                 return (msgsys(td, (struct msgsys_args *)uap));
1326         }
1327 #else
1328         return (nosys(td, NULL));
1329 #endif
1330 }
1331
1332 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
1333     defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
1334 int
1335 freebsd7_freebsd32_msgctl(struct thread *td,
1336     struct freebsd7_freebsd32_msgctl_args *uap)
1337 {
1338         struct msqid_ds msqbuf;
1339         struct msqid_ds32_old msqbuf32;
1340         int error;
1341
1342         if (uap->cmd == IPC_SET) {
1343                 error = copyin(uap->buf, &msqbuf32, sizeof(msqbuf32));
1344                 if (error)
1345                         return (error);
1346                 freebsd32_ipcperm_old_in(&msqbuf32.msg_perm, &msqbuf.msg_perm);
1347                 PTRIN_CP(msqbuf32, msqbuf, msg_first);
1348                 PTRIN_CP(msqbuf32, msqbuf, msg_last);
1349                 CP(msqbuf32, msqbuf, msg_cbytes);
1350                 CP(msqbuf32, msqbuf, msg_qnum);
1351                 CP(msqbuf32, msqbuf, msg_qbytes);
1352                 CP(msqbuf32, msqbuf, msg_lspid);
1353                 CP(msqbuf32, msqbuf, msg_lrpid);
1354                 CP(msqbuf32, msqbuf, msg_stime);
1355                 CP(msqbuf32, msqbuf, msg_rtime);
1356                 CP(msqbuf32, msqbuf, msg_ctime);
1357         }
1358         error = kern_msgctl(td, uap->msqid, uap->cmd, &msqbuf);
1359         if (error)
1360                 return (error);
1361         if (uap->cmd == IPC_STAT) {
1362                 bzero(&msqbuf32, sizeof(msqbuf32));
1363                 freebsd32_ipcperm_old_out(&msqbuf.msg_perm, &msqbuf32.msg_perm);
1364                 PTROUT_CP(msqbuf, msqbuf32, msg_first);
1365                 PTROUT_CP(msqbuf, msqbuf32, msg_last);
1366                 CP(msqbuf, msqbuf32, msg_cbytes);
1367                 CP(msqbuf, msqbuf32, msg_qnum);
1368                 CP(msqbuf, msqbuf32, msg_qbytes);
1369                 CP(msqbuf, msqbuf32, msg_lspid);
1370                 CP(msqbuf, msqbuf32, msg_lrpid);
1371                 CP(msqbuf, msqbuf32, msg_stime);
1372                 CP(msqbuf, msqbuf32, msg_rtime);
1373                 CP(msqbuf, msqbuf32, msg_ctime);
1374                 error = copyout(&msqbuf32, uap->buf, sizeof(struct msqid_ds32));
1375         }
1376         return (error);
1377 }
1378 #endif
1379
1380 int
1381 freebsd32_msgctl(struct thread *td, struct freebsd32_msgctl_args *uap)
1382 {
1383         struct msqid_ds msqbuf;
1384         struct msqid_ds32 msqbuf32;
1385         int error;
1386
1387         if (uap->cmd == IPC_SET) {
1388                 error = copyin(uap->buf, &msqbuf32, sizeof(msqbuf32));
1389                 if (error)
1390                         return (error);
1391                 freebsd32_ipcperm_in(&msqbuf32.msg_perm, &msqbuf.msg_perm);
1392                 PTRIN_CP(msqbuf32, msqbuf, msg_first);
1393                 PTRIN_CP(msqbuf32, msqbuf, msg_last);
1394                 CP(msqbuf32, msqbuf, msg_cbytes);
1395                 CP(msqbuf32, msqbuf, msg_qnum);
1396                 CP(msqbuf32, msqbuf, msg_qbytes);
1397                 CP(msqbuf32, msqbuf, msg_lspid);
1398                 CP(msqbuf32, msqbuf, msg_lrpid);
1399                 CP(msqbuf32, msqbuf, msg_stime);
1400                 CP(msqbuf32, msqbuf, msg_rtime);
1401                 CP(msqbuf32, msqbuf, msg_ctime);
1402         }
1403         error = kern_msgctl(td, uap->msqid, uap->cmd, &msqbuf);
1404         if (error)
1405                 return (error);
1406         if (uap->cmd == IPC_STAT) {
1407                 freebsd32_ipcperm_out(&msqbuf.msg_perm, &msqbuf32.msg_perm);
1408                 PTROUT_CP(msqbuf, msqbuf32, msg_first);
1409                 PTROUT_CP(msqbuf, msqbuf32, msg_last);
1410                 CP(msqbuf, msqbuf32, msg_cbytes);
1411                 CP(msqbuf, msqbuf32, msg_qnum);
1412                 CP(msqbuf, msqbuf32, msg_qbytes);
1413                 CP(msqbuf, msqbuf32, msg_lspid);
1414                 CP(msqbuf, msqbuf32, msg_lrpid);
1415                 CP(msqbuf, msqbuf32, msg_stime);
1416                 CP(msqbuf, msqbuf32, msg_rtime);
1417                 CP(msqbuf, msqbuf32, msg_ctime);
1418                 error = copyout(&msqbuf32, uap->buf, sizeof(struct msqid_ds32));
1419         }
1420         return (error);
1421 }
1422
1423 int
1424 freebsd32_msgsnd(struct thread *td, struct freebsd32_msgsnd_args *uap)
1425 {
1426         const void *msgp;
1427         long mtype;
1428         int32_t mtype32;
1429         int error;
1430
1431         msgp = PTRIN(uap->msgp);
1432         if ((error = copyin(msgp, &mtype32, sizeof(mtype32))) != 0)
1433                 return (error);
1434         mtype = mtype32;
1435         return (kern_msgsnd(td, uap->msqid,
1436             (const char *)msgp + sizeof(mtype32),
1437             uap->msgsz, uap->msgflg, mtype));
1438 }
1439
1440 int
1441 freebsd32_msgrcv(struct thread *td, struct freebsd32_msgrcv_args *uap)
1442 {
1443         void *msgp;
1444         long mtype;
1445         int32_t mtype32;
1446         int error;
1447
1448         msgp = PTRIN(uap->msgp);
1449         if ((error = kern_msgrcv(td, uap->msqid,
1450             (char *)msgp + sizeof(mtype32), uap->msgsz,
1451             uap->msgtyp, uap->msgflg, &mtype)) != 0)
1452                 return (error);
1453         mtype32 = (int32_t)mtype;
1454         return (copyout(&mtype32, msgp, sizeof(mtype32)));
1455 }
1456 #endif
1457
1458 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
1459     defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
1460
1461 /* XXX casting to (sy_call_t *) is bogus, as usual. */
1462 static sy_call_t *msgcalls[] = {
1463         (sy_call_t *)freebsd7_msgctl, (sy_call_t *)msgget,
1464         (sy_call_t *)msgsnd, (sy_call_t *)msgrcv
1465 };
1466
1467 /*
1468  * Entry point for all MSG calls.
1469  */
1470 int
1471 msgsys(td, uap)
1472         struct thread *td;
1473         /* XXX actually varargs. */
1474         struct msgsys_args /* {
1475                 int     which;
1476                 int     a2;
1477                 int     a3;
1478                 int     a4;
1479                 int     a5;
1480                 int     a6;
1481         } */ *uap;
1482 {
1483         int error;
1484
1485         if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
1486                 return (ENOSYS);
1487         if (uap->which < 0 ||
1488             uap->which >= sizeof(msgcalls)/sizeof(msgcalls[0]))
1489                 return (EINVAL);
1490         error = (*msgcalls[uap->which])(td, &uap->a2);
1491         return (error);
1492 }
1493
1494 #ifndef CP
1495 #define CP(src, dst, fld)       do { (dst).fld = (src).fld; } while (0)
1496 #endif
1497
1498 #ifndef _SYS_SYSPROTO_H_
1499 struct freebsd7_msgctl_args {
1500         int     msqid;
1501         int     cmd;
1502         struct  msqid_ds_old *buf;
1503 };
1504 #endif
1505 int
1506 freebsd7_msgctl(td, uap)
1507         struct thread *td;
1508         struct freebsd7_msgctl_args *uap;
1509 {
1510         struct msqid_ds_old msqold;
1511         struct msqid_ds msqbuf;
1512         int error;
1513
1514         DPRINTF(("call to freebsd7_msgctl(%d, %d, %p)\n", uap->msqid, uap->cmd,
1515             uap->buf));
1516         if (uap->cmd == IPC_SET) {
1517                 error = copyin(uap->buf, &msqold, sizeof(msqold));
1518                 if (error)
1519                         return (error);
1520                 ipcperm_old2new(&msqold.msg_perm, &msqbuf.msg_perm);
1521                 CP(msqold, msqbuf, msg_first);
1522                 CP(msqold, msqbuf, msg_last);
1523                 CP(msqold, msqbuf, msg_cbytes);
1524                 CP(msqold, msqbuf, msg_qnum);
1525                 CP(msqold, msqbuf, msg_qbytes);
1526                 CP(msqold, msqbuf, msg_lspid);
1527                 CP(msqold, msqbuf, msg_lrpid);
1528                 CP(msqold, msqbuf, msg_stime);
1529                 CP(msqold, msqbuf, msg_rtime);
1530                 CP(msqold, msqbuf, msg_ctime);
1531         }
1532         error = kern_msgctl(td, uap->msqid, uap->cmd, &msqbuf);
1533         if (error)
1534                 return (error);
1535         if (uap->cmd == IPC_STAT) {
1536                 bzero(&msqold, sizeof(msqold));
1537                 ipcperm_new2old(&msqbuf.msg_perm, &msqold.msg_perm);
1538                 CP(msqbuf, msqold, msg_first);
1539                 CP(msqbuf, msqold, msg_last);
1540                 CP(msqbuf, msqold, msg_cbytes);
1541                 CP(msqbuf, msqold, msg_qnum);
1542                 CP(msqbuf, msqold, msg_qbytes);
1543                 CP(msqbuf, msqold, msg_lspid);
1544                 CP(msqbuf, msqold, msg_lrpid);
1545                 CP(msqbuf, msqold, msg_stime);
1546                 CP(msqbuf, msqold, msg_rtime);
1547                 CP(msqbuf, msqold, msg_ctime);
1548                 error = copyout(&msqold, uap->buf, sizeof(struct msqid_ds_old));
1549         }
1550         return (error);
1551 }
1552
1553 #undef CP
1554
1555 #endif  /* COMPAT_FREEBSD4 || COMPAT_FREEBSD5 || COMPAT_FREEBSD6 ||
1556            COMPAT_FREEBSD7 */