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