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