The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/sysv_msg.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 68d2f077c30024a2439ef59b0b7d0a8f


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.