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/10/sys/kern/sysv_msg.c 329741 2018-02-21 18:32:57Z brooks $"); 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> 65298835Sjamie#include <sys/mount.h> 662729Sdfr#include <sys/msg.h> 67220398Strasz#include <sys/racct.h> 68298835Sjamie#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 *); 85298835Sjamiestatic void msq_remove(struct msqid_kernel *); 86298835Sjamiestatic struct prison *msg_find_prison(struct ucred *); 87298835Sjamiestatic int msq_prison_cansee(struct prison *, struct msqid_kernel *); 88298835Sjamiestatic int msg_prison_check(void *, void *); 89298835Sjamiestatic int msg_prison_set(void *, void *); 90298835Sjamiestatic int msg_prison_get(void *, void *); 91298835Sjamiestatic int msg_prison_remove(void *, void *); 92298835Sjamiestatic 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. */ 168298835Sjamiestatic 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{ 208298835Sjamie struct prison *pr; 209298835Sjamie void *rsv; 210205323Skib int i, error; 211298835Sjamie osd_method_t methods[PR_MAXMETHOD] = { 212298835Sjamie [PR_METHOD_CHECK] = msg_prison_check, 213298835Sjamie [PR_METHOD_SET] = msg_prison_set, 214298835Sjamie [PR_METHOD_GET] = msg_prison_get, 215298835Sjamie [PR_METHOD_REMOVE] = msg_prison_remove, 216298835Sjamie }; 2172729Sdfr 21883765Smr TUNABLE_INT_FETCH("kern.ipc.msgseg", &msginfo.msgseg); 21983765Smr TUNABLE_INT_FETCH("kern.ipc.msgssz", &msginfo.msgssz); 22083765Smr msginfo.msgmax = msginfo.msgseg * msginfo.msgssz; 22183765Smr TUNABLE_INT_FETCH("kern.ipc.msgmni", &msginfo.msgmni); 222139436Srwatson TUNABLE_INT_FETCH("kern.ipc.msgmnb", &msginfo.msgmnb); 223139436Srwatson TUNABLE_INT_FETCH("kern.ipc.msgtql", &msginfo.msgtql); 22483765Smr 225111119Simp msgpool = malloc(msginfo.msgmax, M_MSG, M_WAITOK); 226111119Simp msgmaps = malloc(sizeof(struct msgmap) * msginfo.msgseg, M_MSG, M_WAITOK); 227111119Simp msghdrs = malloc(sizeof(struct msg) * msginfo.msgtql, M_MSG, M_WAITOK); 228137613Srwatson msqids = malloc(sizeof(struct msqid_kernel) * msginfo.msgmni, M_MSG, 229137613Srwatson M_WAITOK); 23059839Speter 2312729Sdfr /* 2322729Sdfr * msginfo.msgssz should be a power of two for efficiency reasons. 2332729Sdfr * It is also pretty silly if msginfo.msgssz is less than 8 2342729Sdfr * or greater than about 256 so ... 2352729Sdfr */ 2362729Sdfr 2372729Sdfr i = 8; 2382729Sdfr while (i < 1024 && i != msginfo.msgssz) 2392729Sdfr i <<= 1; 2402729Sdfr if (i != msginfo.msgssz) { 241100523Salfred DPRINTF(("msginfo.msgssz=%d (0x%x)\n", msginfo.msgssz, 242100523Salfred msginfo.msgssz)); 2432729Sdfr panic("msginfo.msgssz not a small power of 2"); 2442729Sdfr } 2452729Sdfr 2462729Sdfr if (msginfo.msgseg > 32767) { 247100523Salfred DPRINTF(("msginfo.msgseg=%d\n", msginfo.msgseg)); 2482729Sdfr panic("msginfo.msgseg > 32767"); 2492729Sdfr } 2502729Sdfr 2512729Sdfr for (i = 0; i < msginfo.msgseg; i++) { 2522729Sdfr if (i > 0) 2532729Sdfr msgmaps[i-1].next = i; 2542729Sdfr msgmaps[i].next = -1; /* implies entry is available */ 2552729Sdfr } 2562729Sdfr free_msgmaps = 0; 2572729Sdfr nfree_msgmaps = msginfo.msgseg; 2582729Sdfr 2592729Sdfr for (i = 0; i < msginfo.msgtql; i++) { 2602729Sdfr msghdrs[i].msg_type = 0; 2612729Sdfr if (i > 0) 2622729Sdfr msghdrs[i-1].msg_next = &msghdrs[i]; 2632729Sdfr msghdrs[i].msg_next = NULL; 264140614Srwatson#ifdef MAC 265172930Srwatson mac_sysvmsg_init(&msghdrs[i]); 266140614Srwatson#endif 2672729Sdfr } 2682729Sdfr free_msghdrs = &msghdrs[0]; 2692729Sdfr 2702729Sdfr for (i = 0; i < msginfo.msgmni; i++) { 271137613Srwatson msqids[i].u.msg_qbytes = 0; /* implies entry is available */ 272137613Srwatson msqids[i].u.msg_perm.seq = 0; /* reset to a known value */ 273137613Srwatson msqids[i].u.msg_perm.mode = 0; 274140614Srwatson#ifdef MAC 275172930Srwatson mac_sysvmsq_init(&msqids[i]); 276140614Srwatson#endif 2772729Sdfr } 278101772Salfred mtx_init(&msq_mtx, "msq", NULL, MTX_DEF); 279205323Skib 280298835Sjamie /* Set current prisons according to their allow.sysvipc. */ 281298835Sjamie msg_prison_slot = osd_jail_register(NULL, methods); 282298835Sjamie rsv = osd_reserve(msg_prison_slot); 283298835Sjamie prison_lock(&prison0); 284298835Sjamie (void)osd_jail_set_reserved(&prison0, msg_prison_slot, rsv, &prison0); 285298835Sjamie prison_unlock(&prison0); 286298835Sjamie rsv = NULL; 287298835Sjamie sx_slock(&allprison_lock); 288298835Sjamie TAILQ_FOREACH(pr, &allprison, pr_list) { 289298835Sjamie if (rsv == NULL) 290298835Sjamie rsv = osd_reserve(msg_prison_slot); 291298835Sjamie prison_lock(pr); 292298835Sjamie if ((pr->pr_allow & PR_ALLOW_SYSVIPC) && pr->pr_ref > 0) { 293298835Sjamie (void)osd_jail_set_reserved(pr, msg_prison_slot, rsv, 294298835Sjamie &prison0); 295298835Sjamie rsv = NULL; 296298835Sjamie } 297298835Sjamie prison_unlock(pr); 298298835Sjamie } 299298835Sjamie if (rsv != NULL) 300298835Sjamie osd_free_reserved(rsv); 301298835Sjamie sx_sunlock(&allprison_lock); 302298835Sjamie 303205323Skib error = syscall_helper_register(msg_syscalls); 304205323Skib if (error != 0) 305205323Skib return (error); 306205323Skib#ifdef COMPAT_FREEBSD32 307205323Skib error = syscall32_helper_register(msg32_syscalls); 308205323Skib if (error != 0) 309205323Skib return (error); 310205323Skib#endif 311205323Skib return (0); 3122729Sdfr} 3132729Sdfr 31469449Salfredstatic int 31569449Salfredmsgunload() 31669449Salfred{ 317137613Srwatson struct msqid_kernel *msqkptr; 31869449Salfred int msqid; 319140614Srwatson#ifdef MAC 320140614Srwatson int i; 321140614Srwatson#endif 32269449Salfred 323205323Skib syscall_helper_unregister(msg_syscalls); 324205323Skib#ifdef COMPAT_FREEBSD32 325205323Skib syscall32_helper_unregister(msg32_syscalls); 326205323Skib#endif 327205323Skib 32869449Salfred for (msqid = 0; msqid < msginfo.msgmni; msqid++) { 329137613Srwatson msqkptr = &msqids[msqid]; 330137613Srwatson if (msqkptr->u.msg_qbytes != 0 || 331137613Srwatson (msqkptr->u.msg_perm.mode & MSG_LOCKED) != 0) 33269449Salfred break; 33369449Salfred } 33469449Salfred if (msqid != msginfo.msgmni) 33569449Salfred return (EBUSY); 33669449Salfred 337298835Sjamie if (msg_prison_slot != 0) 338298835Sjamie osd_jail_deregister(msg_prison_slot); 339140614Srwatson#ifdef MAC 340140614Srwatson for (i = 0; i < msginfo.msgtql; i++) 341172930Srwatson mac_sysvmsg_destroy(&msghdrs[i]); 342140614Srwatson for (msqid = 0; msqid < msginfo.msgmni; msqid++) 343172930Srwatson mac_sysvmsq_destroy(&msqids[msqid]); 344140614Srwatson#endif 34569449Salfred free(msgpool, M_MSG); 34669449Salfred free(msgmaps, M_MSG); 34769449Salfred free(msghdrs, M_MSG); 34869449Salfred free(msqids, M_MSG); 349101772Salfred mtx_destroy(&msq_mtx); 35069449Salfred return (0); 35169449Salfred} 35269449Salfred 35369449Salfred 35469449Salfredstatic int 35569449Salfredsysvmsg_modload(struct module *module, int cmd, void *arg) 35669449Salfred{ 35769449Salfred int error = 0; 35869449Salfred 35969449Salfred switch (cmd) { 36069449Salfred case MOD_LOAD: 361205323Skib error = msginit(); 362205323Skib if (error != 0) 363205323Skib msgunload(); 36469449Salfred break; 36569449Salfred case MOD_UNLOAD: 36669449Salfred error = msgunload(); 36769449Salfred break; 36869449Salfred case MOD_SHUTDOWN: 36969449Salfred break; 37069449Salfred default: 37169449Salfred error = EINVAL; 37269449Salfred break; 37369449Salfred } 37469449Salfred return (error); 37569449Salfred} 37669449Salfred 37771038Sdesstatic moduledata_t sysvmsg_mod = { 37871038Sdes "sysvmsg", 37969449Salfred &sysvmsg_modload, 38069449Salfred NULL 38169449Salfred}; 38269449Salfred 383194832SjhbDECLARE_MODULE(sysvmsg, sysvmsg_mod, SI_SUB_SYSV_MSG, SI_ORDER_FIRST); 38471038SdesMODULE_VERSION(sysvmsg, 1); 38569449Salfred 3862729Sdfrstatic void 3872729Sdfrmsg_freehdr(msghdr) 3882729Sdfr struct msg *msghdr; 3892729Sdfr{ 3902729Sdfr while (msghdr->msg_ts > 0) { 3912729Sdfr short next; 3922729Sdfr if (msghdr->msg_spot < 0 || msghdr->msg_spot >= msginfo.msgseg) 3932729Sdfr panic("msghdr->msg_spot out of range"); 3942729Sdfr next = msgmaps[msghdr->msg_spot].next; 3952729Sdfr msgmaps[msghdr->msg_spot].next = free_msgmaps; 3962729Sdfr free_msgmaps = msghdr->msg_spot; 3972729Sdfr nfree_msgmaps++; 3982729Sdfr msghdr->msg_spot = next; 3992729Sdfr if (msghdr->msg_ts >= msginfo.msgssz) 4002729Sdfr msghdr->msg_ts -= msginfo.msgssz; 4012729Sdfr else 4022729Sdfr msghdr->msg_ts = 0; 4032729Sdfr } 4042729Sdfr if (msghdr->msg_spot != -1) 4052729Sdfr panic("msghdr->msg_spot != -1"); 4062729Sdfr msghdr->msg_next = free_msghdrs; 4072729Sdfr free_msghdrs = msghdr; 408140614Srwatson#ifdef MAC 409172930Srwatson mac_sysvmsg_cleanup(msghdr); 410140614Srwatson#endif 4112729Sdfr} 4122729Sdfr 413298835Sjamiestatic void 414298835Sjamiemsq_remove(struct msqid_kernel *msqkptr) 415298835Sjamie{ 416298835Sjamie struct msg *msghdr; 417298835Sjamie 418298835Sjamie racct_sub_cred(msqkptr->cred, RACCT_NMSGQ, 1); 419298835Sjamie racct_sub_cred(msqkptr->cred, RACCT_MSGQQUEUED, msqkptr->u.msg_qnum); 420298835Sjamie racct_sub_cred(msqkptr->cred, RACCT_MSGQSIZE, msqkptr->u.msg_cbytes); 421298835Sjamie crfree(msqkptr->cred); 422298835Sjamie msqkptr->cred = NULL; 423298835Sjamie 424298835Sjamie /* Free the message headers */ 425298835Sjamie msghdr = msqkptr->u.msg_first; 426298835Sjamie while (msghdr != NULL) { 427298835Sjamie struct msg *msghdr_tmp; 428298835Sjamie 429298835Sjamie /* Free the segments of each message */ 430298835Sjamie msqkptr->u.msg_cbytes -= msghdr->msg_ts; 431298835Sjamie msqkptr->u.msg_qnum--; 432298835Sjamie msghdr_tmp = msghdr; 433298835Sjamie msghdr = msghdr->msg_next; 434298835Sjamie msg_freehdr(msghdr_tmp); 435298835Sjamie } 436298835Sjamie 437298835Sjamie if (msqkptr->u.msg_cbytes != 0) 438298835Sjamie panic("msg_cbytes is screwed up"); 439298835Sjamie if (msqkptr->u.msg_qnum != 0) 440298835Sjamie panic("msg_qnum is screwed up"); 441298835Sjamie 442298835Sjamie msqkptr->u.msg_qbytes = 0; /* Mark it as free */ 443298835Sjamie 444298835Sjamie#ifdef MAC 445298835Sjamie mac_sysvmsq_cleanup(msqkptr); 446298835Sjamie#endif 447298835Sjamie 448298835Sjamie wakeup(msqkptr); 449298835Sjamie} 450298835Sjamie 451298835Sjamiestatic struct prison * 452298835Sjamiemsg_find_prison(struct ucred *cred) 453298835Sjamie{ 454298835Sjamie struct prison *pr, *rpr; 455298835Sjamie 456298835Sjamie pr = cred->cr_prison; 457298835Sjamie prison_lock(pr); 458298835Sjamie rpr = osd_jail_get(pr, msg_prison_slot); 459298835Sjamie prison_unlock(pr); 460298835Sjamie return rpr; 461298835Sjamie} 462298835Sjamie 463298835Sjamiestatic int 464298835Sjamiemsq_prison_cansee(struct prison *rpr, struct msqid_kernel *msqkptr) 465298835Sjamie{ 466298835Sjamie 467298835Sjamie if (msqkptr->cred == NULL || 468298835Sjamie !(rpr == msqkptr->cred->cr_prison || 469298835Sjamie prison_ischild(rpr, msqkptr->cred->cr_prison))) 470298835Sjamie return (EINVAL); 471298835Sjamie return (0); 472298835Sjamie} 473298835Sjamie 47412866Speter#ifndef _SYS_SYSPROTO_H_ 4752729Sdfrstruct msgctl_args { 4762729Sdfr int msqid; 4772729Sdfr int cmd; 47812866Speter struct msqid_ds *buf; 4792729Sdfr}; 48012866Speter#endif 48112866Speterint 482225617Skmacysys_msgctl(td, uap) 48383366Sjulian struct thread *td; 4842729Sdfr register struct msgctl_args *uap; 4852729Sdfr{ 4862729Sdfr int msqid = uap->msqid; 4872729Sdfr int cmd = uap->cmd; 4882729Sdfr struct msqid_ds msqbuf; 489140839Ssobomax int error; 490140839Ssobomax 491165403Sjkim DPRINTF(("call to msgctl(%d, %d, %p)\n", msqid, cmd, uap->buf)); 492140839Ssobomax if (cmd == IPC_SET && 493140839Ssobomax (error = copyin(uap->buf, &msqbuf, sizeof(msqbuf))) != 0) 494140839Ssobomax return (error); 495141471Sjhb error = kern_msgctl(td, msqid, cmd, &msqbuf); 496140839Ssobomax if (cmd == IPC_STAT && error == 0) 497141471Sjhb error = copyout(&msqbuf, uap->buf, sizeof(struct msqid_ds)); 498140839Ssobomax return (error); 499140839Ssobomax} 500140839Ssobomax 501140839Ssobomaxint 502141471Sjhbkern_msgctl(td, msqid, cmd, msqbuf) 503140839Ssobomax struct thread *td; 504140839Ssobomax int msqid; 505140839Ssobomax int cmd; 506140839Ssobomax struct msqid_ds *msqbuf; 507140839Ssobomax{ 508140839Ssobomax int rval, error, msqix; 509137613Srwatson register struct msqid_kernel *msqkptr; 510298835Sjamie struct prison *rpr; 5112729Sdfr 512298835Sjamie rpr = msg_find_prison(td->td_ucred); 513298835Sjamie if (rpr == NULL) 51491703Sjhb return (ENOSYS); 51591703Sjhb 516140839Ssobomax msqix = IPCID_TO_IX(msqid); 5172729Sdfr 518140839Ssobomax if (msqix < 0 || msqix >= msginfo.msgmni) { 519140839Ssobomax DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqix, 520100523Salfred msginfo.msgmni)); 521101772Salfred return (EINVAL); 5222729Sdfr } 5232729Sdfr 524140839Ssobomax msqkptr = &msqids[msqix]; 5252729Sdfr 526101772Salfred mtx_lock(&msq_mtx); 527137613Srwatson if (msqkptr->u.msg_qbytes == 0) { 528100523Salfred DPRINTF(("no such msqid\n")); 52982607Sdillon error = EINVAL; 53082607Sdillon goto done2; 5312729Sdfr } 532140839Ssobomax if (msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) { 533100523Salfred DPRINTF(("wrong sequence number\n")); 53482607Sdillon error = EINVAL; 53582607Sdillon goto done2; 5362729Sdfr } 537298835Sjamie 538298835Sjamie error = msq_prison_cansee(rpr, msqkptr); 539298835Sjamie if (error != 0) { 540298835Sjamie DPRINTF(("requester can't see prison\n")); 541298835Sjamie goto done2; 542298835Sjamie } 543298835Sjamie 544140614Srwatson#ifdef MAC 545172930Srwatson error = mac_sysvmsq_check_msqctl(td->td_ucred, msqkptr, cmd); 546162468Srwatson if (error != 0) 547140614Srwatson goto done2; 548140614Srwatson#endif 5492729Sdfr 55082607Sdillon error = 0; 5512729Sdfr rval = 0; 5522729Sdfr 5532729Sdfr switch (cmd) { 5542729Sdfr 5552729Sdfr case IPC_RMID: 5562729Sdfr { 557298835Sjamie#ifdef MAC 5582729Sdfr struct msg *msghdr; 559298835Sjamie#endif 560137613Srwatson if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_M))) 56182607Sdillon goto done2; 562137613Srwatson 563140614Srwatson#ifdef MAC 564140614Srwatson /* 565140614Srwatson * Check that the thread has MAC access permissions to 566140614Srwatson * individual msghdrs. Note: We need to do this in a 567140614Srwatson * separate loop because the actual loop alters the 568140614Srwatson * msq/msghdr info as it progresses, and there is no going 569140614Srwatson * back if half the way through we discover that the 570140614Srwatson * thread cannot free a certain msghdr. The msq will get 571140614Srwatson * into an inconsistent state. 572140614Srwatson */ 573140614Srwatson for (msghdr = msqkptr->u.msg_first; msghdr != NULL; 574140614Srwatson msghdr = msghdr->msg_next) { 575172930Srwatson error = mac_sysvmsq_check_msgrmid(td->td_ucred, msghdr); 576162468Srwatson if (error != 0) 577140614Srwatson goto done2; 578140614Srwatson } 579140614Srwatson#endif 580140614Srwatson 581298835Sjamie msq_remove(msqkptr); 5822729Sdfr } 5832729Sdfr 5842729Sdfr break; 5852729Sdfr 5862729Sdfr case IPC_SET: 587137613Srwatson if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_M))) 58882607Sdillon goto done2; 589140839Ssobomax if (msqbuf->msg_qbytes > msqkptr->u.msg_qbytes) { 590170587Srwatson error = priv_check(td, PRIV_IPC_MSGSIZE); 59182607Sdillon if (error) 59282607Sdillon goto done2; 59343426Sphk } 594140839Ssobomax if (msqbuf->msg_qbytes > msginfo.msgmnb) { 595100523Salfred DPRINTF(("can't increase msg_qbytes beyond %d" 596100523Salfred "(truncating)\n", msginfo.msgmnb)); 597140839Ssobomax msqbuf->msg_qbytes = msginfo.msgmnb; /* silently restrict qbytes to system limit */ 5982729Sdfr } 599140839Ssobomax if (msqbuf->msg_qbytes == 0) { 600100523Salfred DPRINTF(("can't reduce msg_qbytes to 0\n")); 60182607Sdillon error = EINVAL; /* non-standard errno! */ 60282607Sdillon goto done2; 6032729Sdfr } 604140839Ssobomax msqkptr->u.msg_perm.uid = msqbuf->msg_perm.uid; /* change the owner */ 605140839Ssobomax msqkptr->u.msg_perm.gid = msqbuf->msg_perm.gid; /* change the owner */ 606137613Srwatson msqkptr->u.msg_perm.mode = (msqkptr->u.msg_perm.mode & ~0777) | 607140839Ssobomax (msqbuf->msg_perm.mode & 0777); 608140839Ssobomax msqkptr->u.msg_qbytes = msqbuf->msg_qbytes; 609137613Srwatson msqkptr->u.msg_ctime = time_second; 6102729Sdfr break; 6112729Sdfr 6122729Sdfr case IPC_STAT: 613137613Srwatson if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_R))) { 614100523Salfred DPRINTF(("requester doesn't have read access\n")); 61582607Sdillon goto done2; 6162729Sdfr } 617141471Sjhb *msqbuf = msqkptr->u; 618298835Sjamie if (td->td_ucred->cr_prison != msqkptr->cred->cr_prison) 619298835Sjamie msqbuf->msg_perm.key = IPC_PRIVATE; 6202729Sdfr break; 6212729Sdfr 6222729Sdfr default: 623100523Salfred DPRINTF(("invalid command %d\n", cmd)); 62482607Sdillon error = EINVAL; 62582607Sdillon goto done2; 6262729Sdfr } 6272729Sdfr 62882607Sdillon if (error == 0) 62983366Sjulian td->td_retval[0] = rval; 63082607Sdillondone2: 631101772Salfred mtx_unlock(&msq_mtx); 632141471Sjhb return (error); 6332729Sdfr} 6342729Sdfr 63512866Speter#ifndef _SYS_SYSPROTO_H_ 6362729Sdfrstruct msgget_args { 6372729Sdfr key_t key; 6382729Sdfr int msgflg; 6392729Sdfr}; 64012866Speter#endif 641225617Skmacy 64212866Speterint 643225617Skmacysys_msgget(td, uap) 64483366Sjulian struct thread *td; 6452729Sdfr register struct msgget_args *uap; 6462729Sdfr{ 64782607Sdillon int msqid, error = 0; 6482729Sdfr int key = uap->key; 6492729Sdfr int msgflg = uap->msgflg; 65091703Sjhb struct ucred *cred = td->td_ucred; 651137613Srwatson register struct msqid_kernel *msqkptr = NULL; 6522729Sdfr 653100523Salfred DPRINTF(("msgget(0x%x, 0%o)\n", key, msgflg)); 6542729Sdfr 655298835Sjamie if (msg_find_prison(cred) == NULL) 65691703Sjhb return (ENOSYS); 65791703Sjhb 658101772Salfred mtx_lock(&msq_mtx); 6592729Sdfr if (key != IPC_PRIVATE) { 6602729Sdfr for (msqid = 0; msqid < msginfo.msgmni; msqid++) { 661137613Srwatson msqkptr = &msqids[msqid]; 662137613Srwatson if (msqkptr->u.msg_qbytes != 0 && 663298835Sjamie msqkptr->cred != NULL && 664298835Sjamie msqkptr->cred->cr_prison == cred->cr_prison && 665137613Srwatson msqkptr->u.msg_perm.key == key) 6662729Sdfr break; 6672729Sdfr } 6682729Sdfr if (msqid < msginfo.msgmni) { 669100523Salfred DPRINTF(("found public key\n")); 6702729Sdfr if ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL)) { 671100523Salfred DPRINTF(("not exclusive\n")); 67282607Sdillon error = EEXIST; 67382607Sdillon goto done2; 6742729Sdfr } 675137613Srwatson if ((error = ipcperm(td, &msqkptr->u.msg_perm, 676137613Srwatson msgflg & 0700))) { 677100523Salfred DPRINTF(("requester doesn't have 0%o access\n", 678100523Salfred msgflg & 0700)); 67982607Sdillon goto done2; 6802729Sdfr } 681140614Srwatson#ifdef MAC 682172930Srwatson error = mac_sysvmsq_check_msqget(cred, msqkptr); 683162468Srwatson if (error != 0) 684140614Srwatson goto done2; 685140614Srwatson#endif 6862729Sdfr goto found; 6872729Sdfr } 6882729Sdfr } 6892729Sdfr 690100523Salfred DPRINTF(("need to allocate the msqid_ds\n")); 6912729Sdfr if (key == IPC_PRIVATE || (msgflg & IPC_CREAT)) { 6922729Sdfr for (msqid = 0; msqid < msginfo.msgmni; msqid++) { 6932729Sdfr /* 6942729Sdfr * Look for an unallocated and unlocked msqid_ds. 6952729Sdfr * msqid_ds's can be locked by msgsnd or msgrcv while 6962729Sdfr * they are copying the message in/out. We can't 6972729Sdfr * re-use the entry until they release it. 6982729Sdfr */ 699137613Srwatson msqkptr = &msqids[msqid]; 700137613Srwatson if (msqkptr->u.msg_qbytes == 0 && 701137613Srwatson (msqkptr->u.msg_perm.mode & MSG_LOCKED) == 0) 7022729Sdfr break; 7032729Sdfr } 7042729Sdfr if (msqid == msginfo.msgmni) { 705100523Salfred DPRINTF(("no more msqid_ds's available\n")); 70682607Sdillon error = ENOSPC; 70782607Sdillon goto done2; 7082729Sdfr } 709223825Strasz#ifdef RACCT 710284665Strasz if (racct_enable) { 711284665Strasz PROC_LOCK(td->td_proc); 712284665Strasz error = racct_add(td->td_proc, RACCT_NMSGQ, 1); 713284665Strasz PROC_UNLOCK(td->td_proc); 714284665Strasz if (error != 0) { 715284665Strasz error = ENOSPC; 716284665Strasz goto done2; 717284665Strasz } 718220398Strasz } 719223825Strasz#endif 720100523Salfred DPRINTF(("msqid %d is available\n", msqid)); 721137613Srwatson msqkptr->u.msg_perm.key = key; 722137613Srwatson msqkptr->u.msg_perm.cuid = cred->cr_uid; 723137613Srwatson msqkptr->u.msg_perm.uid = cred->cr_uid; 724137613Srwatson msqkptr->u.msg_perm.cgid = cred->cr_gid; 725137613Srwatson msqkptr->u.msg_perm.gid = cred->cr_gid; 726137613Srwatson msqkptr->u.msg_perm.mode = (msgflg & 0777); 727220399Strasz msqkptr->cred = crhold(cred); 7282729Sdfr /* Make sure that the returned msqid is unique */ 729137613Srwatson msqkptr->u.msg_perm.seq = (msqkptr->u.msg_perm.seq + 1) & 0x7fff; 730137613Srwatson msqkptr->u.msg_first = NULL; 731137613Srwatson msqkptr->u.msg_last = NULL; 732137613Srwatson msqkptr->u.msg_cbytes = 0; 733137613Srwatson msqkptr->u.msg_qnum = 0; 734137613Srwatson msqkptr->u.msg_qbytes = msginfo.msgmnb; 735137613Srwatson msqkptr->u.msg_lspid = 0; 736137613Srwatson msqkptr->u.msg_lrpid = 0; 737137613Srwatson msqkptr->u.msg_stime = 0; 738137613Srwatson msqkptr->u.msg_rtime = 0; 739137613Srwatson msqkptr->u.msg_ctime = time_second; 740140614Srwatson#ifdef MAC 741172930Srwatson mac_sysvmsq_create(cred, msqkptr); 742140614Srwatson#endif 7432729Sdfr } else { 744100523Salfred DPRINTF(("didn't find it and wasn't asked to create it\n")); 74582607Sdillon error = ENOENT; 74682607Sdillon goto done2; 7472729Sdfr } 7482729Sdfr 7492729Sdfrfound: 7502729Sdfr /* Construct the unique msqid */ 751137613Srwatson td->td_retval[0] = IXSEQ_TO_IPCID(msqid, msqkptr->u.msg_perm); 75282607Sdillondone2: 753101772Salfred mtx_unlock(&msq_mtx); 75482607Sdillon return (error); 7552729Sdfr} 7562729Sdfr 75712866Speter#ifndef _SYS_SYSPROTO_H_ 7582729Sdfrstruct msgsnd_args { 7592729Sdfr int msqid; 760109895Salfred const void *msgp; 7612729Sdfr size_t msgsz; 7622729Sdfr int msgflg; 7632729Sdfr}; 76412866Speter#endif 76512866Speterint 766165403Sjkimkern_msgsnd(td, msqid, msgp, msgsz, msgflg, mtype) 76783366Sjulian struct thread *td; 768165403Sjkim int msqid; 769165403Sjkim const void *msgp; /* XXX msgp is actually mtext. */ 770165403Sjkim size_t msgsz; 771165403Sjkim int msgflg; 772165403Sjkim long mtype; 7732729Sdfr{ 774165403Sjkim int msqix, segs_needed, error = 0; 775137613Srwatson register struct msqid_kernel *msqkptr; 7762729Sdfr register struct msg *msghdr; 777298835Sjamie struct prison *rpr; 7782729Sdfr short next; 779223825Strasz#ifdef RACCT 780220398Strasz size_t saved_msgsz; 781223825Strasz#endif 7822729Sdfr 783298835Sjamie rpr = msg_find_prison(td->td_ucred); 784298835Sjamie if (rpr == NULL) 78591703Sjhb return (ENOSYS); 78691703Sjhb 787101772Salfred mtx_lock(&msq_mtx); 788165403Sjkim msqix = IPCID_TO_IX(msqid); 7892729Sdfr 790165403Sjkim if (msqix < 0 || msqix >= msginfo.msgmni) { 791165403Sjkim DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqix, 792100523Salfred msginfo.msgmni)); 79382607Sdillon error = EINVAL; 79482607Sdillon goto done2; 7952729Sdfr } 7962729Sdfr 797165403Sjkim msqkptr = &msqids[msqix]; 798137613Srwatson if (msqkptr->u.msg_qbytes == 0) { 799100523Salfred DPRINTF(("no such message queue id\n")); 80082607Sdillon error = EINVAL; 80182607Sdillon goto done2; 8022729Sdfr } 803165403Sjkim if (msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) { 804100523Salfred DPRINTF(("wrong sequence number\n")); 80582607Sdillon error = EINVAL; 80682607Sdillon goto done2; 8072729Sdfr } 8082729Sdfr 809298835Sjamie if ((error = msq_prison_cansee(rpr, msqkptr))) { 810298835Sjamie DPRINTF(("requester can't see prison\n")); 811298835Sjamie goto done2; 812298835Sjamie } 813298835Sjamie 814137613Srwatson if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_W))) { 815100523Salfred DPRINTF(("requester doesn't have write access\n")); 81682607Sdillon goto done2; 8172729Sdfr } 8182729Sdfr 819140614Srwatson#ifdef MAC 820172930Srwatson error = mac_sysvmsq_check_msqsnd(td->td_ucred, msqkptr); 821162468Srwatson if (error != 0) 822140614Srwatson goto done2; 823140614Srwatson#endif 824140614Srwatson 825223825Strasz#ifdef RACCT 826284665Strasz if (racct_enable) { 827284665Strasz PROC_LOCK(td->td_proc); 828284665Strasz if (racct_add(td->td_proc, RACCT_MSGQQUEUED, 1)) { 829284665Strasz PROC_UNLOCK(td->td_proc); 830284665Strasz error = EAGAIN; 831284665Strasz goto done2; 832284665Strasz } 833284665Strasz saved_msgsz = msgsz; 834284665Strasz if (racct_add(td->td_proc, RACCT_MSGQSIZE, msgsz)) { 835284665Strasz racct_sub(td->td_proc, RACCT_MSGQQUEUED, 1); 836284665Strasz PROC_UNLOCK(td->td_proc); 837284665Strasz error = EAGAIN; 838284665Strasz goto done2; 839284665Strasz } 840220398Strasz PROC_UNLOCK(td->td_proc); 841220398Strasz } 842223825Strasz#endif 843220398Strasz 8442729Sdfr segs_needed = (msgsz + msginfo.msgssz - 1) / msginfo.msgssz; 845165403Sjkim DPRINTF(("msgsz=%zu, msgssz=%d, segs_needed=%d\n", msgsz, 846165403Sjkim msginfo.msgssz, segs_needed)); 8472729Sdfr for (;;) { 8482729Sdfr int need_more_resources = 0; 8492729Sdfr 8502729Sdfr /* 8512729Sdfr * check msgsz 8522729Sdfr * (inside this loop in case msg_qbytes changes while we sleep) 8532729Sdfr */ 8542729Sdfr 855137613Srwatson if (msgsz > msqkptr->u.msg_qbytes) { 856137613Srwatson DPRINTF(("msgsz > msqkptr->u.msg_qbytes\n")); 85782607Sdillon error = EINVAL; 858220398Strasz goto done3; 8592729Sdfr } 8602729Sdfr 861137613Srwatson if (msqkptr->u.msg_perm.mode & MSG_LOCKED) { 862100523Salfred DPRINTF(("msqid is locked\n")); 8632729Sdfr need_more_resources = 1; 8642729Sdfr } 865137613Srwatson if (msgsz + msqkptr->u.msg_cbytes > msqkptr->u.msg_qbytes) { 866100523Salfred DPRINTF(("msgsz + msg_cbytes > msg_qbytes\n")); 8672729Sdfr need_more_resources = 1; 8682729Sdfr } 8692729Sdfr if (segs_needed > nfree_msgmaps) { 870100523Salfred DPRINTF(("segs_needed > nfree_msgmaps\n")); 8712729Sdfr need_more_resources = 1; 8722729Sdfr } 8732729Sdfr if (free_msghdrs == NULL) { 874100523Salfred DPRINTF(("no more msghdrs\n")); 8752729Sdfr need_more_resources = 1; 8762729Sdfr } 8772729Sdfr 8782729Sdfr if (need_more_resources) { 8792729Sdfr int we_own_it; 8802729Sdfr 8812729Sdfr if ((msgflg & IPC_NOWAIT) != 0) { 882100523Salfred DPRINTF(("need more resources but caller " 883100523Salfred "doesn't want to wait\n")); 88482607Sdillon error = EAGAIN; 885220398Strasz goto done3; 8862729Sdfr } 8872729Sdfr 888137613Srwatson if ((msqkptr->u.msg_perm.mode & MSG_LOCKED) != 0) { 889100523Salfred DPRINTF(("we don't own the msqid_ds\n")); 8902729Sdfr we_own_it = 0; 8912729Sdfr } else { 8922729Sdfr /* Force later arrivals to wait for our 8932729Sdfr request */ 894100523Salfred DPRINTF(("we own the msqid_ds\n")); 895137613Srwatson msqkptr->u.msg_perm.mode |= MSG_LOCKED; 8962729Sdfr we_own_it = 1; 8972729Sdfr } 898164368Sjkim DPRINTF(("msgsnd: goodnight\n")); 899137613Srwatson error = msleep(msqkptr, &msq_mtx, (PZERO - 4) | PCATCH, 900164368Sjkim "msgsnd", hz); 901164368Sjkim DPRINTF(("msgsnd: good morning, error=%d\n", error)); 9022729Sdfr if (we_own_it) 903137613Srwatson msqkptr->u.msg_perm.mode &= ~MSG_LOCKED; 904164368Sjkim if (error == EWOULDBLOCK) { 905164368Sjkim DPRINTF(("msgsnd: timed out\n")); 906164368Sjkim continue; 907164368Sjkim } 90882607Sdillon if (error != 0) { 909100523Salfred DPRINTF(("msgsnd: interrupted system call\n")); 91082607Sdillon error = EINTR; 911220398Strasz goto done3; 9122729Sdfr } 9132729Sdfr 9142729Sdfr /* 9152729Sdfr * Make sure that the msq queue still exists 9162729Sdfr */ 9172729Sdfr 918137613Srwatson if (msqkptr->u.msg_qbytes == 0) { 919100523Salfred DPRINTF(("msqid deleted\n")); 92082607Sdillon error = EIDRM; 921220398Strasz goto done3; 9222729Sdfr } 9232729Sdfr 9242729Sdfr } else { 925100523Salfred DPRINTF(("got all the resources that we need\n")); 9262729Sdfr break; 9272729Sdfr } 9282729Sdfr } 9292729Sdfr 9302729Sdfr /* 9312729Sdfr * We have the resources that we need. 9322729Sdfr * Make sure! 9332729Sdfr */ 9342729Sdfr 935137613Srwatson if (msqkptr->u.msg_perm.mode & MSG_LOCKED) 9362729Sdfr panic("msg_perm.mode & MSG_LOCKED"); 9372729Sdfr if (segs_needed > nfree_msgmaps) 9382729Sdfr panic("segs_needed > nfree_msgmaps"); 939137613Srwatson if (msgsz + msqkptr->u.msg_cbytes > msqkptr->u.msg_qbytes) 9402729Sdfr panic("msgsz + msg_cbytes > msg_qbytes"); 9412729Sdfr if (free_msghdrs == NULL) 9422729Sdfr panic("no more msghdrs"); 9432729Sdfr 9442729Sdfr /* 9452729Sdfr * Re-lock the msqid_ds in case we page-fault when copying in the 9462729Sdfr * message 9472729Sdfr */ 9482729Sdfr 949137613Srwatson if ((msqkptr->u.msg_perm.mode & MSG_LOCKED) != 0) 9502729Sdfr panic("msqid_ds is already locked"); 951137613Srwatson msqkptr->u.msg_perm.mode |= MSG_LOCKED; 9522729Sdfr 9532729Sdfr /* 9542729Sdfr * Allocate a message header 9552729Sdfr */ 9562729Sdfr 9572729Sdfr msghdr = free_msghdrs; 9582729Sdfr free_msghdrs = msghdr->msg_next; 9592729Sdfr msghdr->msg_spot = -1; 9602729Sdfr msghdr->msg_ts = msgsz; 961165403Sjkim msghdr->msg_type = mtype; 962140614Srwatson#ifdef MAC 963140614Srwatson /* 964172930Srwatson * XXXMAC: Should the mac_sysvmsq_check_msgmsq check follow here 965140614Srwatson * immediately? Or, should it be checked just before the msg is 966140614Srwatson * enqueued in the msgq (as it is done now)? 967140614Srwatson */ 968172930Srwatson mac_sysvmsg_create(td->td_ucred, msqkptr, msghdr); 969140614Srwatson#endif 9702729Sdfr 9712729Sdfr /* 9722729Sdfr * Allocate space for the message 9732729Sdfr */ 9742729Sdfr 9752729Sdfr while (segs_needed > 0) { 9762729Sdfr if (nfree_msgmaps <= 0) 9772729Sdfr panic("not enough msgmaps"); 9782729Sdfr if (free_msgmaps == -1) 9792729Sdfr panic("nil free_msgmaps"); 9802729Sdfr next = free_msgmaps; 9812729Sdfr if (next <= -1) 9822729Sdfr panic("next too low #1"); 9832729Sdfr if (next >= msginfo.msgseg) 9842729Sdfr panic("next out of range #1"); 985100523Salfred DPRINTF(("allocating segment %d to message\n", next)); 9862729Sdfr free_msgmaps = msgmaps[next].next; 9872729Sdfr nfree_msgmaps--; 9882729Sdfr msgmaps[next].next = msghdr->msg_spot; 9892729Sdfr msghdr->msg_spot = next; 9902729Sdfr segs_needed--; 9912729Sdfr } 9922729Sdfr 9932729Sdfr /* 9942729Sdfr * Validate the message type 9952729Sdfr */ 9962729Sdfr 9972729Sdfr if (msghdr->msg_type < 1) { 9982729Sdfr msg_freehdr(msghdr); 999137613Srwatson msqkptr->u.msg_perm.mode &= ~MSG_LOCKED; 1000137613Srwatson wakeup(msqkptr); 1001165403Sjkim DPRINTF(("mtype (%ld) < 1\n", msghdr->msg_type)); 100282607Sdillon error = EINVAL; 1003220398Strasz goto done3; 10042729Sdfr } 10052729Sdfr 10062729Sdfr /* 10072729Sdfr * Copy in the message body 10082729Sdfr */ 10092729Sdfr 10102729Sdfr next = msghdr->msg_spot; 10112729Sdfr while (msgsz > 0) { 10122729Sdfr size_t tlen; 10132729Sdfr if (msgsz > msginfo.msgssz) 10142729Sdfr tlen = msginfo.msgssz; 10152729Sdfr else 10162729Sdfr tlen = msgsz; 10172729Sdfr if (next <= -1) 10182729Sdfr panic("next too low #2"); 10192729Sdfr if (next >= msginfo.msgseg) 10202729Sdfr panic("next out of range #2"); 1021101772Salfred mtx_unlock(&msq_mtx); 1022165403Sjkim if ((error = copyin(msgp, &msgpool[next * msginfo.msgssz], 10232729Sdfr tlen)) != 0) { 1024101772Salfred mtx_lock(&msq_mtx); 1025100523Salfred DPRINTF(("error %d copying in message segment\n", 1026100523Salfred error)); 10272729Sdfr msg_freehdr(msghdr); 1028137613Srwatson msqkptr->u.msg_perm.mode &= ~MSG_LOCKED; 1029137613Srwatson wakeup(msqkptr); 1030220398Strasz goto done3; 10312729Sdfr } 1032101772Salfred mtx_lock(&msq_mtx); 10332729Sdfr msgsz -= tlen; 1034165403Sjkim msgp = (const char *)msgp + tlen; 10352729Sdfr next = msgmaps[next].next; 10362729Sdfr } 10372729Sdfr if (next != -1) 10382729Sdfr panic("didn't use all the msg segments"); 10392729Sdfr 10402729Sdfr /* 10412729Sdfr * We've got the message. Unlock the msqid_ds. 10422729Sdfr */ 10432729Sdfr 1044137613Srwatson msqkptr->u.msg_perm.mode &= ~MSG_LOCKED; 10452729Sdfr 10462729Sdfr /* 10472729Sdfr * Make sure that the msqid_ds is still allocated. 10482729Sdfr */ 10492729Sdfr 1050137613Srwatson if (msqkptr->u.msg_qbytes == 0) { 10512729Sdfr msg_freehdr(msghdr); 1052137613Srwatson wakeup(msqkptr); 105382607Sdillon error = EIDRM; 1054220398Strasz goto done3; 10552729Sdfr } 10562729Sdfr 1057140614Srwatson#ifdef MAC 10582729Sdfr /* 1059140614Srwatson * Note: Since the task/thread allocates the msghdr and usually 1060140614Srwatson * primes it with its own MAC label, for a majority of policies, it 1061140614Srwatson * won't be necessary to check whether the msghdr has access 1062172930Srwatson * permissions to the msgq. The mac_sysvmsq_check_msqsnd check would 1063140614Srwatson * suffice in that case. However, this hook may be required where 1064140614Srwatson * individual policies derive a non-identical label for the msghdr 1065140614Srwatson * from the current thread label and may want to check the msghdr 1066140614Srwatson * enqueue permissions, along with read/write permissions to the 1067140614Srwatson * msgq. 1068140614Srwatson */ 1069172930Srwatson error = mac_sysvmsq_check_msgmsq(td->td_ucred, msghdr, msqkptr); 1070140614Srwatson if (error != 0) { 1071140614Srwatson msg_freehdr(msghdr); 1072140614Srwatson wakeup(msqkptr); 1073220398Strasz goto done3; 1074140614Srwatson } 1075140614Srwatson#endif 1076140614Srwatson 1077140614Srwatson /* 10782729Sdfr * Put the message into the queue 10792729Sdfr */ 1080137613Srwatson if (msqkptr->u.msg_first == NULL) { 1081137613Srwatson msqkptr->u.msg_first = msghdr; 1082137613Srwatson msqkptr->u.msg_last = msghdr; 10832729Sdfr } else { 1084137613Srwatson msqkptr->u.msg_last->msg_next = msghdr; 1085137613Srwatson msqkptr->u.msg_last = msghdr; 10862729Sdfr } 1087137613Srwatson msqkptr->u.msg_last->msg_next = NULL; 10882729Sdfr 1089137613Srwatson msqkptr->u.msg_cbytes += msghdr->msg_ts; 1090137613Srwatson msqkptr->u.msg_qnum++; 1091137613Srwatson msqkptr->u.msg_lspid = td->td_proc->p_pid; 1092137613Srwatson msqkptr->u.msg_stime = time_second; 10932729Sdfr 1094137613Srwatson wakeup(msqkptr); 109583366Sjulian td->td_retval[0] = 0; 1096220398Straszdone3: 1097223825Strasz#ifdef RACCT 1098284665Strasz if (racct_enable && error != 0) { 1099220398Strasz PROC_LOCK(td->td_proc); 1100220398Strasz racct_sub(td->td_proc, RACCT_MSGQQUEUED, 1); 1101220398Strasz racct_sub(td->td_proc, RACCT_MSGQSIZE, saved_msgsz); 1102220398Strasz PROC_UNLOCK(td->td_proc); 1103220398Strasz } 1104223825Strasz#endif 110582607Sdillondone2: 1106101772Salfred mtx_unlock(&msq_mtx); 110782607Sdillon return (error); 11082729Sdfr} 11092729Sdfr 1110165403Sjkimint 1111225617Skmacysys_msgsnd(td, uap) 1112165403Sjkim struct thread *td; 1113165403Sjkim register struct msgsnd_args *uap; 1114165403Sjkim{ 1115165403Sjkim int error; 1116165403Sjkim long mtype; 1117165403Sjkim 1118165403Sjkim DPRINTF(("call to msgsnd(%d, %p, %zu, %d)\n", uap->msqid, uap->msgp, 1119165403Sjkim uap->msgsz, uap->msgflg)); 1120165403Sjkim 1121165403Sjkim if ((error = copyin(uap->msgp, &mtype, sizeof(mtype))) != 0) { 1122165403Sjkim DPRINTF(("error %d copying the message type\n", error)); 1123165403Sjkim return (error); 1124165403Sjkim } 1125165403Sjkim return (kern_msgsnd(td, uap->msqid, 1126165403Sjkim (const char *)uap->msgp + sizeof(mtype), 1127165403Sjkim uap->msgsz, uap->msgflg, mtype)); 1128165403Sjkim} 1129165403Sjkim 113012866Speter#ifndef _SYS_SYSPROTO_H_ 11312729Sdfrstruct msgrcv_args { 11322729Sdfr int msqid; 11332729Sdfr void *msgp; 11342729Sdfr size_t msgsz; 11352729Sdfr long msgtyp; 11362729Sdfr int msgflg; 11372729Sdfr}; 113812866Speter#endif 113912866Speterint 1140165403Sjkimkern_msgrcv(td, msqid, msgp, msgsz, msgtyp, msgflg, mtype) 114183366Sjulian struct thread *td; 1142165403Sjkim int msqid; 1143165403Sjkim void *msgp; /* XXX msgp is actually mtext. */ 1144165403Sjkim size_t msgsz; 1145165403Sjkim long msgtyp; 1146165403Sjkim int msgflg; 1147165403Sjkim long *mtype; 11482729Sdfr{ 11492729Sdfr size_t len; 1150137613Srwatson register struct msqid_kernel *msqkptr; 11512729Sdfr register struct msg *msghdr; 1152298835Sjamie struct prison *rpr; 1153165403Sjkim int msqix, error = 0; 11542729Sdfr short next; 11552729Sdfr 1156298835Sjamie rpr = msg_find_prison(td->td_ucred); 1157298835Sjamie if (rpr == NULL) 115891703Sjhb return (ENOSYS); 115991703Sjhb 1160165403Sjkim msqix = IPCID_TO_IX(msqid); 11612729Sdfr 1162165403Sjkim if (msqix < 0 || msqix >= msginfo.msgmni) { 1163165403Sjkim DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqix, 1164100523Salfred msginfo.msgmni)); 1165101772Salfred return (EINVAL); 11662729Sdfr } 11672729Sdfr 1168165403Sjkim msqkptr = &msqids[msqix]; 1169101772Salfred mtx_lock(&msq_mtx); 1170137613Srwatson if (msqkptr->u.msg_qbytes == 0) { 1171100523Salfred DPRINTF(("no such message queue id\n")); 117282607Sdillon error = EINVAL; 117382607Sdillon goto done2; 11742729Sdfr } 1175165403Sjkim if (msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) { 1176100523Salfred DPRINTF(("wrong sequence number\n")); 117782607Sdillon error = EINVAL; 117882607Sdillon goto done2; 11792729Sdfr } 11802729Sdfr 1181298835Sjamie if ((error = msq_prison_cansee(rpr, msqkptr))) { 1182298835Sjamie DPRINTF(("requester can't see prison\n")); 1183298835Sjamie goto done2; 1184298835Sjamie } 1185298835Sjamie 1186137613Srwatson if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_R))) { 1187100523Salfred DPRINTF(("requester doesn't have read access\n")); 118882607Sdillon goto done2; 11892729Sdfr } 11902729Sdfr 1191140614Srwatson#ifdef MAC 1192172930Srwatson error = mac_sysvmsq_check_msqrcv(td->td_ucred, msqkptr); 1193162468Srwatson if (error != 0) 1194140614Srwatson goto done2; 1195140614Srwatson#endif 1196140614Srwatson 11972729Sdfr msghdr = NULL; 11982729Sdfr while (msghdr == NULL) { 11992729Sdfr if (msgtyp == 0) { 1200137613Srwatson msghdr = msqkptr->u.msg_first; 12012729Sdfr if (msghdr != NULL) { 12022729Sdfr if (msgsz < msghdr->msg_ts && 12032729Sdfr (msgflg & MSG_NOERROR) == 0) { 1204100523Salfred DPRINTF(("first message on the queue " 1205165403Sjkim "is too big (want %zu, got %d)\n", 1206100523Salfred msgsz, msghdr->msg_ts)); 120782607Sdillon error = E2BIG; 120882607Sdillon goto done2; 12092729Sdfr } 1210140614Srwatson#ifdef MAC 1211172930Srwatson error = mac_sysvmsq_check_msgrcv(td->td_ucred, 1212140614Srwatson msghdr); 1213162468Srwatson if (error != 0) 1214140614Srwatson goto done2; 1215140614Srwatson#endif 1216137613Srwatson if (msqkptr->u.msg_first == msqkptr->u.msg_last) { 1217137613Srwatson msqkptr->u.msg_first = NULL; 1218137613Srwatson msqkptr->u.msg_last = NULL; 12192729Sdfr } else { 1220137613Srwatson msqkptr->u.msg_first = msghdr->msg_next; 1221137613Srwatson if (msqkptr->u.msg_first == NULL) 12222729Sdfr panic("msg_first/last screwed up #1"); 12232729Sdfr } 12242729Sdfr } 12252729Sdfr } else { 12262729Sdfr struct msg *previous; 12272729Sdfr struct msg **prev; 12282729Sdfr 12292729Sdfr previous = NULL; 1230137613Srwatson prev = &(msqkptr->u.msg_first); 12312729Sdfr while ((msghdr = *prev) != NULL) { 12322729Sdfr /* 12332729Sdfr * Is this message's type an exact match or is 12342729Sdfr * this message's type less than or equal to 12352729Sdfr * the absolute value of a negative msgtyp? 12362729Sdfr * Note that the second half of this test can 12372729Sdfr * NEVER be true if msgtyp is positive since 12382729Sdfr * msg_type is always positive! 12392729Sdfr */ 12402729Sdfr 12412729Sdfr if (msgtyp == msghdr->msg_type || 12422729Sdfr msghdr->msg_type <= -msgtyp) { 1243165403Sjkim DPRINTF(("found message type %ld, " 1244165403Sjkim "requested %ld\n", 1245100523Salfred msghdr->msg_type, msgtyp)); 12462729Sdfr if (msgsz < msghdr->msg_ts && 12472729Sdfr (msgflg & MSG_NOERROR) == 0) { 1248100523Salfred DPRINTF(("requested message " 1249100523Salfred "on the queue is too big " 1250165403Sjkim "(want %zu, got %hu)\n", 1251100523Salfred msgsz, msghdr->msg_ts)); 125282607Sdillon error = E2BIG; 125382607Sdillon goto done2; 12542729Sdfr } 1255140614Srwatson#ifdef MAC 1256172930Srwatson error = mac_sysvmsq_check_msgrcv( 1257140614Srwatson td->td_ucred, msghdr); 1258162468Srwatson if (error != 0) 1259140614Srwatson goto done2; 1260140614Srwatson#endif 12612729Sdfr *prev = msghdr->msg_next; 1262137613Srwatson if (msghdr == msqkptr->u.msg_last) { 12632729Sdfr if (previous == NULL) { 12642729Sdfr if (prev != 1265137613Srwatson &msqkptr->u.msg_first) 12662729Sdfr panic("msg_first/last screwed up #2"); 1267137613Srwatson msqkptr->u.msg_first = 12682729Sdfr NULL; 1269137613Srwatson msqkptr->u.msg_last = 12702729Sdfr NULL; 12712729Sdfr } else { 12722729Sdfr if (prev == 1273137613Srwatson &msqkptr->u.msg_first) 12742729Sdfr panic("msg_first/last screwed up #3"); 1275137613Srwatson msqkptr->u.msg_last = 12762729Sdfr previous; 12772729Sdfr } 12782729Sdfr } 12792729Sdfr break; 12802729Sdfr } 12812729Sdfr previous = msghdr; 12822729Sdfr prev = &(msghdr->msg_next); 12832729Sdfr } 12842729Sdfr } 12852729Sdfr 12862729Sdfr /* 12872729Sdfr * We've either extracted the msghdr for the appropriate 12882729Sdfr * message or there isn't one. 12892729Sdfr * If there is one then bail out of this loop. 12902729Sdfr */ 12912729Sdfr 12922729Sdfr if (msghdr != NULL) 12932729Sdfr break; 12942729Sdfr 12952729Sdfr /* 12962729Sdfr * Hmph! No message found. Does the user want to wait? 12972729Sdfr */ 12982729Sdfr 12992729Sdfr if ((msgflg & IPC_NOWAIT) != 0) { 1300165403Sjkim DPRINTF(("no appropriate message found (msgtyp=%ld)\n", 1301100523Salfred msgtyp)); 13022729Sdfr /* The SVID says to return ENOMSG. */ 130382607Sdillon error = ENOMSG; 130482607Sdillon goto done2; 13052729Sdfr } 13062729Sdfr 13072729Sdfr /* 13082729Sdfr * Wait for something to happen 13092729Sdfr */ 13102729Sdfr 1311100523Salfred DPRINTF(("msgrcv: goodnight\n")); 1312137613Srwatson error = msleep(msqkptr, &msq_mtx, (PZERO - 4) | PCATCH, 1313164368Sjkim "msgrcv", 0); 1314100523Salfred DPRINTF(("msgrcv: good morning (error=%d)\n", error)); 13152729Sdfr 131682607Sdillon if (error != 0) { 1317164368Sjkim DPRINTF(("msgrcv: interrupted system call\n")); 131882607Sdillon error = EINTR; 131982607Sdillon goto done2; 13202729Sdfr } 13212729Sdfr 13222729Sdfr /* 13232729Sdfr * Make sure that the msq queue still exists 13242729Sdfr */ 13252729Sdfr 1326137613Srwatson if (msqkptr->u.msg_qbytes == 0 || 1327165403Sjkim msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) { 1328100523Salfred DPRINTF(("msqid deleted\n")); 132982607Sdillon error = EIDRM; 133082607Sdillon goto done2; 13312729Sdfr } 13322729Sdfr } 13332729Sdfr 13342729Sdfr /* 13352729Sdfr * Return the message to the user. 13362729Sdfr * 13372729Sdfr * First, do the bookkeeping (before we risk being interrupted). 13382729Sdfr */ 13392729Sdfr 1340137613Srwatson msqkptr->u.msg_cbytes -= msghdr->msg_ts; 1341137613Srwatson msqkptr->u.msg_qnum--; 1342137613Srwatson msqkptr->u.msg_lrpid = td->td_proc->p_pid; 1343137613Srwatson msqkptr->u.msg_rtime = time_second; 13442729Sdfr 1345220398Strasz racct_sub_cred(msqkptr->cred, RACCT_MSGQQUEUED, 1); 1346220398Strasz racct_sub_cred(msqkptr->cred, RACCT_MSGQSIZE, msghdr->msg_ts); 1347220398Strasz 13482729Sdfr /* 13492729Sdfr * Make msgsz the actual amount that we'll be returning. 13502729Sdfr * Note that this effectively truncates the message if it is too long 13512729Sdfr * (since msgsz is never increased). 13522729Sdfr */ 13532729Sdfr 1354165403Sjkim DPRINTF(("found a message, msgsz=%zu, msg_ts=%hu\n", msgsz, 1355100523Salfred msghdr->msg_ts)); 13562729Sdfr if (msgsz > msghdr->msg_ts) 13572729Sdfr msgsz = msghdr->msg_ts; 1358165403Sjkim *mtype = msghdr->msg_type; 13592729Sdfr 13602729Sdfr /* 13612729Sdfr * Return the segments to the user 13622729Sdfr */ 13632729Sdfr 13642729Sdfr next = msghdr->msg_spot; 13652729Sdfr for (len = 0; len < msgsz; len += msginfo.msgssz) { 13662729Sdfr size_t tlen; 13672729Sdfr 136845921Ssada if (msgsz - len > msginfo.msgssz) 13692729Sdfr tlen = msginfo.msgssz; 13702729Sdfr else 137145921Ssada tlen = msgsz - len; 13722729Sdfr if (next <= -1) 13732729Sdfr panic("next too low #3"); 13742729Sdfr if (next >= msginfo.msgseg) 13752729Sdfr panic("next out of range #3"); 1376101772Salfred mtx_unlock(&msq_mtx); 1377165403Sjkim error = copyout(&msgpool[next * msginfo.msgssz], msgp, tlen); 1378101772Salfred mtx_lock(&msq_mtx); 137982607Sdillon if (error != 0) { 1380100523Salfred DPRINTF(("error (%d) copying out message segment\n", 1381100523Salfred error)); 13822729Sdfr msg_freehdr(msghdr); 1383137613Srwatson wakeup(msqkptr); 138482607Sdillon goto done2; 13852729Sdfr } 1386165403Sjkim msgp = (char *)msgp + tlen; 13872729Sdfr next = msgmaps[next].next; 13882729Sdfr } 13892729Sdfr 13902729Sdfr /* 13912729Sdfr * Done, return the actual number of bytes copied out. 13922729Sdfr */ 13932729Sdfr 13942729Sdfr msg_freehdr(msghdr); 1395137613Srwatson wakeup(msqkptr); 139683366Sjulian td->td_retval[0] = msgsz; 139782607Sdillondone2: 1398101772Salfred mtx_unlock(&msq_mtx); 139982607Sdillon return (error); 14002729Sdfr} 140177461Sdd 1402165403Sjkimint 1403225617Skmacysys_msgrcv(td, uap) 1404165403Sjkim struct thread *td; 1405165403Sjkim register struct msgrcv_args *uap; 1406165403Sjkim{ 1407165403Sjkim int error; 1408165403Sjkim long mtype; 1409165403Sjkim 1410165403Sjkim DPRINTF(("call to msgrcv(%d, %p, %zu, %ld, %d)\n", uap->msqid, 1411165403Sjkim uap->msgp, uap->msgsz, uap->msgtyp, uap->msgflg)); 1412165403Sjkim 1413165403Sjkim if ((error = kern_msgrcv(td, uap->msqid, 1414165403Sjkim (char *)uap->msgp + sizeof(mtype), uap->msgsz, 1415165403Sjkim uap->msgtyp, uap->msgflg, &mtype)) != 0) 1416165403Sjkim return (error); 1417165403Sjkim if ((error = copyout(&mtype, uap->msgp, sizeof(mtype))) != 0) 1418165403Sjkim DPRINTF(("error %d copying the message type\n", error)); 1419165403Sjkim return (error); 1420165403Sjkim} 1421165403Sjkim 142277461Sddstatic int 142377461Sddsysctl_msqids(SYSCTL_HANDLER_ARGS) 142477461Sdd{ 1425298835Sjamie struct msqid_kernel tmsqk; 1426298835Sjamie struct prison *pr, *rpr; 1427298835Sjamie int error, i; 142877461Sdd 1429298835Sjamie pr = req->td->td_ucred->cr_prison; 1430298835Sjamie rpr = msg_find_prison(req->td->td_ucred); 1431298835Sjamie error = 0; 1432298835Sjamie for (i = 0; i < msginfo.msgmni; i++) { 1433298835Sjamie mtx_lock(&msq_mtx); 1434298835Sjamie if (msqids[i].u.msg_qbytes == 0 || rpr == NULL || 1435298835Sjamie msq_prison_cansee(rpr, &msqids[i]) != 0) 1436298835Sjamie bzero(&tmsqk, sizeof(tmsqk)); 1437298835Sjamie else { 1438298835Sjamie tmsqk = msqids[i]; 1439298835Sjamie if (tmsqk.cred->cr_prison != pr) 1440298835Sjamie tmsqk.u.msg_perm.key = IPC_PRIVATE; 1441298835Sjamie } 1442298835Sjamie mtx_unlock(&msq_mtx); 1443298835Sjamie error = SYSCTL_OUT(req, &tmsqk, sizeof(tmsqk)); 1444298835Sjamie if (error != 0) 1445298835Sjamie break; 1446298835Sjamie } 1447298835Sjamie return (error); 144877461Sdd} 144977461Sdd 1450141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgmax, CTLFLAG_RD, &msginfo.msgmax, 0, 1451141710Scsjp "Maximum message size"); 1452141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgmni, CTLFLAG_RDTUN, &msginfo.msgmni, 0, 1453141710Scsjp "Number of message queue identifiers"); 1454141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgmnb, CTLFLAG_RDTUN, &msginfo.msgmnb, 0, 1455141710Scsjp "Maximum number of bytes in a queue"); 1456141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgtql, CTLFLAG_RDTUN, &msginfo.msgtql, 0, 1457141710Scsjp "Maximum number of messages in the system"); 1458141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgssz, CTLFLAG_RDTUN, &msginfo.msgssz, 0, 1459141710Scsjp "Size of a message segment"); 1460141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgseg, CTLFLAG_RDTUN, &msginfo.msgseg, 0, 1461141710Scsjp "Number of message segments"); 1462298835SjamieSYSCTL_PROC(_kern_ipc, OID_AUTO, msqids, 1463298835Sjamie CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, 1464329741Sbrooks NULL, 0, sysctl_msqids, "", 1465329741Sbrooks "Array of struct msqid_kernel for each potential message queue"); 1466194894Sjhb 1467298835Sjamiestatic int 1468298835Sjamiemsg_prison_check(void *obj, void *data) 1469298835Sjamie{ 1470298835Sjamie struct prison *pr = obj; 1471298835Sjamie struct prison *prpr; 1472298835Sjamie struct vfsoptlist *opts = data; 1473298835Sjamie int error, jsys; 1474298835Sjamie 1475298835Sjamie /* 1476298835Sjamie * sysvmsg is a jailsys integer. 1477298835Sjamie * It must be "disable" if the parent jail is disabled. 1478298835Sjamie */ 1479298835Sjamie error = vfs_copyopt(opts, "sysvmsg", &jsys, sizeof(jsys)); 1480298835Sjamie if (error != ENOENT) { 1481298835Sjamie if (error != 0) 1482298835Sjamie return (error); 1483298835Sjamie switch (jsys) { 1484298835Sjamie case JAIL_SYS_DISABLE: 1485298835Sjamie break; 1486298835Sjamie case JAIL_SYS_NEW: 1487298835Sjamie case JAIL_SYS_INHERIT: 1488298835Sjamie prison_lock(pr->pr_parent); 1489298835Sjamie prpr = osd_jail_get(pr->pr_parent, msg_prison_slot); 1490298835Sjamie prison_unlock(pr->pr_parent); 1491298835Sjamie if (prpr == NULL) 1492298835Sjamie return (EPERM); 1493298835Sjamie break; 1494298835Sjamie default: 1495298835Sjamie return (EINVAL); 1496298835Sjamie } 1497298835Sjamie } 1498298835Sjamie 1499298835Sjamie return (0); 1500298835Sjamie} 1501298835Sjamie 1502298835Sjamiestatic int 1503298835Sjamiemsg_prison_set(void *obj, void *data) 1504298835Sjamie{ 1505298835Sjamie struct prison *pr = obj; 1506298835Sjamie struct prison *tpr, *orpr, *nrpr, *trpr; 1507298835Sjamie struct vfsoptlist *opts = data; 1508298835Sjamie void *rsv; 1509298835Sjamie int jsys, descend; 1510298835Sjamie 1511298835Sjamie /* 1512298835Sjamie * sysvmsg controls which jail is the root of the associated msgs (this 1513298835Sjamie * jail or same as the parent), or if the feature is available at all. 1514298835Sjamie */ 1515298835Sjamie if (vfs_copyopt(opts, "sysvmsg", &jsys, sizeof(jsys)) == ENOENT) 1516298835Sjamie jsys = vfs_flagopt(opts, "allow.sysvipc", NULL, 0) 1517298835Sjamie ? JAIL_SYS_INHERIT 1518298835Sjamie : vfs_flagopt(opts, "allow.nosysvipc", NULL, 0) 1519298835Sjamie ? JAIL_SYS_DISABLE 1520298835Sjamie : -1; 1521298835Sjamie if (jsys == JAIL_SYS_DISABLE) { 1522298835Sjamie prison_lock(pr); 1523298835Sjamie orpr = osd_jail_get(pr, msg_prison_slot); 1524298835Sjamie if (orpr != NULL) 1525298835Sjamie osd_jail_del(pr, msg_prison_slot); 1526298835Sjamie prison_unlock(pr); 1527298835Sjamie if (orpr != NULL) { 1528298835Sjamie if (orpr == pr) 1529298835Sjamie msg_prison_cleanup(pr); 1530298835Sjamie /* Disable all child jails as well. */ 1531298835Sjamie FOREACH_PRISON_DESCENDANT(pr, tpr, descend) { 1532298835Sjamie prison_lock(tpr); 1533298835Sjamie trpr = osd_jail_get(tpr, msg_prison_slot); 1534298835Sjamie if (trpr != NULL) { 1535298835Sjamie osd_jail_del(tpr, msg_prison_slot); 1536298835Sjamie prison_unlock(tpr); 1537298835Sjamie if (trpr == tpr) 1538298835Sjamie msg_prison_cleanup(tpr); 1539298835Sjamie } else { 1540298835Sjamie prison_unlock(tpr); 1541298835Sjamie descend = 0; 1542298835Sjamie } 1543298835Sjamie } 1544298835Sjamie } 1545298835Sjamie } else if (jsys != -1) { 1546298835Sjamie if (jsys == JAIL_SYS_NEW) 1547298835Sjamie nrpr = pr; 1548298835Sjamie else { 1549298835Sjamie prison_lock(pr->pr_parent); 1550298835Sjamie nrpr = osd_jail_get(pr->pr_parent, msg_prison_slot); 1551298835Sjamie prison_unlock(pr->pr_parent); 1552298835Sjamie } 1553298835Sjamie rsv = osd_reserve(msg_prison_slot); 1554298835Sjamie prison_lock(pr); 1555298835Sjamie orpr = osd_jail_get(pr, msg_prison_slot); 1556298835Sjamie if (orpr != nrpr) 1557298835Sjamie (void)osd_jail_set_reserved(pr, msg_prison_slot, rsv, 1558298835Sjamie nrpr); 1559298835Sjamie else 1560298835Sjamie osd_free_reserved(rsv); 1561298835Sjamie prison_unlock(pr); 1562298835Sjamie if (orpr != nrpr) { 1563298835Sjamie if (orpr == pr) 1564298835Sjamie msg_prison_cleanup(pr); 1565298835Sjamie if (orpr != NULL) { 1566298835Sjamie /* Change child jails matching the old root, */ 1567298835Sjamie FOREACH_PRISON_DESCENDANT(pr, tpr, descend) { 1568298835Sjamie prison_lock(tpr); 1569298835Sjamie trpr = osd_jail_get(tpr, 1570298835Sjamie msg_prison_slot); 1571298835Sjamie if (trpr == orpr) { 1572298835Sjamie (void)osd_jail_set(tpr, 1573298835Sjamie msg_prison_slot, nrpr); 1574298835Sjamie prison_unlock(tpr); 1575298835Sjamie if (trpr == tpr) 1576298835Sjamie msg_prison_cleanup(tpr); 1577298835Sjamie } else { 1578298835Sjamie prison_unlock(tpr); 1579298835Sjamie descend = 0; 1580298835Sjamie } 1581298835Sjamie } 1582298835Sjamie } 1583298835Sjamie } 1584298835Sjamie } 1585298835Sjamie 1586298835Sjamie return (0); 1587298835Sjamie} 1588298835Sjamie 1589298835Sjamiestatic int 1590298835Sjamiemsg_prison_get(void *obj, void *data) 1591298835Sjamie{ 1592298835Sjamie struct prison *pr = obj; 1593298835Sjamie struct prison *rpr; 1594298835Sjamie struct vfsoptlist *opts = data; 1595298835Sjamie int error, jsys; 1596298835Sjamie 1597298835Sjamie /* Set sysvmsg based on the jail's root prison. */ 1598298835Sjamie prison_lock(pr); 1599298835Sjamie rpr = osd_jail_get(pr, msg_prison_slot); 1600298835Sjamie prison_unlock(pr); 1601298835Sjamie jsys = rpr == NULL ? JAIL_SYS_DISABLE 1602298835Sjamie : rpr == pr ? JAIL_SYS_NEW : JAIL_SYS_INHERIT; 1603298835Sjamie error = vfs_setopt(opts, "sysvmsg", &jsys, sizeof(jsys)); 1604298835Sjamie if (error == ENOENT) 1605298835Sjamie error = 0; 1606298835Sjamie return (error); 1607298835Sjamie} 1608298835Sjamie 1609298835Sjamiestatic int 1610298835Sjamiemsg_prison_remove(void *obj, void *data __unused) 1611298835Sjamie{ 1612298835Sjamie struct prison *pr = obj; 1613298835Sjamie struct prison *rpr; 1614298835Sjamie 1615298835Sjamie prison_lock(pr); 1616298835Sjamie rpr = osd_jail_get(pr, msg_prison_slot); 1617298835Sjamie prison_unlock(pr); 1618298835Sjamie if (rpr == pr) 1619298835Sjamie msg_prison_cleanup(pr); 1620298835Sjamie return (0); 1621298835Sjamie} 1622298835Sjamie 1623298835Sjamiestatic void 1624298835Sjamiemsg_prison_cleanup(struct prison *pr) 1625298835Sjamie{ 1626298835Sjamie struct msqid_kernel *msqkptr; 1627298835Sjamie int i; 1628298835Sjamie 1629298835Sjamie /* Remove any msqs that belong to this jail. */ 1630298835Sjamie mtx_lock(&msq_mtx); 1631298835Sjamie for (i = 0; i < msginfo.msgmni; i++) { 1632298835Sjamie msqkptr = &msqids[i]; 1633298835Sjamie if (msqkptr->u.msg_qbytes != 0 && 1634298835Sjamie msqkptr->cred != NULL && msqkptr->cred->cr_prison == pr) 1635298835Sjamie msq_remove(msqkptr); 1636298835Sjamie } 1637298835Sjamie mtx_unlock(&msq_mtx); 1638298835Sjamie} 1639298835Sjamie 1640298835SjamieSYSCTL_JAIL_PARAM_SYS_NODE(sysvmsg, CTLFLAG_RW, "SYSV message queues"); 1641298835Sjamie 1642205323Skib#ifdef COMPAT_FREEBSD32 1643205323Skibint 1644205323Skibfreebsd32_msgsys(struct thread *td, struct freebsd32_msgsys_args *uap) 1645205323Skib{ 1646205323Skib 1647194894Sjhb#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1648194894Sjhb defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1649205323Skib switch (uap->which) { 1650205323Skib case 0: 1651205323Skib return (freebsd7_freebsd32_msgctl(td, 1652205323Skib (struct freebsd7_freebsd32_msgctl_args *)&uap->a2)); 1653205323Skib case 2: 1654205323Skib return (freebsd32_msgsnd(td, 1655205323Skib (struct freebsd32_msgsnd_args *)&uap->a2)); 1656205323Skib case 3: 1657205323Skib return (freebsd32_msgrcv(td, 1658205323Skib (struct freebsd32_msgrcv_args *)&uap->a2)); 1659205323Skib default: 1660225617Skmacy return (sys_msgsys(td, (struct msgsys_args *)uap)); 1661205323Skib } 1662205323Skib#else 1663205323Skib return (nosys(td, NULL)); 1664205323Skib#endif 1665205323Skib} 1666194894Sjhb 1667205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1668205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1669205323Skibint 1670205323Skibfreebsd7_freebsd32_msgctl(struct thread *td, 1671205323Skib struct freebsd7_freebsd32_msgctl_args *uap) 1672205323Skib{ 1673205323Skib struct msqid_ds msqbuf; 1674205323Skib struct msqid_ds32_old msqbuf32; 1675205323Skib int error; 1676205323Skib 1677205323Skib if (uap->cmd == IPC_SET) { 1678205323Skib error = copyin(uap->buf, &msqbuf32, sizeof(msqbuf32)); 1679205323Skib if (error) 1680205323Skib return (error); 1681205323Skib freebsd32_ipcperm_old_in(&msqbuf32.msg_perm, &msqbuf.msg_perm); 1682205323Skib PTRIN_CP(msqbuf32, msqbuf, msg_first); 1683205323Skib PTRIN_CP(msqbuf32, msqbuf, msg_last); 1684205323Skib CP(msqbuf32, msqbuf, msg_cbytes); 1685205323Skib CP(msqbuf32, msqbuf, msg_qnum); 1686205323Skib CP(msqbuf32, msqbuf, msg_qbytes); 1687205323Skib CP(msqbuf32, msqbuf, msg_lspid); 1688205323Skib CP(msqbuf32, msqbuf, msg_lrpid); 1689205323Skib CP(msqbuf32, msqbuf, msg_stime); 1690205323Skib CP(msqbuf32, msqbuf, msg_rtime); 1691205323Skib CP(msqbuf32, msqbuf, msg_ctime); 1692205323Skib } 1693205323Skib error = kern_msgctl(td, uap->msqid, uap->cmd, &msqbuf); 1694205323Skib if (error) 1695205323Skib return (error); 1696205323Skib if (uap->cmd == IPC_STAT) { 1697205323Skib bzero(&msqbuf32, sizeof(msqbuf32)); 1698205323Skib freebsd32_ipcperm_old_out(&msqbuf.msg_perm, &msqbuf32.msg_perm); 1699205323Skib PTROUT_CP(msqbuf, msqbuf32, msg_first); 1700205323Skib PTROUT_CP(msqbuf, msqbuf32, msg_last); 1701205323Skib CP(msqbuf, msqbuf32, msg_cbytes); 1702205323Skib CP(msqbuf, msqbuf32, msg_qnum); 1703205323Skib CP(msqbuf, msqbuf32, msg_qbytes); 1704205323Skib CP(msqbuf, msqbuf32, msg_lspid); 1705205323Skib CP(msqbuf, msqbuf32, msg_lrpid); 1706205323Skib CP(msqbuf, msqbuf32, msg_stime); 1707205323Skib CP(msqbuf, msqbuf32, msg_rtime); 1708205323Skib CP(msqbuf, msqbuf32, msg_ctime); 1709205323Skib error = copyout(&msqbuf32, uap->buf, sizeof(struct msqid_ds32)); 1710205323Skib } 1711205323Skib return (error); 1712205323Skib} 1713205323Skib#endif 1714205323Skib 1715205323Skibint 1716205323Skibfreebsd32_msgctl(struct thread *td, struct freebsd32_msgctl_args *uap) 1717205323Skib{ 1718205323Skib struct msqid_ds msqbuf; 1719205323Skib struct msqid_ds32 msqbuf32; 1720205323Skib int error; 1721205323Skib 1722205323Skib if (uap->cmd == IPC_SET) { 1723205323Skib error = copyin(uap->buf, &msqbuf32, sizeof(msqbuf32)); 1724205323Skib if (error) 1725205323Skib return (error); 1726205323Skib freebsd32_ipcperm_in(&msqbuf32.msg_perm, &msqbuf.msg_perm); 1727205323Skib PTRIN_CP(msqbuf32, msqbuf, msg_first); 1728205323Skib PTRIN_CP(msqbuf32, msqbuf, msg_last); 1729205323Skib CP(msqbuf32, msqbuf, msg_cbytes); 1730205323Skib CP(msqbuf32, msqbuf, msg_qnum); 1731205323Skib CP(msqbuf32, msqbuf, msg_qbytes); 1732205323Skib CP(msqbuf32, msqbuf, msg_lspid); 1733205323Skib CP(msqbuf32, msqbuf, msg_lrpid); 1734205323Skib CP(msqbuf32, msqbuf, msg_stime); 1735205323Skib CP(msqbuf32, msqbuf, msg_rtime); 1736205323Skib CP(msqbuf32, msqbuf, msg_ctime); 1737205323Skib } 1738205323Skib error = kern_msgctl(td, uap->msqid, uap->cmd, &msqbuf); 1739205323Skib if (error) 1740205323Skib return (error); 1741205323Skib if (uap->cmd == IPC_STAT) { 1742205323Skib freebsd32_ipcperm_out(&msqbuf.msg_perm, &msqbuf32.msg_perm); 1743205323Skib PTROUT_CP(msqbuf, msqbuf32, msg_first); 1744205323Skib PTROUT_CP(msqbuf, msqbuf32, msg_last); 1745205323Skib CP(msqbuf, msqbuf32, msg_cbytes); 1746205323Skib CP(msqbuf, msqbuf32, msg_qnum); 1747205323Skib CP(msqbuf, msqbuf32, msg_qbytes); 1748205323Skib CP(msqbuf, msqbuf32, msg_lspid); 1749205323Skib CP(msqbuf, msqbuf32, msg_lrpid); 1750205323Skib CP(msqbuf, msqbuf32, msg_stime); 1751205323Skib CP(msqbuf, msqbuf32, msg_rtime); 1752205323Skib CP(msqbuf, msqbuf32, msg_ctime); 1753205323Skib error = copyout(&msqbuf32, uap->buf, sizeof(struct msqid_ds32)); 1754205323Skib } 1755205323Skib return (error); 1756205323Skib} 1757205323Skib 1758205323Skibint 1759205323Skibfreebsd32_msgsnd(struct thread *td, struct freebsd32_msgsnd_args *uap) 1760205323Skib{ 1761205323Skib const void *msgp; 1762205323Skib long mtype; 1763205323Skib int32_t mtype32; 1764205323Skib int error; 1765205323Skib 1766205323Skib msgp = PTRIN(uap->msgp); 1767205323Skib if ((error = copyin(msgp, &mtype32, sizeof(mtype32))) != 0) 1768205323Skib return (error); 1769205323Skib mtype = mtype32; 1770205323Skib return (kern_msgsnd(td, uap->msqid, 1771205323Skib (const char *)msgp + sizeof(mtype32), 1772205323Skib uap->msgsz, uap->msgflg, mtype)); 1773205323Skib} 1774205323Skib 1775205323Skibint 1776205323Skibfreebsd32_msgrcv(struct thread *td, struct freebsd32_msgrcv_args *uap) 1777205323Skib{ 1778205323Skib void *msgp; 1779205323Skib long mtype; 1780205323Skib int32_t mtype32; 1781205323Skib int error; 1782205323Skib 1783205323Skib msgp = PTRIN(uap->msgp); 1784205323Skib if ((error = kern_msgrcv(td, uap->msqid, 1785205323Skib (char *)msgp + sizeof(mtype32), uap->msgsz, 1786205323Skib uap->msgtyp, uap->msgflg, &mtype)) != 0) 1787205323Skib return (error); 1788205323Skib mtype32 = (int32_t)mtype; 1789205323Skib return (copyout(&mtype32, msgp, sizeof(mtype32))); 1790205323Skib} 1791205323Skib#endif 1792205323Skib 1793205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1794205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1795205323Skib 1796194894Sjhb/* XXX casting to (sy_call_t *) is bogus, as usual. */ 1797194894Sjhbstatic sy_call_t *msgcalls[] = { 1798225617Skmacy (sy_call_t *)freebsd7_msgctl, (sy_call_t *)sys_msgget, 1799225617Skmacy (sy_call_t *)sys_msgsnd, (sy_call_t *)sys_msgrcv 1800194894Sjhb}; 1801194894Sjhb 1802194894Sjhb/* 1803194894Sjhb * Entry point for all MSG calls. 1804194894Sjhb */ 1805194894Sjhbint 1806225617Skmacysys_msgsys(td, uap) 1807194894Sjhb struct thread *td; 1808194894Sjhb /* XXX actually varargs. */ 1809194894Sjhb struct msgsys_args /* { 1810194894Sjhb int which; 1811194894Sjhb int a2; 1812194894Sjhb int a3; 1813194894Sjhb int a4; 1814194894Sjhb int a5; 1815194894Sjhb int a6; 1816194894Sjhb } */ *uap; 1817194894Sjhb{ 1818194894Sjhb int error; 1819194894Sjhb 1820194894Sjhb if (uap->which < 0 || 1821194894Sjhb uap->which >= sizeof(msgcalls)/sizeof(msgcalls[0])) 1822194894Sjhb return (EINVAL); 1823194894Sjhb error = (*msgcalls[uap->which])(td, &uap->a2); 1824194894Sjhb return (error); 1825194894Sjhb} 1826194910Sjhb 1827205323Skib#ifndef CP 1828194910Sjhb#define CP(src, dst, fld) do { (dst).fld = (src).fld; } while (0) 1829205323Skib#endif 1830194910Sjhb 1831194910Sjhb#ifndef _SYS_SYSPROTO_H_ 1832194910Sjhbstruct freebsd7_msgctl_args { 1833194910Sjhb int msqid; 1834194910Sjhb int cmd; 1835194910Sjhb struct msqid_ds_old *buf; 1836194910Sjhb}; 1837194910Sjhb#endif 1838194910Sjhbint 1839194910Sjhbfreebsd7_msgctl(td, uap) 1840194910Sjhb struct thread *td; 1841194910Sjhb struct freebsd7_msgctl_args *uap; 1842194910Sjhb{ 1843194910Sjhb struct msqid_ds_old msqold; 1844194910Sjhb struct msqid_ds msqbuf; 1845194910Sjhb int error; 1846194910Sjhb 1847194910Sjhb DPRINTF(("call to freebsd7_msgctl(%d, %d, %p)\n", uap->msqid, uap->cmd, 1848194910Sjhb uap->buf)); 1849194910Sjhb if (uap->cmd == IPC_SET) { 1850194910Sjhb error = copyin(uap->buf, &msqold, sizeof(msqold)); 1851194910Sjhb if (error) 1852194910Sjhb return (error); 1853194910Sjhb ipcperm_old2new(&msqold.msg_perm, &msqbuf.msg_perm); 1854194910Sjhb CP(msqold, msqbuf, msg_first); 1855194910Sjhb CP(msqold, msqbuf, msg_last); 1856194910Sjhb CP(msqold, msqbuf, msg_cbytes); 1857194910Sjhb CP(msqold, msqbuf, msg_qnum); 1858194910Sjhb CP(msqold, msqbuf, msg_qbytes); 1859194910Sjhb CP(msqold, msqbuf, msg_lspid); 1860194910Sjhb CP(msqold, msqbuf, msg_lrpid); 1861194910Sjhb CP(msqold, msqbuf, msg_stime); 1862194910Sjhb CP(msqold, msqbuf, msg_rtime); 1863194910Sjhb CP(msqold, msqbuf, msg_ctime); 1864194910Sjhb } 1865194910Sjhb error = kern_msgctl(td, uap->msqid, uap->cmd, &msqbuf); 1866194910Sjhb if (error) 1867194910Sjhb return (error); 1868194910Sjhb if (uap->cmd == IPC_STAT) { 1869194910Sjhb bzero(&msqold, sizeof(msqold)); 1870194910Sjhb ipcperm_new2old(&msqbuf.msg_perm, &msqold.msg_perm); 1871194910Sjhb CP(msqbuf, msqold, msg_first); 1872194910Sjhb CP(msqbuf, msqold, msg_last); 1873194910Sjhb CP(msqbuf, msqold, msg_cbytes); 1874194910Sjhb CP(msqbuf, msqold, msg_qnum); 1875194910Sjhb CP(msqbuf, msqold, msg_qbytes); 1876194910Sjhb CP(msqbuf, msqold, msg_lspid); 1877194910Sjhb CP(msqbuf, msqold, msg_lrpid); 1878194910Sjhb CP(msqbuf, msqold, msg_stime); 1879194910Sjhb CP(msqbuf, msqold, msg_rtime); 1880194910Sjhb CP(msqbuf, msqold, msg_ctime); 1881194910Sjhb error = copyout(&msqold, uap->buf, sizeof(struct msqid_ds_old)); 1882194910Sjhb } 1883194910Sjhb return (error); 1884194910Sjhb} 1885194910Sjhb 1886194910Sjhb#undef CP 1887194910Sjhb 1888194894Sjhb#endif /* COMPAT_FREEBSD4 || COMPAT_FREEBSD5 || COMPAT_FREEBSD6 || 1889194894Sjhb COMPAT_FREEBSD7 */ 1890