sysv_msg.c revision 220399
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: head/sys/kern/sysv_msg.c 220399 2011-04-06 19:08:50Z trasz $"); 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> 652729Sdfr#include <sys/msg.h> 66220398Strasz#include <sys/racct.h> 6769449Salfred#include <sys/syscall.h> 68140839Ssobomax#include <sys/syscallsubr.h> 6911626Sbde#include <sys/sysent.h> 7059839Speter#include <sys/sysctl.h> 7159839Speter#include <sys/malloc.h> 7268024Srwatson#include <sys/jail.h> 732729Sdfr 74163606Srwatson#include <security/mac/mac_framework.h> 75163606Srwatson 76219028SnetchildFEATURE(sysv_msg, "System V message queues support"); 77219028Snetchild 7859839Speterstatic MALLOC_DEFINE(M_MSG, "msg", "SVID compatible message queues"); 7959839Speter 80205323Skibstatic int msginit(void); 8192723Salfredstatic int msgunload(void); 8292723Salfredstatic int sysvmsg_modload(struct module *, int, void *); 8310358Sjulian 84100523Salfred#ifdef MSG_DEBUG 85100523Salfred#define DPRINTF(a) printf a 86100523Salfred#else 87194575Srdivacky#define DPRINTF(a) (void)0 88100523Salfred#endif 892729Sdfr 9092723Salfredstatic void msg_freehdr(struct msg *msghdr); 912729Sdfr 9259839Speter#ifndef MSGSSZ 9359839Speter#define MSGSSZ 8 /* Each segment must be 2^N long */ 9459839Speter#endif 9559839Speter#ifndef MSGSEG 9659839Speter#define MSGSEG 2048 /* must be less than 32767 */ 9759839Speter#endif 9859839Speter#define MSGMAX (MSGSSZ*MSGSEG) 9959839Speter#ifndef MSGMNB 10059839Speter#define MSGMNB 2048 /* max # of bytes in a queue */ 10159839Speter#endif 10259839Speter#ifndef MSGMNI 10359839Speter#define MSGMNI 40 10459839Speter#endif 10559839Speter#ifndef MSGTQL 10659839Speter#define MSGTQL 40 10759839Speter#endif 10859839Speter 10959839Speter/* 11059839Speter * Based on the configuration parameters described in an SVR2 (yes, two) 11159839Speter * config(1m) man page. 11259839Speter * 11359839Speter * Each message is broken up and stored in segments that are msgssz bytes 11459839Speter * long. For efficiency reasons, this should be a power of two. Also, 11559839Speter * it doesn't make sense if it is less than 8 or greater than about 256. 11659839Speter * Consequently, msginit in kern/sysv_msg.c checks that msgssz is a power of 11759839Speter * two between 8 and 1024 inclusive (and panic's if it isn't). 11859839Speter */ 11959839Speterstruct msginfo msginfo = { 12059839Speter MSGMAX, /* max chars in a message */ 12159839Speter MSGMNI, /* # of message queue identifiers */ 12259839Speter MSGMNB, /* max chars in a queue */ 12359839Speter MSGTQL, /* max messages in system */ 12459839Speter MSGSSZ, /* size of a message segment */ 12559839Speter /* (must be small power of 2 greater than 4) */ 12659839Speter MSGSEG /* number of message segments */ 12759839Speter}; 12859839Speter 12959839Speter/* 13059839Speter * macros to convert between msqid_ds's and msqid's. 13159839Speter * (specific to this implementation) 13259839Speter */ 13359839Speter#define MSQID(ix,ds) ((ix) & 0xffff | (((ds).msg_perm.seq << 16) & 0xffff0000)) 13459839Speter#define MSQID_IX(id) ((id) & 0xffff) 13559839Speter#define MSQID_SEQ(id) (((id) >> 16) & 0xffff) 13659839Speter 13759839Speter/* 13859839Speter * The rest of this file is specific to this particular implementation. 13959839Speter */ 14059839Speter 14159839Speterstruct msgmap { 14259839Speter short next; /* next segment in buffer */ 14359839Speter /* -1 -> available */ 14459839Speter /* 0..(MSGSEG-1) -> index of next segment */ 14559839Speter}; 14659839Speter 14759839Speter#define MSG_LOCKED 01000 /* Is this msqid_ds locked? */ 14859839Speter 14912819Sphkstatic int nfree_msgmaps; /* # of free map entries */ 15012819Sphkstatic short free_msgmaps; /* head of linked list of free map entries */ 15159839Speterstatic struct msg *free_msghdrs;/* list of free msg headers */ 15259839Speterstatic char *msgpool; /* MSGMAX byte long msg buffer pool */ 15359839Speterstatic struct msgmap *msgmaps; /* MSGSEG msgmap structures */ 15459839Speterstatic struct msg *msghdrs; /* MSGTQL msg headers */ 155137613Srwatsonstatic struct msqid_kernel *msqids; /* MSGMNI msqid_kernel struct's */ 156101772Salfredstatic struct mtx msq_mtx; /* global mutex for message queues. */ 1572729Sdfr 158205323Skibstatic struct syscall_helper_data msg_syscalls[] = { 159205323Skib SYSCALL_INIT_HELPER(msgctl), 160205323Skib SYSCALL_INIT_HELPER(msgget), 161205323Skib SYSCALL_INIT_HELPER(msgsnd), 162205323Skib SYSCALL_INIT_HELPER(msgrcv), 163205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 164205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 165205323Skib SYSCALL_INIT_HELPER(msgsys), 166205323Skib SYSCALL_INIT_HELPER(freebsd7_msgctl), 167205323Skib#endif 168205323Skib SYSCALL_INIT_LAST 169205323Skib}; 170205323Skib 171205323Skib#ifdef COMPAT_FREEBSD32 172205323Skib#include <compat/freebsd32/freebsd32.h> 173205323Skib#include <compat/freebsd32/freebsd32_ipc.h> 174205323Skib#include <compat/freebsd32/freebsd32_proto.h> 175205323Skib#include <compat/freebsd32/freebsd32_signal.h> 176205323Skib#include <compat/freebsd32/freebsd32_syscall.h> 177205323Skib#include <compat/freebsd32/freebsd32_util.h> 178205323Skib 179205323Skibstatic struct syscall_helper_data msg32_syscalls[] = { 180205323Skib SYSCALL32_INIT_HELPER(freebsd32_msgctl), 181205323Skib SYSCALL32_INIT_HELPER(freebsd32_msgsnd), 182205323Skib SYSCALL32_INIT_HELPER(freebsd32_msgrcv), 183205323Skib SYSCALL32_INIT_HELPER(msgget), 184205323Skib SYSCALL32_INIT_HELPER(freebsd32_msgsys), 185205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 186205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 187205323Skib SYSCALL32_INIT_HELPER(freebsd7_freebsd32_msgctl), 188205323Skib#endif 189205323Skib SYSCALL_INIT_LAST 190205323Skib}; 191205323Skib#endif 192205323Skib 193205323Skibstatic int 19469449Salfredmsginit() 1952729Sdfr{ 196205323Skib int i, error; 1972729Sdfr 19883765Smr TUNABLE_INT_FETCH("kern.ipc.msgseg", &msginfo.msgseg); 19983765Smr TUNABLE_INT_FETCH("kern.ipc.msgssz", &msginfo.msgssz); 20083765Smr msginfo.msgmax = msginfo.msgseg * msginfo.msgssz; 20183765Smr TUNABLE_INT_FETCH("kern.ipc.msgmni", &msginfo.msgmni); 202139436Srwatson TUNABLE_INT_FETCH("kern.ipc.msgmnb", &msginfo.msgmnb); 203139436Srwatson TUNABLE_INT_FETCH("kern.ipc.msgtql", &msginfo.msgtql); 20483765Smr 205111119Simp msgpool = malloc(msginfo.msgmax, M_MSG, M_WAITOK); 206111119Simp msgmaps = malloc(sizeof(struct msgmap) * msginfo.msgseg, M_MSG, M_WAITOK); 207111119Simp msghdrs = malloc(sizeof(struct msg) * msginfo.msgtql, M_MSG, M_WAITOK); 208137613Srwatson msqids = malloc(sizeof(struct msqid_kernel) * msginfo.msgmni, M_MSG, 209137613Srwatson M_WAITOK); 21059839Speter 2112729Sdfr /* 2122729Sdfr * msginfo.msgssz should be a power of two for efficiency reasons. 2132729Sdfr * It is also pretty silly if msginfo.msgssz is less than 8 2142729Sdfr * or greater than about 256 so ... 2152729Sdfr */ 2162729Sdfr 2172729Sdfr i = 8; 2182729Sdfr while (i < 1024 && i != msginfo.msgssz) 2192729Sdfr i <<= 1; 2202729Sdfr if (i != msginfo.msgssz) { 221100523Salfred DPRINTF(("msginfo.msgssz=%d (0x%x)\n", msginfo.msgssz, 222100523Salfred msginfo.msgssz)); 2232729Sdfr panic("msginfo.msgssz not a small power of 2"); 2242729Sdfr } 2252729Sdfr 2262729Sdfr if (msginfo.msgseg > 32767) { 227100523Salfred DPRINTF(("msginfo.msgseg=%d\n", msginfo.msgseg)); 2282729Sdfr panic("msginfo.msgseg > 32767"); 2292729Sdfr } 2302729Sdfr 2312729Sdfr for (i = 0; i < msginfo.msgseg; i++) { 2322729Sdfr if (i > 0) 2332729Sdfr msgmaps[i-1].next = i; 2342729Sdfr msgmaps[i].next = -1; /* implies entry is available */ 2352729Sdfr } 2362729Sdfr free_msgmaps = 0; 2372729Sdfr nfree_msgmaps = msginfo.msgseg; 2382729Sdfr 2392729Sdfr for (i = 0; i < msginfo.msgtql; i++) { 2402729Sdfr msghdrs[i].msg_type = 0; 2412729Sdfr if (i > 0) 2422729Sdfr msghdrs[i-1].msg_next = &msghdrs[i]; 2432729Sdfr msghdrs[i].msg_next = NULL; 244140614Srwatson#ifdef MAC 245172930Srwatson mac_sysvmsg_init(&msghdrs[i]); 246140614Srwatson#endif 2472729Sdfr } 2482729Sdfr free_msghdrs = &msghdrs[0]; 2492729Sdfr 2502729Sdfr for (i = 0; i < msginfo.msgmni; i++) { 251137613Srwatson msqids[i].u.msg_qbytes = 0; /* implies entry is available */ 252137613Srwatson msqids[i].u.msg_perm.seq = 0; /* reset to a known value */ 253137613Srwatson msqids[i].u.msg_perm.mode = 0; 254140614Srwatson#ifdef MAC 255172930Srwatson mac_sysvmsq_init(&msqids[i]); 256140614Srwatson#endif 2572729Sdfr } 258101772Salfred mtx_init(&msq_mtx, "msq", NULL, MTX_DEF); 259205323Skib 260205323Skib error = syscall_helper_register(msg_syscalls); 261205323Skib if (error != 0) 262205323Skib return (error); 263205323Skib#ifdef COMPAT_FREEBSD32 264205323Skib error = syscall32_helper_register(msg32_syscalls); 265205323Skib if (error != 0) 266205323Skib return (error); 267205323Skib#endif 268205323Skib return (0); 2692729Sdfr} 2702729Sdfr 27169449Salfredstatic int 27269449Salfredmsgunload() 27369449Salfred{ 274137613Srwatson struct msqid_kernel *msqkptr; 27569449Salfred int msqid; 276140614Srwatson#ifdef MAC 277140614Srwatson int i; 278140614Srwatson#endif 27969449Salfred 280205323Skib syscall_helper_unregister(msg_syscalls); 281205323Skib#ifdef COMPAT_FREEBSD32 282205323Skib syscall32_helper_unregister(msg32_syscalls); 283205323Skib#endif 284205323Skib 28569449Salfred for (msqid = 0; msqid < msginfo.msgmni; msqid++) { 28669449Salfred /* 28769449Salfred * Look for an unallocated and unlocked msqid_ds. 28869449Salfred * msqid_ds's can be locked by msgsnd or msgrcv while 28969449Salfred * they are copying the message in/out. We can't 29069449Salfred * re-use the entry until they release it. 29169449Salfred */ 292137613Srwatson msqkptr = &msqids[msqid]; 293137613Srwatson if (msqkptr->u.msg_qbytes != 0 || 294137613Srwatson (msqkptr->u.msg_perm.mode & MSG_LOCKED) != 0) 29569449Salfred break; 29669449Salfred } 29769449Salfred if (msqid != msginfo.msgmni) 29869449Salfred return (EBUSY); 29969449Salfred 300140614Srwatson#ifdef MAC 301140614Srwatson for (i = 0; i < msginfo.msgtql; i++) 302172930Srwatson mac_sysvmsg_destroy(&msghdrs[i]); 303140614Srwatson for (msqid = 0; msqid < msginfo.msgmni; msqid++) 304172930Srwatson mac_sysvmsq_destroy(&msqids[msqid]); 305140614Srwatson#endif 30669449Salfred free(msgpool, M_MSG); 30769449Salfred free(msgmaps, M_MSG); 30869449Salfred free(msghdrs, M_MSG); 30969449Salfred free(msqids, M_MSG); 310101772Salfred mtx_destroy(&msq_mtx); 31169449Salfred return (0); 31269449Salfred} 31369449Salfred 31469449Salfred 31569449Salfredstatic int 31669449Salfredsysvmsg_modload(struct module *module, int cmd, void *arg) 31769449Salfred{ 31869449Salfred int error = 0; 31969449Salfred 32069449Salfred switch (cmd) { 32169449Salfred case MOD_LOAD: 322205323Skib error = msginit(); 323205323Skib if (error != 0) 324205323Skib msgunload(); 32569449Salfred break; 32669449Salfred case MOD_UNLOAD: 32769449Salfred error = msgunload(); 32869449Salfred break; 32969449Salfred case MOD_SHUTDOWN: 33069449Salfred break; 33169449Salfred default: 33269449Salfred error = EINVAL; 33369449Salfred break; 33469449Salfred } 33569449Salfred return (error); 33669449Salfred} 33769449Salfred 33871038Sdesstatic moduledata_t sysvmsg_mod = { 33971038Sdes "sysvmsg", 34069449Salfred &sysvmsg_modload, 34169449Salfred NULL 34269449Salfred}; 34369449Salfred 344194832SjhbDECLARE_MODULE(sysvmsg, sysvmsg_mod, SI_SUB_SYSV_MSG, SI_ORDER_FIRST); 34571038SdesMODULE_VERSION(sysvmsg, 1); 34669449Salfred 3472729Sdfrstatic void 3482729Sdfrmsg_freehdr(msghdr) 3492729Sdfr struct msg *msghdr; 3502729Sdfr{ 3512729Sdfr while (msghdr->msg_ts > 0) { 3522729Sdfr short next; 3532729Sdfr if (msghdr->msg_spot < 0 || msghdr->msg_spot >= msginfo.msgseg) 3542729Sdfr panic("msghdr->msg_spot out of range"); 3552729Sdfr next = msgmaps[msghdr->msg_spot].next; 3562729Sdfr msgmaps[msghdr->msg_spot].next = free_msgmaps; 3572729Sdfr free_msgmaps = msghdr->msg_spot; 3582729Sdfr nfree_msgmaps++; 3592729Sdfr msghdr->msg_spot = next; 3602729Sdfr if (msghdr->msg_ts >= msginfo.msgssz) 3612729Sdfr msghdr->msg_ts -= msginfo.msgssz; 3622729Sdfr else 3632729Sdfr msghdr->msg_ts = 0; 3642729Sdfr } 3652729Sdfr if (msghdr->msg_spot != -1) 3662729Sdfr panic("msghdr->msg_spot != -1"); 3672729Sdfr msghdr->msg_next = free_msghdrs; 3682729Sdfr free_msghdrs = msghdr; 369140614Srwatson#ifdef MAC 370172930Srwatson mac_sysvmsg_cleanup(msghdr); 371140614Srwatson#endif 3722729Sdfr} 3732729Sdfr 37412866Speter#ifndef _SYS_SYSPROTO_H_ 3752729Sdfrstruct msgctl_args { 3762729Sdfr int msqid; 3772729Sdfr int cmd; 37812866Speter struct msqid_ds *buf; 3792729Sdfr}; 38012866Speter#endif 38112866Speterint 38283366Sjulianmsgctl(td, uap) 38383366Sjulian struct thread *td; 3842729Sdfr register struct msgctl_args *uap; 3852729Sdfr{ 3862729Sdfr int msqid = uap->msqid; 3872729Sdfr int cmd = uap->cmd; 3882729Sdfr struct msqid_ds msqbuf; 389140839Ssobomax int error; 390140839Ssobomax 391165403Sjkim DPRINTF(("call to msgctl(%d, %d, %p)\n", msqid, cmd, uap->buf)); 392140839Ssobomax if (cmd == IPC_SET && 393140839Ssobomax (error = copyin(uap->buf, &msqbuf, sizeof(msqbuf))) != 0) 394140839Ssobomax return (error); 395141471Sjhb error = kern_msgctl(td, msqid, cmd, &msqbuf); 396140839Ssobomax if (cmd == IPC_STAT && error == 0) 397141471Sjhb error = copyout(&msqbuf, uap->buf, sizeof(struct msqid_ds)); 398140839Ssobomax return (error); 399140839Ssobomax} 400140839Ssobomax 401140839Ssobomaxint 402141471Sjhbkern_msgctl(td, msqid, cmd, msqbuf) 403140839Ssobomax struct thread *td; 404140839Ssobomax int msqid; 405140839Ssobomax int cmd; 406140839Ssobomax struct msqid_ds *msqbuf; 407140839Ssobomax{ 408140839Ssobomax int rval, error, msqix; 409137613Srwatson register struct msqid_kernel *msqkptr; 4102729Sdfr 411192895Sjamie if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC)) 41291703Sjhb return (ENOSYS); 41391703Sjhb 414140839Ssobomax msqix = IPCID_TO_IX(msqid); 4152729Sdfr 416140839Ssobomax if (msqix < 0 || msqix >= msginfo.msgmni) { 417140839Ssobomax DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqix, 418100523Salfred msginfo.msgmni)); 419101772Salfred return (EINVAL); 4202729Sdfr } 4212729Sdfr 422140839Ssobomax msqkptr = &msqids[msqix]; 4232729Sdfr 424101772Salfred mtx_lock(&msq_mtx); 425137613Srwatson if (msqkptr->u.msg_qbytes == 0) { 426100523Salfred DPRINTF(("no such msqid\n")); 42782607Sdillon error = EINVAL; 42882607Sdillon goto done2; 4292729Sdfr } 430140839Ssobomax if (msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) { 431100523Salfred DPRINTF(("wrong sequence number\n")); 43282607Sdillon error = EINVAL; 43382607Sdillon goto done2; 4342729Sdfr } 435140614Srwatson#ifdef MAC 436172930Srwatson error = mac_sysvmsq_check_msqctl(td->td_ucred, msqkptr, cmd); 437162468Srwatson if (error != 0) 438140614Srwatson goto done2; 439140614Srwatson#endif 4402729Sdfr 44182607Sdillon error = 0; 4422729Sdfr rval = 0; 4432729Sdfr 4442729Sdfr switch (cmd) { 4452729Sdfr 4462729Sdfr case IPC_RMID: 4472729Sdfr { 4482729Sdfr struct msg *msghdr; 449137613Srwatson if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_M))) 45082607Sdillon goto done2; 451137613Srwatson 452140614Srwatson#ifdef MAC 453140614Srwatson /* 454140614Srwatson * Check that the thread has MAC access permissions to 455140614Srwatson * individual msghdrs. Note: We need to do this in a 456140614Srwatson * separate loop because the actual loop alters the 457140614Srwatson * msq/msghdr info as it progresses, and there is no going 458140614Srwatson * back if half the way through we discover that the 459140614Srwatson * thread cannot free a certain msghdr. The msq will get 460140614Srwatson * into an inconsistent state. 461140614Srwatson */ 462140614Srwatson for (msghdr = msqkptr->u.msg_first; msghdr != NULL; 463140614Srwatson msghdr = msghdr->msg_next) { 464172930Srwatson error = mac_sysvmsq_check_msgrmid(td->td_ucred, msghdr); 465162468Srwatson if (error != 0) 466140614Srwatson goto done2; 467140614Srwatson } 468140614Srwatson#endif 469140614Srwatson 470220398Strasz racct_sub_cred(msqkptr->cred, RACCT_NMSGQ, 1); 471220398Strasz racct_sub_cred(msqkptr->cred, RACCT_MSGQQUEUED, msqkptr->u.msg_qnum); 472220398Strasz racct_sub_cred(msqkptr->cred, RACCT_MSGQSIZE, msqkptr->u.msg_cbytes); 473220388Strasz crfree(msqkptr->cred); 474220388Strasz msqkptr->cred = NULL; 475220388Strasz 4762729Sdfr /* Free the message headers */ 477137613Srwatson msghdr = msqkptr->u.msg_first; 4782729Sdfr while (msghdr != NULL) { 4792729Sdfr struct msg *msghdr_tmp; 4802729Sdfr 4812729Sdfr /* Free the segments of each message */ 482137613Srwatson msqkptr->u.msg_cbytes -= msghdr->msg_ts; 483137613Srwatson msqkptr->u.msg_qnum--; 4842729Sdfr msghdr_tmp = msghdr; 4852729Sdfr msghdr = msghdr->msg_next; 4862729Sdfr msg_freehdr(msghdr_tmp); 4872729Sdfr } 4882729Sdfr 489137613Srwatson if (msqkptr->u.msg_cbytes != 0) 4902729Sdfr panic("msg_cbytes is screwed up"); 491137613Srwatson if (msqkptr->u.msg_qnum != 0) 4922729Sdfr panic("msg_qnum is screwed up"); 4932729Sdfr 494137613Srwatson msqkptr->u.msg_qbytes = 0; /* Mark it as free */ 4952729Sdfr 496140614Srwatson#ifdef MAC 497172930Srwatson mac_sysvmsq_cleanup(msqkptr); 498140614Srwatson#endif 499140614Srwatson 500137613Srwatson wakeup(msqkptr); 5012729Sdfr } 5022729Sdfr 5032729Sdfr break; 5042729Sdfr 5052729Sdfr case IPC_SET: 506137613Srwatson if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_M))) 50782607Sdillon goto done2; 508140839Ssobomax if (msqbuf->msg_qbytes > msqkptr->u.msg_qbytes) { 509170587Srwatson error = priv_check(td, PRIV_IPC_MSGSIZE); 51082607Sdillon if (error) 51182607Sdillon goto done2; 51243426Sphk } 513140839Ssobomax if (msqbuf->msg_qbytes > msginfo.msgmnb) { 514100523Salfred DPRINTF(("can't increase msg_qbytes beyond %d" 515100523Salfred "(truncating)\n", msginfo.msgmnb)); 516140839Ssobomax msqbuf->msg_qbytes = msginfo.msgmnb; /* silently restrict qbytes to system limit */ 5172729Sdfr } 518140839Ssobomax if (msqbuf->msg_qbytes == 0) { 519100523Salfred DPRINTF(("can't reduce msg_qbytes to 0\n")); 52082607Sdillon error = EINVAL; /* non-standard errno! */ 52182607Sdillon goto done2; 5222729Sdfr } 523140839Ssobomax msqkptr->u.msg_perm.uid = msqbuf->msg_perm.uid; /* change the owner */ 524140839Ssobomax msqkptr->u.msg_perm.gid = msqbuf->msg_perm.gid; /* change the owner */ 525137613Srwatson msqkptr->u.msg_perm.mode = (msqkptr->u.msg_perm.mode & ~0777) | 526140839Ssobomax (msqbuf->msg_perm.mode & 0777); 527140839Ssobomax msqkptr->u.msg_qbytes = msqbuf->msg_qbytes; 528137613Srwatson msqkptr->u.msg_ctime = time_second; 5292729Sdfr break; 5302729Sdfr 5312729Sdfr case IPC_STAT: 532137613Srwatson if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_R))) { 533100523Salfred DPRINTF(("requester doesn't have read access\n")); 53482607Sdillon goto done2; 5352729Sdfr } 536141471Sjhb *msqbuf = msqkptr->u; 5372729Sdfr break; 5382729Sdfr 5392729Sdfr default: 540100523Salfred DPRINTF(("invalid command %d\n", cmd)); 54182607Sdillon error = EINVAL; 54282607Sdillon goto done2; 5432729Sdfr } 5442729Sdfr 54582607Sdillon if (error == 0) 54683366Sjulian td->td_retval[0] = rval; 54782607Sdillondone2: 548101772Salfred mtx_unlock(&msq_mtx); 549141471Sjhb return (error); 5502729Sdfr} 5512729Sdfr 55212866Speter#ifndef _SYS_SYSPROTO_H_ 5532729Sdfrstruct msgget_args { 5542729Sdfr key_t key; 5552729Sdfr int msgflg; 5562729Sdfr}; 55712866Speter#endif 55812866Speterint 55983366Sjulianmsgget(td, uap) 56083366Sjulian struct thread *td; 5612729Sdfr register struct msgget_args *uap; 5622729Sdfr{ 56382607Sdillon int msqid, error = 0; 5642729Sdfr int key = uap->key; 5652729Sdfr int msgflg = uap->msgflg; 56691703Sjhb struct ucred *cred = td->td_ucred; 567137613Srwatson register struct msqid_kernel *msqkptr = NULL; 5682729Sdfr 569100523Salfred DPRINTF(("msgget(0x%x, 0%o)\n", key, msgflg)); 5702729Sdfr 571192895Sjamie if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC)) 57291703Sjhb return (ENOSYS); 57391703Sjhb 574101772Salfred mtx_lock(&msq_mtx); 5752729Sdfr if (key != IPC_PRIVATE) { 5762729Sdfr for (msqid = 0; msqid < msginfo.msgmni; msqid++) { 577137613Srwatson msqkptr = &msqids[msqid]; 578137613Srwatson if (msqkptr->u.msg_qbytes != 0 && 579137613Srwatson msqkptr->u.msg_perm.key == key) 5802729Sdfr break; 5812729Sdfr } 5822729Sdfr if (msqid < msginfo.msgmni) { 583100523Salfred DPRINTF(("found public key\n")); 5842729Sdfr if ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL)) { 585100523Salfred DPRINTF(("not exclusive\n")); 58682607Sdillon error = EEXIST; 58782607Sdillon goto done2; 5882729Sdfr } 589137613Srwatson if ((error = ipcperm(td, &msqkptr->u.msg_perm, 590137613Srwatson msgflg & 0700))) { 591100523Salfred DPRINTF(("requester doesn't have 0%o access\n", 592100523Salfred msgflg & 0700)); 59382607Sdillon goto done2; 5942729Sdfr } 595140614Srwatson#ifdef MAC 596172930Srwatson error = mac_sysvmsq_check_msqget(cred, msqkptr); 597162468Srwatson if (error != 0) 598140614Srwatson goto done2; 599140614Srwatson#endif 6002729Sdfr goto found; 6012729Sdfr } 6022729Sdfr } 6032729Sdfr 604100523Salfred DPRINTF(("need to allocate the msqid_ds\n")); 6052729Sdfr if (key == IPC_PRIVATE || (msgflg & IPC_CREAT)) { 6062729Sdfr for (msqid = 0; msqid < msginfo.msgmni; msqid++) { 6072729Sdfr /* 6082729Sdfr * Look for an unallocated and unlocked msqid_ds. 6092729Sdfr * msqid_ds's can be locked by msgsnd or msgrcv while 6102729Sdfr * they are copying the message in/out. We can't 6112729Sdfr * re-use the entry until they release it. 6122729Sdfr */ 613137613Srwatson msqkptr = &msqids[msqid]; 614137613Srwatson if (msqkptr->u.msg_qbytes == 0 && 615137613Srwatson (msqkptr->u.msg_perm.mode & MSG_LOCKED) == 0) 6162729Sdfr break; 6172729Sdfr } 6182729Sdfr if (msqid == msginfo.msgmni) { 619100523Salfred DPRINTF(("no more msqid_ds's available\n")); 62082607Sdillon error = ENOSPC; 62182607Sdillon goto done2; 6222729Sdfr } 623220398Strasz PROC_LOCK(td->td_proc); 624220398Strasz error = racct_add(td->td_proc, RACCT_NMSGQ, 1); 625220398Strasz PROC_UNLOCK(td->td_proc); 626220398Strasz if (error != 0) { 627220398Strasz error = ENOSPC; 628220398Strasz goto done2; 629220398Strasz } 630100523Salfred DPRINTF(("msqid %d is available\n", msqid)); 631137613Srwatson msqkptr->u.msg_perm.key = key; 632137613Srwatson msqkptr->u.msg_perm.cuid = cred->cr_uid; 633137613Srwatson msqkptr->u.msg_perm.uid = cred->cr_uid; 634137613Srwatson msqkptr->u.msg_perm.cgid = cred->cr_gid; 635137613Srwatson msqkptr->u.msg_perm.gid = cred->cr_gid; 636137613Srwatson msqkptr->u.msg_perm.mode = (msgflg & 0777); 637220399Strasz msqkptr->cred = crhold(cred); 6382729Sdfr /* Make sure that the returned msqid is unique */ 639137613Srwatson msqkptr->u.msg_perm.seq = (msqkptr->u.msg_perm.seq + 1) & 0x7fff; 640137613Srwatson msqkptr->u.msg_first = NULL; 641137613Srwatson msqkptr->u.msg_last = NULL; 642137613Srwatson msqkptr->u.msg_cbytes = 0; 643137613Srwatson msqkptr->u.msg_qnum = 0; 644137613Srwatson msqkptr->u.msg_qbytes = msginfo.msgmnb; 645137613Srwatson msqkptr->u.msg_lspid = 0; 646137613Srwatson msqkptr->u.msg_lrpid = 0; 647137613Srwatson msqkptr->u.msg_stime = 0; 648137613Srwatson msqkptr->u.msg_rtime = 0; 649137613Srwatson msqkptr->u.msg_ctime = time_second; 650140614Srwatson#ifdef MAC 651172930Srwatson mac_sysvmsq_create(cred, msqkptr); 652140614Srwatson#endif 6532729Sdfr } else { 654100523Salfred DPRINTF(("didn't find it and wasn't asked to create it\n")); 65582607Sdillon error = ENOENT; 65682607Sdillon goto done2; 6572729Sdfr } 6582729Sdfr 6592729Sdfrfound: 6602729Sdfr /* Construct the unique msqid */ 661137613Srwatson td->td_retval[0] = IXSEQ_TO_IPCID(msqid, msqkptr->u.msg_perm); 66282607Sdillondone2: 663101772Salfred mtx_unlock(&msq_mtx); 66482607Sdillon return (error); 6652729Sdfr} 6662729Sdfr 66712866Speter#ifndef _SYS_SYSPROTO_H_ 6682729Sdfrstruct msgsnd_args { 6692729Sdfr int msqid; 670109895Salfred const void *msgp; 6712729Sdfr size_t msgsz; 6722729Sdfr int msgflg; 6732729Sdfr}; 67412866Speter#endif 67512866Speterint 676165403Sjkimkern_msgsnd(td, msqid, msgp, msgsz, msgflg, mtype) 67783366Sjulian struct thread *td; 678165403Sjkim int msqid; 679165403Sjkim const void *msgp; /* XXX msgp is actually mtext. */ 680165403Sjkim size_t msgsz; 681165403Sjkim int msgflg; 682165403Sjkim long mtype; 6832729Sdfr{ 684165403Sjkim int msqix, segs_needed, error = 0; 685137613Srwatson register struct msqid_kernel *msqkptr; 6862729Sdfr register struct msg *msghdr; 6872729Sdfr short next; 688220398Strasz size_t saved_msgsz; 6892729Sdfr 690192895Sjamie if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC)) 69191703Sjhb return (ENOSYS); 69291703Sjhb 693101772Salfred mtx_lock(&msq_mtx); 694165403Sjkim msqix = IPCID_TO_IX(msqid); 6952729Sdfr 696165403Sjkim if (msqix < 0 || msqix >= msginfo.msgmni) { 697165403Sjkim DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqix, 698100523Salfred msginfo.msgmni)); 69982607Sdillon error = EINVAL; 70082607Sdillon goto done2; 7012729Sdfr } 7022729Sdfr 703165403Sjkim msqkptr = &msqids[msqix]; 704137613Srwatson if (msqkptr->u.msg_qbytes == 0) { 705100523Salfred DPRINTF(("no such message queue id\n")); 70682607Sdillon error = EINVAL; 70782607Sdillon goto done2; 7082729Sdfr } 709165403Sjkim if (msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) { 710100523Salfred DPRINTF(("wrong sequence number\n")); 71182607Sdillon error = EINVAL; 71282607Sdillon goto done2; 7132729Sdfr } 7142729Sdfr 715137613Srwatson if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_W))) { 716100523Salfred DPRINTF(("requester doesn't have write access\n")); 71782607Sdillon goto done2; 7182729Sdfr } 7192729Sdfr 720140614Srwatson#ifdef MAC 721172930Srwatson error = mac_sysvmsq_check_msqsnd(td->td_ucred, msqkptr); 722162468Srwatson if (error != 0) 723140614Srwatson goto done2; 724140614Srwatson#endif 725140614Srwatson 726220398Strasz PROC_LOCK(td->td_proc); 727220398Strasz if (racct_add(td->td_proc, RACCT_MSGQQUEUED, 1)) { 728220398Strasz PROC_UNLOCK(td->td_proc); 729220398Strasz error = EAGAIN; 730220398Strasz goto done2; 731220398Strasz } 732220398Strasz saved_msgsz = msgsz; 733220398Strasz if (racct_add(td->td_proc, RACCT_MSGQSIZE, msgsz)) { 734220398Strasz racct_sub(td->td_proc, RACCT_MSGQQUEUED, 1); 735220398Strasz PROC_UNLOCK(td->td_proc); 736220398Strasz error = EAGAIN; 737220398Strasz goto done2; 738220398Strasz } 739220398Strasz PROC_UNLOCK(td->td_proc); 740220398Strasz 7412729Sdfr segs_needed = (msgsz + msginfo.msgssz - 1) / msginfo.msgssz; 742165403Sjkim DPRINTF(("msgsz=%zu, msgssz=%d, segs_needed=%d\n", msgsz, 743165403Sjkim msginfo.msgssz, segs_needed)); 7442729Sdfr for (;;) { 7452729Sdfr int need_more_resources = 0; 7462729Sdfr 7472729Sdfr /* 7482729Sdfr * check msgsz 7492729Sdfr * (inside this loop in case msg_qbytes changes while we sleep) 7502729Sdfr */ 7512729Sdfr 752137613Srwatson if (msgsz > msqkptr->u.msg_qbytes) { 753137613Srwatson DPRINTF(("msgsz > msqkptr->u.msg_qbytes\n")); 75482607Sdillon error = EINVAL; 755220398Strasz goto done3; 7562729Sdfr } 7572729Sdfr 758137613Srwatson if (msqkptr->u.msg_perm.mode & MSG_LOCKED) { 759100523Salfred DPRINTF(("msqid is locked\n")); 7602729Sdfr need_more_resources = 1; 7612729Sdfr } 762137613Srwatson if (msgsz + msqkptr->u.msg_cbytes > msqkptr->u.msg_qbytes) { 763100523Salfred DPRINTF(("msgsz + msg_cbytes > msg_qbytes\n")); 7642729Sdfr need_more_resources = 1; 7652729Sdfr } 7662729Sdfr if (segs_needed > nfree_msgmaps) { 767100523Salfred DPRINTF(("segs_needed > nfree_msgmaps\n")); 7682729Sdfr need_more_resources = 1; 7692729Sdfr } 7702729Sdfr if (free_msghdrs == NULL) { 771100523Salfred DPRINTF(("no more msghdrs\n")); 7722729Sdfr need_more_resources = 1; 7732729Sdfr } 7742729Sdfr 7752729Sdfr if (need_more_resources) { 7762729Sdfr int we_own_it; 7772729Sdfr 7782729Sdfr if ((msgflg & IPC_NOWAIT) != 0) { 779100523Salfred DPRINTF(("need more resources but caller " 780100523Salfred "doesn't want to wait\n")); 78182607Sdillon error = EAGAIN; 782220398Strasz goto done3; 7832729Sdfr } 7842729Sdfr 785137613Srwatson if ((msqkptr->u.msg_perm.mode & MSG_LOCKED) != 0) { 786100523Salfred DPRINTF(("we don't own the msqid_ds\n")); 7872729Sdfr we_own_it = 0; 7882729Sdfr } else { 7892729Sdfr /* Force later arrivals to wait for our 7902729Sdfr request */ 791100523Salfred DPRINTF(("we own the msqid_ds\n")); 792137613Srwatson msqkptr->u.msg_perm.mode |= MSG_LOCKED; 7932729Sdfr we_own_it = 1; 7942729Sdfr } 795164368Sjkim DPRINTF(("msgsnd: goodnight\n")); 796137613Srwatson error = msleep(msqkptr, &msq_mtx, (PZERO - 4) | PCATCH, 797164368Sjkim "msgsnd", hz); 798164368Sjkim DPRINTF(("msgsnd: good morning, error=%d\n", error)); 7992729Sdfr if (we_own_it) 800137613Srwatson msqkptr->u.msg_perm.mode &= ~MSG_LOCKED; 801164368Sjkim if (error == EWOULDBLOCK) { 802164368Sjkim DPRINTF(("msgsnd: timed out\n")); 803164368Sjkim continue; 804164368Sjkim } 80582607Sdillon if (error != 0) { 806100523Salfred DPRINTF(("msgsnd: interrupted system call\n")); 80782607Sdillon error = EINTR; 808220398Strasz goto done3; 8092729Sdfr } 8102729Sdfr 8112729Sdfr /* 8122729Sdfr * Make sure that the msq queue still exists 8132729Sdfr */ 8142729Sdfr 815137613Srwatson if (msqkptr->u.msg_qbytes == 0) { 816100523Salfred DPRINTF(("msqid deleted\n")); 81782607Sdillon error = EIDRM; 818220398Strasz goto done3; 8192729Sdfr } 8202729Sdfr 8212729Sdfr } else { 822100523Salfred DPRINTF(("got all the resources that we need\n")); 8232729Sdfr break; 8242729Sdfr } 8252729Sdfr } 8262729Sdfr 8272729Sdfr /* 8282729Sdfr * We have the resources that we need. 8292729Sdfr * Make sure! 8302729Sdfr */ 8312729Sdfr 832137613Srwatson if (msqkptr->u.msg_perm.mode & MSG_LOCKED) 8332729Sdfr panic("msg_perm.mode & MSG_LOCKED"); 8342729Sdfr if (segs_needed > nfree_msgmaps) 8352729Sdfr panic("segs_needed > nfree_msgmaps"); 836137613Srwatson if (msgsz + msqkptr->u.msg_cbytes > msqkptr->u.msg_qbytes) 8372729Sdfr panic("msgsz + msg_cbytes > msg_qbytes"); 8382729Sdfr if (free_msghdrs == NULL) 8392729Sdfr panic("no more msghdrs"); 8402729Sdfr 8412729Sdfr /* 8422729Sdfr * Re-lock the msqid_ds in case we page-fault when copying in the 8432729Sdfr * message 8442729Sdfr */ 8452729Sdfr 846137613Srwatson if ((msqkptr->u.msg_perm.mode & MSG_LOCKED) != 0) 8472729Sdfr panic("msqid_ds is already locked"); 848137613Srwatson msqkptr->u.msg_perm.mode |= MSG_LOCKED; 8492729Sdfr 8502729Sdfr /* 8512729Sdfr * Allocate a message header 8522729Sdfr */ 8532729Sdfr 8542729Sdfr msghdr = free_msghdrs; 8552729Sdfr free_msghdrs = msghdr->msg_next; 8562729Sdfr msghdr->msg_spot = -1; 8572729Sdfr msghdr->msg_ts = msgsz; 858165403Sjkim msghdr->msg_type = mtype; 859140614Srwatson#ifdef MAC 860140614Srwatson /* 861172930Srwatson * XXXMAC: Should the mac_sysvmsq_check_msgmsq check follow here 862140614Srwatson * immediately? Or, should it be checked just before the msg is 863140614Srwatson * enqueued in the msgq (as it is done now)? 864140614Srwatson */ 865172930Srwatson mac_sysvmsg_create(td->td_ucred, msqkptr, msghdr); 866140614Srwatson#endif 8672729Sdfr 8682729Sdfr /* 8692729Sdfr * Allocate space for the message 8702729Sdfr */ 8712729Sdfr 8722729Sdfr while (segs_needed > 0) { 8732729Sdfr if (nfree_msgmaps <= 0) 8742729Sdfr panic("not enough msgmaps"); 8752729Sdfr if (free_msgmaps == -1) 8762729Sdfr panic("nil free_msgmaps"); 8772729Sdfr next = free_msgmaps; 8782729Sdfr if (next <= -1) 8792729Sdfr panic("next too low #1"); 8802729Sdfr if (next >= msginfo.msgseg) 8812729Sdfr panic("next out of range #1"); 882100523Salfred DPRINTF(("allocating segment %d to message\n", next)); 8832729Sdfr free_msgmaps = msgmaps[next].next; 8842729Sdfr nfree_msgmaps--; 8852729Sdfr msgmaps[next].next = msghdr->msg_spot; 8862729Sdfr msghdr->msg_spot = next; 8872729Sdfr segs_needed--; 8882729Sdfr } 8892729Sdfr 8902729Sdfr /* 8912729Sdfr * Validate the message type 8922729Sdfr */ 8932729Sdfr 8942729Sdfr if (msghdr->msg_type < 1) { 8952729Sdfr msg_freehdr(msghdr); 896137613Srwatson msqkptr->u.msg_perm.mode &= ~MSG_LOCKED; 897137613Srwatson wakeup(msqkptr); 898165403Sjkim DPRINTF(("mtype (%ld) < 1\n", msghdr->msg_type)); 89982607Sdillon error = EINVAL; 900220398Strasz goto done3; 9012729Sdfr } 9022729Sdfr 9032729Sdfr /* 9042729Sdfr * Copy in the message body 9052729Sdfr */ 9062729Sdfr 9072729Sdfr next = msghdr->msg_spot; 9082729Sdfr while (msgsz > 0) { 9092729Sdfr size_t tlen; 9102729Sdfr if (msgsz > msginfo.msgssz) 9112729Sdfr tlen = msginfo.msgssz; 9122729Sdfr else 9132729Sdfr tlen = msgsz; 9142729Sdfr if (next <= -1) 9152729Sdfr panic("next too low #2"); 9162729Sdfr if (next >= msginfo.msgseg) 9172729Sdfr panic("next out of range #2"); 918101772Salfred mtx_unlock(&msq_mtx); 919165403Sjkim if ((error = copyin(msgp, &msgpool[next * msginfo.msgssz], 9202729Sdfr tlen)) != 0) { 921101772Salfred mtx_lock(&msq_mtx); 922100523Salfred DPRINTF(("error %d copying in message segment\n", 923100523Salfred error)); 9242729Sdfr msg_freehdr(msghdr); 925137613Srwatson msqkptr->u.msg_perm.mode &= ~MSG_LOCKED; 926137613Srwatson wakeup(msqkptr); 927220398Strasz goto done3; 9282729Sdfr } 929101772Salfred mtx_lock(&msq_mtx); 9302729Sdfr msgsz -= tlen; 931165403Sjkim msgp = (const char *)msgp + tlen; 9322729Sdfr next = msgmaps[next].next; 9332729Sdfr } 9342729Sdfr if (next != -1) 9352729Sdfr panic("didn't use all the msg segments"); 9362729Sdfr 9372729Sdfr /* 9382729Sdfr * We've got the message. Unlock the msqid_ds. 9392729Sdfr */ 9402729Sdfr 941137613Srwatson msqkptr->u.msg_perm.mode &= ~MSG_LOCKED; 9422729Sdfr 9432729Sdfr /* 9442729Sdfr * Make sure that the msqid_ds is still allocated. 9452729Sdfr */ 9462729Sdfr 947137613Srwatson if (msqkptr->u.msg_qbytes == 0) { 9482729Sdfr msg_freehdr(msghdr); 949137613Srwatson wakeup(msqkptr); 95082607Sdillon error = EIDRM; 951220398Strasz goto done3; 9522729Sdfr } 9532729Sdfr 954140614Srwatson#ifdef MAC 9552729Sdfr /* 956140614Srwatson * Note: Since the task/thread allocates the msghdr and usually 957140614Srwatson * primes it with its own MAC label, for a majority of policies, it 958140614Srwatson * won't be necessary to check whether the msghdr has access 959172930Srwatson * permissions to the msgq. The mac_sysvmsq_check_msqsnd check would 960140614Srwatson * suffice in that case. However, this hook may be required where 961140614Srwatson * individual policies derive a non-identical label for the msghdr 962140614Srwatson * from the current thread label and may want to check the msghdr 963140614Srwatson * enqueue permissions, along with read/write permissions to the 964140614Srwatson * msgq. 965140614Srwatson */ 966172930Srwatson error = mac_sysvmsq_check_msgmsq(td->td_ucred, msghdr, msqkptr); 967140614Srwatson if (error != 0) { 968140614Srwatson msg_freehdr(msghdr); 969140614Srwatson wakeup(msqkptr); 970220398Strasz goto done3; 971140614Srwatson } 972140614Srwatson#endif 973140614Srwatson 974140614Srwatson /* 9752729Sdfr * Put the message into the queue 9762729Sdfr */ 977137613Srwatson if (msqkptr->u.msg_first == NULL) { 978137613Srwatson msqkptr->u.msg_first = msghdr; 979137613Srwatson msqkptr->u.msg_last = msghdr; 9802729Sdfr } else { 981137613Srwatson msqkptr->u.msg_last->msg_next = msghdr; 982137613Srwatson msqkptr->u.msg_last = msghdr; 9832729Sdfr } 984137613Srwatson msqkptr->u.msg_last->msg_next = NULL; 9852729Sdfr 986137613Srwatson msqkptr->u.msg_cbytes += msghdr->msg_ts; 987137613Srwatson msqkptr->u.msg_qnum++; 988137613Srwatson msqkptr->u.msg_lspid = td->td_proc->p_pid; 989137613Srwatson msqkptr->u.msg_stime = time_second; 9902729Sdfr 991137613Srwatson wakeup(msqkptr); 99283366Sjulian td->td_retval[0] = 0; 993220398Straszdone3: 994220398Strasz if (error != 0) { 995220398Strasz PROC_LOCK(td->td_proc); 996220398Strasz racct_sub(td->td_proc, RACCT_MSGQQUEUED, 1); 997220398Strasz racct_sub(td->td_proc, RACCT_MSGQSIZE, saved_msgsz); 998220398Strasz PROC_UNLOCK(td->td_proc); 999220398Strasz } 100082607Sdillondone2: 1001101772Salfred mtx_unlock(&msq_mtx); 100282607Sdillon return (error); 10032729Sdfr} 10042729Sdfr 1005165403Sjkimint 1006165403Sjkimmsgsnd(td, uap) 1007165403Sjkim struct thread *td; 1008165403Sjkim register struct msgsnd_args *uap; 1009165403Sjkim{ 1010165403Sjkim int error; 1011165403Sjkim long mtype; 1012165403Sjkim 1013165403Sjkim DPRINTF(("call to msgsnd(%d, %p, %zu, %d)\n", uap->msqid, uap->msgp, 1014165403Sjkim uap->msgsz, uap->msgflg)); 1015165403Sjkim 1016165403Sjkim if ((error = copyin(uap->msgp, &mtype, sizeof(mtype))) != 0) { 1017165403Sjkim DPRINTF(("error %d copying the message type\n", error)); 1018165403Sjkim return (error); 1019165403Sjkim } 1020165403Sjkim return (kern_msgsnd(td, uap->msqid, 1021165403Sjkim (const char *)uap->msgp + sizeof(mtype), 1022165403Sjkim uap->msgsz, uap->msgflg, mtype)); 1023165403Sjkim} 1024165403Sjkim 102512866Speter#ifndef _SYS_SYSPROTO_H_ 10262729Sdfrstruct msgrcv_args { 10272729Sdfr int msqid; 10282729Sdfr void *msgp; 10292729Sdfr size_t msgsz; 10302729Sdfr long msgtyp; 10312729Sdfr int msgflg; 10322729Sdfr}; 103312866Speter#endif 103412866Speterint 1035165403Sjkimkern_msgrcv(td, msqid, msgp, msgsz, msgtyp, msgflg, mtype) 103683366Sjulian struct thread *td; 1037165403Sjkim int msqid; 1038165403Sjkim void *msgp; /* XXX msgp is actually mtext. */ 1039165403Sjkim size_t msgsz; 1040165403Sjkim long msgtyp; 1041165403Sjkim int msgflg; 1042165403Sjkim long *mtype; 10432729Sdfr{ 10442729Sdfr size_t len; 1045137613Srwatson register struct msqid_kernel *msqkptr; 10462729Sdfr register struct msg *msghdr; 1047165403Sjkim int msqix, error = 0; 10482729Sdfr short next; 10492729Sdfr 1050192895Sjamie if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC)) 105191703Sjhb return (ENOSYS); 105291703Sjhb 1053165403Sjkim msqix = IPCID_TO_IX(msqid); 10542729Sdfr 1055165403Sjkim if (msqix < 0 || msqix >= msginfo.msgmni) { 1056165403Sjkim DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqix, 1057100523Salfred msginfo.msgmni)); 1058101772Salfred return (EINVAL); 10592729Sdfr } 10602729Sdfr 1061165403Sjkim msqkptr = &msqids[msqix]; 1062101772Salfred mtx_lock(&msq_mtx); 1063137613Srwatson if (msqkptr->u.msg_qbytes == 0) { 1064100523Salfred DPRINTF(("no such message queue id\n")); 106582607Sdillon error = EINVAL; 106682607Sdillon goto done2; 10672729Sdfr } 1068165403Sjkim if (msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) { 1069100523Salfred DPRINTF(("wrong sequence number\n")); 107082607Sdillon error = EINVAL; 107182607Sdillon goto done2; 10722729Sdfr } 10732729Sdfr 1074137613Srwatson if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_R))) { 1075100523Salfred DPRINTF(("requester doesn't have read access\n")); 107682607Sdillon goto done2; 10772729Sdfr } 10782729Sdfr 1079140614Srwatson#ifdef MAC 1080172930Srwatson error = mac_sysvmsq_check_msqrcv(td->td_ucred, msqkptr); 1081162468Srwatson if (error != 0) 1082140614Srwatson goto done2; 1083140614Srwatson#endif 1084140614Srwatson 10852729Sdfr msghdr = NULL; 10862729Sdfr while (msghdr == NULL) { 10872729Sdfr if (msgtyp == 0) { 1088137613Srwatson msghdr = msqkptr->u.msg_first; 10892729Sdfr if (msghdr != NULL) { 10902729Sdfr if (msgsz < msghdr->msg_ts && 10912729Sdfr (msgflg & MSG_NOERROR) == 0) { 1092100523Salfred DPRINTF(("first message on the queue " 1093165403Sjkim "is too big (want %zu, got %d)\n", 1094100523Salfred msgsz, msghdr->msg_ts)); 109582607Sdillon error = E2BIG; 109682607Sdillon goto done2; 10972729Sdfr } 1098140614Srwatson#ifdef MAC 1099172930Srwatson error = mac_sysvmsq_check_msgrcv(td->td_ucred, 1100140614Srwatson msghdr); 1101162468Srwatson if (error != 0) 1102140614Srwatson goto done2; 1103140614Srwatson#endif 1104137613Srwatson if (msqkptr->u.msg_first == msqkptr->u.msg_last) { 1105137613Srwatson msqkptr->u.msg_first = NULL; 1106137613Srwatson msqkptr->u.msg_last = NULL; 11072729Sdfr } else { 1108137613Srwatson msqkptr->u.msg_first = msghdr->msg_next; 1109137613Srwatson if (msqkptr->u.msg_first == NULL) 11102729Sdfr panic("msg_first/last screwed up #1"); 11112729Sdfr } 11122729Sdfr } 11132729Sdfr } else { 11142729Sdfr struct msg *previous; 11152729Sdfr struct msg **prev; 11162729Sdfr 11172729Sdfr previous = NULL; 1118137613Srwatson prev = &(msqkptr->u.msg_first); 11192729Sdfr while ((msghdr = *prev) != NULL) { 11202729Sdfr /* 11212729Sdfr * Is this message's type an exact match or is 11222729Sdfr * this message's type less than or equal to 11232729Sdfr * the absolute value of a negative msgtyp? 11242729Sdfr * Note that the second half of this test can 11252729Sdfr * NEVER be true if msgtyp is positive since 11262729Sdfr * msg_type is always positive! 11272729Sdfr */ 11282729Sdfr 11292729Sdfr if (msgtyp == msghdr->msg_type || 11302729Sdfr msghdr->msg_type <= -msgtyp) { 1131165403Sjkim DPRINTF(("found message type %ld, " 1132165403Sjkim "requested %ld\n", 1133100523Salfred msghdr->msg_type, msgtyp)); 11342729Sdfr if (msgsz < msghdr->msg_ts && 11352729Sdfr (msgflg & MSG_NOERROR) == 0) { 1136100523Salfred DPRINTF(("requested message " 1137100523Salfred "on the queue is too big " 1138165403Sjkim "(want %zu, got %hu)\n", 1139100523Salfred msgsz, msghdr->msg_ts)); 114082607Sdillon error = E2BIG; 114182607Sdillon goto done2; 11422729Sdfr } 1143140614Srwatson#ifdef MAC 1144172930Srwatson error = mac_sysvmsq_check_msgrcv( 1145140614Srwatson td->td_ucred, msghdr); 1146162468Srwatson if (error != 0) 1147140614Srwatson goto done2; 1148140614Srwatson#endif 11492729Sdfr *prev = msghdr->msg_next; 1150137613Srwatson if (msghdr == msqkptr->u.msg_last) { 11512729Sdfr if (previous == NULL) { 11522729Sdfr if (prev != 1153137613Srwatson &msqkptr->u.msg_first) 11542729Sdfr panic("msg_first/last screwed up #2"); 1155137613Srwatson msqkptr->u.msg_first = 11562729Sdfr NULL; 1157137613Srwatson msqkptr->u.msg_last = 11582729Sdfr NULL; 11592729Sdfr } else { 11602729Sdfr if (prev == 1161137613Srwatson &msqkptr->u.msg_first) 11622729Sdfr panic("msg_first/last screwed up #3"); 1163137613Srwatson msqkptr->u.msg_last = 11642729Sdfr previous; 11652729Sdfr } 11662729Sdfr } 11672729Sdfr break; 11682729Sdfr } 11692729Sdfr previous = msghdr; 11702729Sdfr prev = &(msghdr->msg_next); 11712729Sdfr } 11722729Sdfr } 11732729Sdfr 11742729Sdfr /* 11752729Sdfr * We've either extracted the msghdr for the appropriate 11762729Sdfr * message or there isn't one. 11772729Sdfr * If there is one then bail out of this loop. 11782729Sdfr */ 11792729Sdfr 11802729Sdfr if (msghdr != NULL) 11812729Sdfr break; 11822729Sdfr 11832729Sdfr /* 11842729Sdfr * Hmph! No message found. Does the user want to wait? 11852729Sdfr */ 11862729Sdfr 11872729Sdfr if ((msgflg & IPC_NOWAIT) != 0) { 1188165403Sjkim DPRINTF(("no appropriate message found (msgtyp=%ld)\n", 1189100523Salfred msgtyp)); 11902729Sdfr /* The SVID says to return ENOMSG. */ 119182607Sdillon error = ENOMSG; 119282607Sdillon goto done2; 11932729Sdfr } 11942729Sdfr 11952729Sdfr /* 11962729Sdfr * Wait for something to happen 11972729Sdfr */ 11982729Sdfr 1199100523Salfred DPRINTF(("msgrcv: goodnight\n")); 1200137613Srwatson error = msleep(msqkptr, &msq_mtx, (PZERO - 4) | PCATCH, 1201164368Sjkim "msgrcv", 0); 1202100523Salfred DPRINTF(("msgrcv: good morning (error=%d)\n", error)); 12032729Sdfr 120482607Sdillon if (error != 0) { 1205164368Sjkim DPRINTF(("msgrcv: interrupted system call\n")); 120682607Sdillon error = EINTR; 120782607Sdillon goto done2; 12082729Sdfr } 12092729Sdfr 12102729Sdfr /* 12112729Sdfr * Make sure that the msq queue still exists 12122729Sdfr */ 12132729Sdfr 1214137613Srwatson if (msqkptr->u.msg_qbytes == 0 || 1215165403Sjkim msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) { 1216100523Salfred DPRINTF(("msqid deleted\n")); 121782607Sdillon error = EIDRM; 121882607Sdillon goto done2; 12192729Sdfr } 12202729Sdfr } 12212729Sdfr 12222729Sdfr /* 12232729Sdfr * Return the message to the user. 12242729Sdfr * 12252729Sdfr * First, do the bookkeeping (before we risk being interrupted). 12262729Sdfr */ 12272729Sdfr 1228137613Srwatson msqkptr->u.msg_cbytes -= msghdr->msg_ts; 1229137613Srwatson msqkptr->u.msg_qnum--; 1230137613Srwatson msqkptr->u.msg_lrpid = td->td_proc->p_pid; 1231137613Srwatson msqkptr->u.msg_rtime = time_second; 12322729Sdfr 1233220398Strasz racct_sub_cred(msqkptr->cred, RACCT_MSGQQUEUED, 1); 1234220398Strasz racct_sub_cred(msqkptr->cred, RACCT_MSGQSIZE, msghdr->msg_ts); 1235220398Strasz 12362729Sdfr /* 12372729Sdfr * Make msgsz the actual amount that we'll be returning. 12382729Sdfr * Note that this effectively truncates the message if it is too long 12392729Sdfr * (since msgsz is never increased). 12402729Sdfr */ 12412729Sdfr 1242165403Sjkim DPRINTF(("found a message, msgsz=%zu, msg_ts=%hu\n", msgsz, 1243100523Salfred msghdr->msg_ts)); 12442729Sdfr if (msgsz > msghdr->msg_ts) 12452729Sdfr msgsz = msghdr->msg_ts; 1246165403Sjkim *mtype = msghdr->msg_type; 12472729Sdfr 12482729Sdfr /* 12492729Sdfr * Return the segments to the user 12502729Sdfr */ 12512729Sdfr 12522729Sdfr next = msghdr->msg_spot; 12532729Sdfr for (len = 0; len < msgsz; len += msginfo.msgssz) { 12542729Sdfr size_t tlen; 12552729Sdfr 125645921Ssada if (msgsz - len > msginfo.msgssz) 12572729Sdfr tlen = msginfo.msgssz; 12582729Sdfr else 125945921Ssada tlen = msgsz - len; 12602729Sdfr if (next <= -1) 12612729Sdfr panic("next too low #3"); 12622729Sdfr if (next >= msginfo.msgseg) 12632729Sdfr panic("next out of range #3"); 1264101772Salfred mtx_unlock(&msq_mtx); 1265165403Sjkim error = copyout(&msgpool[next * msginfo.msgssz], msgp, tlen); 1266101772Salfred mtx_lock(&msq_mtx); 126782607Sdillon if (error != 0) { 1268100523Salfred DPRINTF(("error (%d) copying out message segment\n", 1269100523Salfred error)); 12702729Sdfr msg_freehdr(msghdr); 1271137613Srwatson wakeup(msqkptr); 127282607Sdillon goto done2; 12732729Sdfr } 1274165403Sjkim msgp = (char *)msgp + tlen; 12752729Sdfr next = msgmaps[next].next; 12762729Sdfr } 12772729Sdfr 12782729Sdfr /* 12792729Sdfr * Done, return the actual number of bytes copied out. 12802729Sdfr */ 12812729Sdfr 12822729Sdfr msg_freehdr(msghdr); 1283137613Srwatson wakeup(msqkptr); 128483366Sjulian td->td_retval[0] = msgsz; 128582607Sdillondone2: 1286101772Salfred mtx_unlock(&msq_mtx); 128782607Sdillon return (error); 12882729Sdfr} 128977461Sdd 1290165403Sjkimint 1291165403Sjkimmsgrcv(td, uap) 1292165403Sjkim struct thread *td; 1293165403Sjkim register struct msgrcv_args *uap; 1294165403Sjkim{ 1295165403Sjkim int error; 1296165403Sjkim long mtype; 1297165403Sjkim 1298165403Sjkim DPRINTF(("call to msgrcv(%d, %p, %zu, %ld, %d)\n", uap->msqid, 1299165403Sjkim uap->msgp, uap->msgsz, uap->msgtyp, uap->msgflg)); 1300165403Sjkim 1301165403Sjkim if ((error = kern_msgrcv(td, uap->msqid, 1302165403Sjkim (char *)uap->msgp + sizeof(mtype), uap->msgsz, 1303165403Sjkim uap->msgtyp, uap->msgflg, &mtype)) != 0) 1304165403Sjkim return (error); 1305165403Sjkim if ((error = copyout(&mtype, uap->msgp, sizeof(mtype))) != 0) 1306165403Sjkim DPRINTF(("error %d copying the message type\n", error)); 1307165403Sjkim return (error); 1308165403Sjkim} 1309165403Sjkim 131077461Sddstatic int 131177461Sddsysctl_msqids(SYSCTL_HANDLER_ARGS) 131277461Sdd{ 131377461Sdd 131477461Sdd return (SYSCTL_OUT(req, msqids, 1315137613Srwatson sizeof(struct msqid_kernel) * msginfo.msgmni)); 131677461Sdd} 131777461Sdd 1318141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgmax, CTLFLAG_RD, &msginfo.msgmax, 0, 1319141710Scsjp "Maximum message size"); 1320141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgmni, CTLFLAG_RDTUN, &msginfo.msgmni, 0, 1321141710Scsjp "Number of message queue identifiers"); 1322141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgmnb, CTLFLAG_RDTUN, &msginfo.msgmnb, 0, 1323141710Scsjp "Maximum number of bytes in a queue"); 1324141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgtql, CTLFLAG_RDTUN, &msginfo.msgtql, 0, 1325141710Scsjp "Maximum number of messages in the system"); 1326141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgssz, CTLFLAG_RDTUN, &msginfo.msgssz, 0, 1327141710Scsjp "Size of a message segment"); 1328141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgseg, CTLFLAG_RDTUN, &msginfo.msgseg, 0, 1329141710Scsjp "Number of message segments"); 1330217555SmdfSYSCTL_PROC(_kern_ipc, OID_AUTO, msqids, CTLTYPE_OPAQUE | CTLFLAG_RD, 133177461Sdd NULL, 0, sysctl_msqids, "", "Message queue IDs"); 1332194894Sjhb 1333205323Skib#ifdef COMPAT_FREEBSD32 1334205323Skibint 1335205323Skibfreebsd32_msgsys(struct thread *td, struct freebsd32_msgsys_args *uap) 1336205323Skib{ 1337205323Skib 1338194894Sjhb#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1339194894Sjhb defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1340205323Skib switch (uap->which) { 1341205323Skib case 0: 1342205323Skib return (freebsd7_freebsd32_msgctl(td, 1343205323Skib (struct freebsd7_freebsd32_msgctl_args *)&uap->a2)); 1344205323Skib case 2: 1345205323Skib return (freebsd32_msgsnd(td, 1346205323Skib (struct freebsd32_msgsnd_args *)&uap->a2)); 1347205323Skib case 3: 1348205323Skib return (freebsd32_msgrcv(td, 1349205323Skib (struct freebsd32_msgrcv_args *)&uap->a2)); 1350205323Skib default: 1351205323Skib return (msgsys(td, (struct msgsys_args *)uap)); 1352205323Skib } 1353205323Skib#else 1354205323Skib return (nosys(td, NULL)); 1355205323Skib#endif 1356205323Skib} 1357194894Sjhb 1358205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1359205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1360205323Skibint 1361205323Skibfreebsd7_freebsd32_msgctl(struct thread *td, 1362205323Skib struct freebsd7_freebsd32_msgctl_args *uap) 1363205323Skib{ 1364205323Skib struct msqid_ds msqbuf; 1365205323Skib struct msqid_ds32_old msqbuf32; 1366205323Skib int error; 1367205323Skib 1368205323Skib if (uap->cmd == IPC_SET) { 1369205323Skib error = copyin(uap->buf, &msqbuf32, sizeof(msqbuf32)); 1370205323Skib if (error) 1371205323Skib return (error); 1372205323Skib freebsd32_ipcperm_old_in(&msqbuf32.msg_perm, &msqbuf.msg_perm); 1373205323Skib PTRIN_CP(msqbuf32, msqbuf, msg_first); 1374205323Skib PTRIN_CP(msqbuf32, msqbuf, msg_last); 1375205323Skib CP(msqbuf32, msqbuf, msg_cbytes); 1376205323Skib CP(msqbuf32, msqbuf, msg_qnum); 1377205323Skib CP(msqbuf32, msqbuf, msg_qbytes); 1378205323Skib CP(msqbuf32, msqbuf, msg_lspid); 1379205323Skib CP(msqbuf32, msqbuf, msg_lrpid); 1380205323Skib CP(msqbuf32, msqbuf, msg_stime); 1381205323Skib CP(msqbuf32, msqbuf, msg_rtime); 1382205323Skib CP(msqbuf32, msqbuf, msg_ctime); 1383205323Skib } 1384205323Skib error = kern_msgctl(td, uap->msqid, uap->cmd, &msqbuf); 1385205323Skib if (error) 1386205323Skib return (error); 1387205323Skib if (uap->cmd == IPC_STAT) { 1388205323Skib bzero(&msqbuf32, sizeof(msqbuf32)); 1389205323Skib freebsd32_ipcperm_old_out(&msqbuf.msg_perm, &msqbuf32.msg_perm); 1390205323Skib PTROUT_CP(msqbuf, msqbuf32, msg_first); 1391205323Skib PTROUT_CP(msqbuf, msqbuf32, msg_last); 1392205323Skib CP(msqbuf, msqbuf32, msg_cbytes); 1393205323Skib CP(msqbuf, msqbuf32, msg_qnum); 1394205323Skib CP(msqbuf, msqbuf32, msg_qbytes); 1395205323Skib CP(msqbuf, msqbuf32, msg_lspid); 1396205323Skib CP(msqbuf, msqbuf32, msg_lrpid); 1397205323Skib CP(msqbuf, msqbuf32, msg_stime); 1398205323Skib CP(msqbuf, msqbuf32, msg_rtime); 1399205323Skib CP(msqbuf, msqbuf32, msg_ctime); 1400205323Skib error = copyout(&msqbuf32, uap->buf, sizeof(struct msqid_ds32)); 1401205323Skib } 1402205323Skib return (error); 1403205323Skib} 1404205323Skib#endif 1405205323Skib 1406205323Skibint 1407205323Skibfreebsd32_msgctl(struct thread *td, struct freebsd32_msgctl_args *uap) 1408205323Skib{ 1409205323Skib struct msqid_ds msqbuf; 1410205323Skib struct msqid_ds32 msqbuf32; 1411205323Skib int error; 1412205323Skib 1413205323Skib if (uap->cmd == IPC_SET) { 1414205323Skib error = copyin(uap->buf, &msqbuf32, sizeof(msqbuf32)); 1415205323Skib if (error) 1416205323Skib return (error); 1417205323Skib freebsd32_ipcperm_in(&msqbuf32.msg_perm, &msqbuf.msg_perm); 1418205323Skib PTRIN_CP(msqbuf32, msqbuf, msg_first); 1419205323Skib PTRIN_CP(msqbuf32, msqbuf, msg_last); 1420205323Skib CP(msqbuf32, msqbuf, msg_cbytes); 1421205323Skib CP(msqbuf32, msqbuf, msg_qnum); 1422205323Skib CP(msqbuf32, msqbuf, msg_qbytes); 1423205323Skib CP(msqbuf32, msqbuf, msg_lspid); 1424205323Skib CP(msqbuf32, msqbuf, msg_lrpid); 1425205323Skib CP(msqbuf32, msqbuf, msg_stime); 1426205323Skib CP(msqbuf32, msqbuf, msg_rtime); 1427205323Skib CP(msqbuf32, msqbuf, msg_ctime); 1428205323Skib } 1429205323Skib error = kern_msgctl(td, uap->msqid, uap->cmd, &msqbuf); 1430205323Skib if (error) 1431205323Skib return (error); 1432205323Skib if (uap->cmd == IPC_STAT) { 1433205323Skib freebsd32_ipcperm_out(&msqbuf.msg_perm, &msqbuf32.msg_perm); 1434205323Skib PTROUT_CP(msqbuf, msqbuf32, msg_first); 1435205323Skib PTROUT_CP(msqbuf, msqbuf32, msg_last); 1436205323Skib CP(msqbuf, msqbuf32, msg_cbytes); 1437205323Skib CP(msqbuf, msqbuf32, msg_qnum); 1438205323Skib CP(msqbuf, msqbuf32, msg_qbytes); 1439205323Skib CP(msqbuf, msqbuf32, msg_lspid); 1440205323Skib CP(msqbuf, msqbuf32, msg_lrpid); 1441205323Skib CP(msqbuf, msqbuf32, msg_stime); 1442205323Skib CP(msqbuf, msqbuf32, msg_rtime); 1443205323Skib CP(msqbuf, msqbuf32, msg_ctime); 1444205323Skib error = copyout(&msqbuf32, uap->buf, sizeof(struct msqid_ds32)); 1445205323Skib } 1446205323Skib return (error); 1447205323Skib} 1448205323Skib 1449205323Skibint 1450205323Skibfreebsd32_msgsnd(struct thread *td, struct freebsd32_msgsnd_args *uap) 1451205323Skib{ 1452205323Skib const void *msgp; 1453205323Skib long mtype; 1454205323Skib int32_t mtype32; 1455205323Skib int error; 1456205323Skib 1457205323Skib msgp = PTRIN(uap->msgp); 1458205323Skib if ((error = copyin(msgp, &mtype32, sizeof(mtype32))) != 0) 1459205323Skib return (error); 1460205323Skib mtype = mtype32; 1461205323Skib return (kern_msgsnd(td, uap->msqid, 1462205323Skib (const char *)msgp + sizeof(mtype32), 1463205323Skib uap->msgsz, uap->msgflg, mtype)); 1464205323Skib} 1465205323Skib 1466205323Skibint 1467205323Skibfreebsd32_msgrcv(struct thread *td, struct freebsd32_msgrcv_args *uap) 1468205323Skib{ 1469205323Skib void *msgp; 1470205323Skib long mtype; 1471205323Skib int32_t mtype32; 1472205323Skib int error; 1473205323Skib 1474205323Skib msgp = PTRIN(uap->msgp); 1475205323Skib if ((error = kern_msgrcv(td, uap->msqid, 1476205323Skib (char *)msgp + sizeof(mtype32), uap->msgsz, 1477205323Skib uap->msgtyp, uap->msgflg, &mtype)) != 0) 1478205323Skib return (error); 1479205323Skib mtype32 = (int32_t)mtype; 1480205323Skib return (copyout(&mtype32, msgp, sizeof(mtype32))); 1481205323Skib} 1482205323Skib#endif 1483205323Skib 1484205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1485205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1486205323Skib 1487194894Sjhb/* XXX casting to (sy_call_t *) is bogus, as usual. */ 1488194894Sjhbstatic sy_call_t *msgcalls[] = { 1489194910Sjhb (sy_call_t *)freebsd7_msgctl, (sy_call_t *)msgget, 1490194894Sjhb (sy_call_t *)msgsnd, (sy_call_t *)msgrcv 1491194894Sjhb}; 1492194894Sjhb 1493194894Sjhb/* 1494194894Sjhb * Entry point for all MSG calls. 1495194894Sjhb */ 1496194894Sjhbint 1497194894Sjhbmsgsys(td, uap) 1498194894Sjhb struct thread *td; 1499194894Sjhb /* XXX actually varargs. */ 1500194894Sjhb struct msgsys_args /* { 1501194894Sjhb int which; 1502194894Sjhb int a2; 1503194894Sjhb int a3; 1504194894Sjhb int a4; 1505194894Sjhb int a5; 1506194894Sjhb int a6; 1507194894Sjhb } */ *uap; 1508194894Sjhb{ 1509194894Sjhb int error; 1510194894Sjhb 1511194894Sjhb if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC)) 1512194894Sjhb return (ENOSYS); 1513194894Sjhb if (uap->which < 0 || 1514194894Sjhb uap->which >= sizeof(msgcalls)/sizeof(msgcalls[0])) 1515194894Sjhb return (EINVAL); 1516194894Sjhb error = (*msgcalls[uap->which])(td, &uap->a2); 1517194894Sjhb return (error); 1518194894Sjhb} 1519194910Sjhb 1520205323Skib#ifndef CP 1521194910Sjhb#define CP(src, dst, fld) do { (dst).fld = (src).fld; } while (0) 1522205323Skib#endif 1523194910Sjhb 1524194910Sjhb#ifndef _SYS_SYSPROTO_H_ 1525194910Sjhbstruct freebsd7_msgctl_args { 1526194910Sjhb int msqid; 1527194910Sjhb int cmd; 1528194910Sjhb struct msqid_ds_old *buf; 1529194910Sjhb}; 1530194910Sjhb#endif 1531194910Sjhbint 1532194910Sjhbfreebsd7_msgctl(td, uap) 1533194910Sjhb struct thread *td; 1534194910Sjhb struct freebsd7_msgctl_args *uap; 1535194910Sjhb{ 1536194910Sjhb struct msqid_ds_old msqold; 1537194910Sjhb struct msqid_ds msqbuf; 1538194910Sjhb int error; 1539194910Sjhb 1540194910Sjhb DPRINTF(("call to freebsd7_msgctl(%d, %d, %p)\n", uap->msqid, uap->cmd, 1541194910Sjhb uap->buf)); 1542194910Sjhb if (uap->cmd == IPC_SET) { 1543194910Sjhb error = copyin(uap->buf, &msqold, sizeof(msqold)); 1544194910Sjhb if (error) 1545194910Sjhb return (error); 1546194910Sjhb ipcperm_old2new(&msqold.msg_perm, &msqbuf.msg_perm); 1547194910Sjhb CP(msqold, msqbuf, msg_first); 1548194910Sjhb CP(msqold, msqbuf, msg_last); 1549194910Sjhb CP(msqold, msqbuf, msg_cbytes); 1550194910Sjhb CP(msqold, msqbuf, msg_qnum); 1551194910Sjhb CP(msqold, msqbuf, msg_qbytes); 1552194910Sjhb CP(msqold, msqbuf, msg_lspid); 1553194910Sjhb CP(msqold, msqbuf, msg_lrpid); 1554194910Sjhb CP(msqold, msqbuf, msg_stime); 1555194910Sjhb CP(msqold, msqbuf, msg_rtime); 1556194910Sjhb CP(msqold, msqbuf, msg_ctime); 1557194910Sjhb } 1558194910Sjhb error = kern_msgctl(td, uap->msqid, uap->cmd, &msqbuf); 1559194910Sjhb if (error) 1560194910Sjhb return (error); 1561194910Sjhb if (uap->cmd == IPC_STAT) { 1562194910Sjhb bzero(&msqold, sizeof(msqold)); 1563194910Sjhb ipcperm_new2old(&msqbuf.msg_perm, &msqold.msg_perm); 1564194910Sjhb CP(msqbuf, msqold, msg_first); 1565194910Sjhb CP(msqbuf, msqold, msg_last); 1566194910Sjhb CP(msqbuf, msqold, msg_cbytes); 1567194910Sjhb CP(msqbuf, msqold, msg_qnum); 1568194910Sjhb CP(msqbuf, msqold, msg_qbytes); 1569194910Sjhb CP(msqbuf, msqold, msg_lspid); 1570194910Sjhb CP(msqbuf, msqold, msg_lrpid); 1571194910Sjhb CP(msqbuf, msqold, msg_stime); 1572194910Sjhb CP(msqbuf, msqold, msg_rtime); 1573194910Sjhb CP(msqbuf, msqold, msg_ctime); 1574194910Sjhb error = copyout(&msqold, uap->buf, sizeof(struct msqid_ds_old)); 1575194910Sjhb } 1576194910Sjhb return (error); 1577194910Sjhb} 1578194910Sjhb 1579194910Sjhb#undef CP 1580194910Sjhb 1581194894Sjhb#endif /* COMPAT_FREEBSD4 || COMPAT_FREEBSD5 || COMPAT_FREEBSD6 || 1582194894Sjhb COMPAT_FREEBSD7 */ 1583