1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28*0Sstevel@tonic-gate /* All Rights Reserved */ 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate /* 34*0Sstevel@tonic-gate * Inter-Process Communication Message Facility. 35*0Sstevel@tonic-gate * 36*0Sstevel@tonic-gate * See os/ipc.c for a description of common IPC functionality. 37*0Sstevel@tonic-gate * 38*0Sstevel@tonic-gate * Resource controls 39*0Sstevel@tonic-gate * ----------------- 40*0Sstevel@tonic-gate * 41*0Sstevel@tonic-gate * Control: project.max-msg-ids (rc_project_msgmni) 42*0Sstevel@tonic-gate * Description: Maximum number of message queue ids allowed a project. 43*0Sstevel@tonic-gate * 44*0Sstevel@tonic-gate * When msgget() is used to allocate a message queue, one id is 45*0Sstevel@tonic-gate * allocated. If the id allocation doesn't succeed, msgget() fails 46*0Sstevel@tonic-gate * and errno is set to ENOSPC. Upon successful msgctl(, IPC_RMID) 47*0Sstevel@tonic-gate * the id is deallocated. 48*0Sstevel@tonic-gate * 49*0Sstevel@tonic-gate * Control: process.max-msg-qbytes (rc_process_msgmnb) 50*0Sstevel@tonic-gate * Description: Maximum number of bytes of messages on a message queue. 51*0Sstevel@tonic-gate * 52*0Sstevel@tonic-gate * When msgget() successfully allocates a message queue, the minimum 53*0Sstevel@tonic-gate * enforced value of this limit is used to initialize msg_qbytes. 54*0Sstevel@tonic-gate * 55*0Sstevel@tonic-gate * Control: process.max-msg-messages (rc_process_msgtql) 56*0Sstevel@tonic-gate * Description: Maximum number of messages on a message queue. 57*0Sstevel@tonic-gate * 58*0Sstevel@tonic-gate * When msgget() successfully allocates a message queue, the minimum 59*0Sstevel@tonic-gate * enforced value of this limit is used to initialize a per-queue 60*0Sstevel@tonic-gate * limit on the number of messages. 61*0Sstevel@tonic-gate */ 62*0Sstevel@tonic-gate 63*0Sstevel@tonic-gate #include <sys/types.h> 64*0Sstevel@tonic-gate #include <sys/t_lock.h> 65*0Sstevel@tonic-gate #include <sys/param.h> 66*0Sstevel@tonic-gate #include <sys/cred.h> 67*0Sstevel@tonic-gate #include <sys/user.h> 68*0Sstevel@tonic-gate #include <sys/proc.h> 69*0Sstevel@tonic-gate #include <sys/time.h> 70*0Sstevel@tonic-gate #include <sys/ipc.h> 71*0Sstevel@tonic-gate #include <sys/ipc_impl.h> 72*0Sstevel@tonic-gate #include <sys/msg.h> 73*0Sstevel@tonic-gate #include <sys/msg_impl.h> 74*0Sstevel@tonic-gate #include <sys/list.h> 75*0Sstevel@tonic-gate #include <sys/systm.h> 76*0Sstevel@tonic-gate #include <sys/sysmacros.h> 77*0Sstevel@tonic-gate #include <sys/cpuvar.h> 78*0Sstevel@tonic-gate #include <sys/kmem.h> 79*0Sstevel@tonic-gate #include <sys/ddi.h> 80*0Sstevel@tonic-gate #include <sys/errno.h> 81*0Sstevel@tonic-gate #include <sys/cmn_err.h> 82*0Sstevel@tonic-gate #include <sys/debug.h> 83*0Sstevel@tonic-gate #include <sys/project.h> 84*0Sstevel@tonic-gate #include <sys/modctl.h> 85*0Sstevel@tonic-gate #include <sys/syscall.h> 86*0Sstevel@tonic-gate #include <sys/policy.h> 87*0Sstevel@tonic-gate #include <sys/zone.h> 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate #include <c2/audit.h> 90*0Sstevel@tonic-gate 91*0Sstevel@tonic-gate /* 92*0Sstevel@tonic-gate * The following tunables are obsolete. Though for compatibility we 93*0Sstevel@tonic-gate * still read and interpret msginfo_msgmnb, msginfo_msgmni, and 94*0Sstevel@tonic-gate * msginfo_msgtql (see os/project.c and os/rctl_proc.c), the preferred 95*0Sstevel@tonic-gate * mechanism for administrating the IPC Message facility is through the 96*0Sstevel@tonic-gate * resource controls described at the top of this file. 97*0Sstevel@tonic-gate */ 98*0Sstevel@tonic-gate size_t msginfo_msgmax = 2048; /* (obsolete) */ 99*0Sstevel@tonic-gate size_t msginfo_msgmnb = 4096; /* (obsolete) */ 100*0Sstevel@tonic-gate int msginfo_msgmni = 50; /* (obsolete) */ 101*0Sstevel@tonic-gate int msginfo_msgtql = 40; /* (obsolete) */ 102*0Sstevel@tonic-gate int msginfo_msgssz = 8; /* (obsolete) */ 103*0Sstevel@tonic-gate int msginfo_msgmap = 0; /* (obsolete) */ 104*0Sstevel@tonic-gate ushort_t msginfo_msgseg = 1024; /* (obsolete) */ 105*0Sstevel@tonic-gate 106*0Sstevel@tonic-gate extern rctl_hndl_t rc_project_msgmni; 107*0Sstevel@tonic-gate extern rctl_hndl_t rc_process_msgmnb; 108*0Sstevel@tonic-gate extern rctl_hndl_t rc_process_msgtql; 109*0Sstevel@tonic-gate static ipc_service_t *msq_svc; 110*0Sstevel@tonic-gate static zone_key_t msg_zone_key; 111*0Sstevel@tonic-gate 112*0Sstevel@tonic-gate static void msg_dtor(kipc_perm_t *); 113*0Sstevel@tonic-gate static void msg_rmid(kipc_perm_t *); 114*0Sstevel@tonic-gate static void msg_remove_zone(zoneid_t, void *); 115*0Sstevel@tonic-gate 116*0Sstevel@tonic-gate /* 117*0Sstevel@tonic-gate * Module linkage information for the kernel. 118*0Sstevel@tonic-gate */ 119*0Sstevel@tonic-gate static ssize_t msgsys(int opcode, uintptr_t a0, uintptr_t a1, uintptr_t a2, 120*0Sstevel@tonic-gate uintptr_t a4, uintptr_t a5); 121*0Sstevel@tonic-gate 122*0Sstevel@tonic-gate static struct sysent ipcmsg_sysent = { 123*0Sstevel@tonic-gate 6, 124*0Sstevel@tonic-gate #ifdef _LP64 125*0Sstevel@tonic-gate SE_ARGC | SE_NOUNLOAD | SE_64RVAL, 126*0Sstevel@tonic-gate #else 127*0Sstevel@tonic-gate SE_ARGC | SE_NOUNLOAD | SE_32RVAL1, 128*0Sstevel@tonic-gate #endif 129*0Sstevel@tonic-gate (int (*)())msgsys 130*0Sstevel@tonic-gate }; 131*0Sstevel@tonic-gate 132*0Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 133*0Sstevel@tonic-gate static ssize32_t msgsys32(int opcode, uint32_t a0, uint32_t a1, uint32_t a2, 134*0Sstevel@tonic-gate uint32_t a4, uint32_t a5); 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gate static struct sysent ipcmsg_sysent32 = { 137*0Sstevel@tonic-gate 6, 138*0Sstevel@tonic-gate SE_ARGC | SE_NOUNLOAD | SE_32RVAL1, 139*0Sstevel@tonic-gate (int (*)())msgsys32 140*0Sstevel@tonic-gate }; 141*0Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate static struct modlsys modlsys = { 144*0Sstevel@tonic-gate &mod_syscallops, "System V message facility", &ipcmsg_sysent 145*0Sstevel@tonic-gate }; 146*0Sstevel@tonic-gate 147*0Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 148*0Sstevel@tonic-gate static struct modlsys modlsys32 = { 149*0Sstevel@tonic-gate &mod_syscallops32, "32-bit System V message facility", &ipcmsg_sysent32 150*0Sstevel@tonic-gate }; 151*0Sstevel@tonic-gate #endif 152*0Sstevel@tonic-gate 153*0Sstevel@tonic-gate static struct modlinkage modlinkage = { 154*0Sstevel@tonic-gate MODREV_1, 155*0Sstevel@tonic-gate &modlsys, 156*0Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 157*0Sstevel@tonic-gate &modlsys32, 158*0Sstevel@tonic-gate #endif 159*0Sstevel@tonic-gate NULL 160*0Sstevel@tonic-gate }; 161*0Sstevel@tonic-gate 162*0Sstevel@tonic-gate 163*0Sstevel@tonic-gate int 164*0Sstevel@tonic-gate _init(void) 165*0Sstevel@tonic-gate { 166*0Sstevel@tonic-gate int result; 167*0Sstevel@tonic-gate 168*0Sstevel@tonic-gate msq_svc = ipcs_create("msqids", rc_project_msgmni, sizeof (kmsqid_t), 169*0Sstevel@tonic-gate msg_dtor, msg_rmid, AT_IPC_MSG, 170*0Sstevel@tonic-gate offsetof(kproject_data_t, kpd_msgmni)); 171*0Sstevel@tonic-gate zone_key_create(&msg_zone_key, NULL, msg_remove_zone, NULL); 172*0Sstevel@tonic-gate 173*0Sstevel@tonic-gate if ((result = mod_install(&modlinkage)) == 0) 174*0Sstevel@tonic-gate return (0); 175*0Sstevel@tonic-gate 176*0Sstevel@tonic-gate (void) zone_key_delete(msg_zone_key); 177*0Sstevel@tonic-gate ipcs_destroy(msq_svc); 178*0Sstevel@tonic-gate 179*0Sstevel@tonic-gate return (result); 180*0Sstevel@tonic-gate } 181*0Sstevel@tonic-gate 182*0Sstevel@tonic-gate int 183*0Sstevel@tonic-gate _fini(void) 184*0Sstevel@tonic-gate { 185*0Sstevel@tonic-gate return (EBUSY); 186*0Sstevel@tonic-gate } 187*0Sstevel@tonic-gate 188*0Sstevel@tonic-gate int 189*0Sstevel@tonic-gate _info(struct modinfo *modinfop) 190*0Sstevel@tonic-gate { 191*0Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 192*0Sstevel@tonic-gate } 193*0Sstevel@tonic-gate 194*0Sstevel@tonic-gate static void 195*0Sstevel@tonic-gate msg_dtor(kipc_perm_t *perm) 196*0Sstevel@tonic-gate { 197*0Sstevel@tonic-gate kmsqid_t *qp = (kmsqid_t *)perm; 198*0Sstevel@tonic-gate 199*0Sstevel@tonic-gate ASSERT(qp->msg_rcv_cnt == 0); 200*0Sstevel@tonic-gate ASSERT(qp->msg_snd_cnt == 0); 201*0Sstevel@tonic-gate ASSERT(qp->msg_cbytes == 0); 202*0Sstevel@tonic-gate list_destroy(&qp->msg_list); 203*0Sstevel@tonic-gate } 204*0Sstevel@tonic-gate 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gate #define msg_hold(mp) (mp)->msg_copycnt++ 207*0Sstevel@tonic-gate 208*0Sstevel@tonic-gate /* 209*0Sstevel@tonic-gate * msg_rele - decrement the reference count on the message. When count 210*0Sstevel@tonic-gate * reaches zero, free message header and contents. 211*0Sstevel@tonic-gate */ 212*0Sstevel@tonic-gate static void 213*0Sstevel@tonic-gate msg_rele(struct msg *mp) 214*0Sstevel@tonic-gate { 215*0Sstevel@tonic-gate ASSERT(mp->msg_copycnt > 0); 216*0Sstevel@tonic-gate if (mp->msg_copycnt-- == 1) { 217*0Sstevel@tonic-gate if (mp->msg_addr) 218*0Sstevel@tonic-gate kmem_free(mp->msg_addr, mp->msg_size); 219*0Sstevel@tonic-gate kmem_free(mp, sizeof (struct msg)); 220*0Sstevel@tonic-gate } 221*0Sstevel@tonic-gate } 222*0Sstevel@tonic-gate 223*0Sstevel@tonic-gate /* 224*0Sstevel@tonic-gate * msgunlink - Unlink msg from queue, decrement byte count and wake up anyone 225*0Sstevel@tonic-gate * waiting for free bytes on queue. 226*0Sstevel@tonic-gate * 227*0Sstevel@tonic-gate * Called with queue locked. 228*0Sstevel@tonic-gate */ 229*0Sstevel@tonic-gate static void 230*0Sstevel@tonic-gate msgunlink(kmsqid_t *qp, struct msg *mp) 231*0Sstevel@tonic-gate { 232*0Sstevel@tonic-gate list_remove(&qp->msg_list, mp); 233*0Sstevel@tonic-gate qp->msg_qnum--; 234*0Sstevel@tonic-gate qp->msg_cbytes -= mp->msg_size; 235*0Sstevel@tonic-gate msg_rele(mp); 236*0Sstevel@tonic-gate 237*0Sstevel@tonic-gate /* Wake up waiting writers */ 238*0Sstevel@tonic-gate if (qp->msg_snd_cnt) 239*0Sstevel@tonic-gate cv_broadcast(&qp->msg_snd_cv); 240*0Sstevel@tonic-gate } 241*0Sstevel@tonic-gate 242*0Sstevel@tonic-gate static void 243*0Sstevel@tonic-gate msg_rmid(kipc_perm_t *perm) 244*0Sstevel@tonic-gate { 245*0Sstevel@tonic-gate kmsqid_t *qp = (kmsqid_t *)perm; 246*0Sstevel@tonic-gate struct msg *mp; 247*0Sstevel@tonic-gate 248*0Sstevel@tonic-gate 249*0Sstevel@tonic-gate while ((mp = list_head(&qp->msg_list)) != NULL) 250*0Sstevel@tonic-gate msgunlink(qp, mp); 251*0Sstevel@tonic-gate ASSERT(qp->msg_cbytes == 0); 252*0Sstevel@tonic-gate 253*0Sstevel@tonic-gate if (qp->msg_rcv_cnt) 254*0Sstevel@tonic-gate cv_broadcast(&qp->msg_rcv_cv); 255*0Sstevel@tonic-gate if (qp->msg_snd_cnt) 256*0Sstevel@tonic-gate cv_broadcast(&qp->msg_snd_cv); 257*0Sstevel@tonic-gate } 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gate /* 260*0Sstevel@tonic-gate * msgctl system call. 261*0Sstevel@tonic-gate * 262*0Sstevel@tonic-gate * gets q lock (via ipc_lookup), releases before return. 263*0Sstevel@tonic-gate * may call users of msg_lock 264*0Sstevel@tonic-gate */ 265*0Sstevel@tonic-gate static int 266*0Sstevel@tonic-gate msgctl(int msgid, int cmd, void *arg) 267*0Sstevel@tonic-gate { 268*0Sstevel@tonic-gate STRUCT_DECL(msqid_ds, ds); /* SVR4 queue work area */ 269*0Sstevel@tonic-gate kmsqid_t *qp; /* ptr to associated q */ 270*0Sstevel@tonic-gate int error; 271*0Sstevel@tonic-gate struct cred *cr; 272*0Sstevel@tonic-gate model_t mdl = get_udatamodel(); 273*0Sstevel@tonic-gate struct msqid_ds64 ds64; 274*0Sstevel@tonic-gate kmutex_t *lock; 275*0Sstevel@tonic-gate proc_t *pp = curproc; 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate STRUCT_INIT(ds, mdl); 278*0Sstevel@tonic-gate cr = CRED(); 279*0Sstevel@tonic-gate 280*0Sstevel@tonic-gate /* 281*0Sstevel@tonic-gate * Perform pre- or non-lookup actions (e.g. copyins, RMID). 282*0Sstevel@tonic-gate */ 283*0Sstevel@tonic-gate switch (cmd) { 284*0Sstevel@tonic-gate case IPC_SET: 285*0Sstevel@tonic-gate if (copyin(arg, STRUCT_BUF(ds), STRUCT_SIZE(ds))) 286*0Sstevel@tonic-gate return (set_errno(EFAULT)); 287*0Sstevel@tonic-gate break; 288*0Sstevel@tonic-gate 289*0Sstevel@tonic-gate case IPC_SET64: 290*0Sstevel@tonic-gate if (copyin(arg, &ds64, sizeof (struct msqid_ds64))) 291*0Sstevel@tonic-gate return (set_errno(EFAULT)); 292*0Sstevel@tonic-gate break; 293*0Sstevel@tonic-gate 294*0Sstevel@tonic-gate case IPC_RMID: 295*0Sstevel@tonic-gate if (error = ipc_rmid(msq_svc, msgid, cr)) 296*0Sstevel@tonic-gate return (set_errno(error)); 297*0Sstevel@tonic-gate return (0); 298*0Sstevel@tonic-gate } 299*0Sstevel@tonic-gate 300*0Sstevel@tonic-gate /* 301*0Sstevel@tonic-gate * get msqid_ds for this msgid 302*0Sstevel@tonic-gate */ 303*0Sstevel@tonic-gate if ((lock = ipc_lookup(msq_svc, msgid, (kipc_perm_t **)&qp)) == NULL) 304*0Sstevel@tonic-gate return (set_errno(EINVAL)); 305*0Sstevel@tonic-gate 306*0Sstevel@tonic-gate switch (cmd) { 307*0Sstevel@tonic-gate case IPC_SET: 308*0Sstevel@tonic-gate if (STRUCT_FGET(ds, msg_qbytes) > qp->msg_qbytes && 309*0Sstevel@tonic-gate secpolicy_ipc_config(cr) != 0) { 310*0Sstevel@tonic-gate mutex_exit(lock); 311*0Sstevel@tonic-gate return (set_errno(EPERM)); 312*0Sstevel@tonic-gate } 313*0Sstevel@tonic-gate if (error = ipcperm_set(msq_svc, cr, &qp->msg_perm, 314*0Sstevel@tonic-gate &STRUCT_BUF(ds)->msg_perm, mdl)) { 315*0Sstevel@tonic-gate mutex_exit(lock); 316*0Sstevel@tonic-gate return (set_errno(error)); 317*0Sstevel@tonic-gate } 318*0Sstevel@tonic-gate qp->msg_qbytes = STRUCT_FGET(ds, msg_qbytes); 319*0Sstevel@tonic-gate qp->msg_ctime = gethrestime_sec(); 320*0Sstevel@tonic-gate break; 321*0Sstevel@tonic-gate 322*0Sstevel@tonic-gate case IPC_STAT: 323*0Sstevel@tonic-gate if (error = ipcperm_access(&qp->msg_perm, MSG_R, cr)) { 324*0Sstevel@tonic-gate mutex_exit(lock); 325*0Sstevel@tonic-gate return (set_errno(error)); 326*0Sstevel@tonic-gate } 327*0Sstevel@tonic-gate 328*0Sstevel@tonic-gate if (qp->msg_rcv_cnt) 329*0Sstevel@tonic-gate qp->msg_perm.ipc_mode |= MSG_RWAIT; 330*0Sstevel@tonic-gate if (qp->msg_snd_cnt) 331*0Sstevel@tonic-gate qp->msg_perm.ipc_mode |= MSG_WWAIT; 332*0Sstevel@tonic-gate ipcperm_stat(&STRUCT_BUF(ds)->msg_perm, &qp->msg_perm, mdl); 333*0Sstevel@tonic-gate qp->msg_perm.ipc_mode &= ~(MSG_RWAIT|MSG_WWAIT); 334*0Sstevel@tonic-gate STRUCT_FSETP(ds, msg_first, NULL); /* kernel addr */ 335*0Sstevel@tonic-gate STRUCT_FSETP(ds, msg_last, NULL); 336*0Sstevel@tonic-gate STRUCT_FSET(ds, msg_cbytes, qp->msg_cbytes); 337*0Sstevel@tonic-gate STRUCT_FSET(ds, msg_qnum, qp->msg_qnum); 338*0Sstevel@tonic-gate STRUCT_FSET(ds, msg_qbytes, qp->msg_qbytes); 339*0Sstevel@tonic-gate STRUCT_FSET(ds, msg_lspid, qp->msg_lspid); 340*0Sstevel@tonic-gate STRUCT_FSET(ds, msg_lrpid, qp->msg_lrpid); 341*0Sstevel@tonic-gate STRUCT_FSET(ds, msg_stime, qp->msg_stime); 342*0Sstevel@tonic-gate STRUCT_FSET(ds, msg_rtime, qp->msg_rtime); 343*0Sstevel@tonic-gate STRUCT_FSET(ds, msg_ctime, qp->msg_ctime); 344*0Sstevel@tonic-gate break; 345*0Sstevel@tonic-gate 346*0Sstevel@tonic-gate case IPC_SET64: 347*0Sstevel@tonic-gate mutex_enter(&pp->p_lock); 348*0Sstevel@tonic-gate if ((ds64.msgx_qbytes > qp->msg_qbytes) && 349*0Sstevel@tonic-gate secpolicy_ipc_config(cr) != 0 && 350*0Sstevel@tonic-gate rctl_test(rc_process_msgmnb, pp->p_rctls, pp, 351*0Sstevel@tonic-gate ds64.msgx_qbytes, RCA_SAFE) & RCT_DENY) { 352*0Sstevel@tonic-gate mutex_exit(&pp->p_lock); 353*0Sstevel@tonic-gate mutex_exit(lock); 354*0Sstevel@tonic-gate return (set_errno(EPERM)); 355*0Sstevel@tonic-gate } 356*0Sstevel@tonic-gate mutex_exit(&pp->p_lock); 357*0Sstevel@tonic-gate if (error = ipcperm_set64(msq_svc, cr, &qp->msg_perm, 358*0Sstevel@tonic-gate &ds64.msgx_perm)) { 359*0Sstevel@tonic-gate mutex_exit(lock); 360*0Sstevel@tonic-gate return (set_errno(error)); 361*0Sstevel@tonic-gate } 362*0Sstevel@tonic-gate qp->msg_qbytes = ds64.msgx_qbytes; 363*0Sstevel@tonic-gate qp->msg_ctime = gethrestime_sec(); 364*0Sstevel@tonic-gate break; 365*0Sstevel@tonic-gate 366*0Sstevel@tonic-gate case IPC_STAT64: 367*0Sstevel@tonic-gate if (qp->msg_rcv_cnt) 368*0Sstevel@tonic-gate qp->msg_perm.ipc_mode |= MSG_RWAIT; 369*0Sstevel@tonic-gate if (qp->msg_snd_cnt) 370*0Sstevel@tonic-gate qp->msg_perm.ipc_mode |= MSG_WWAIT; 371*0Sstevel@tonic-gate ipcperm_stat64(&ds64.msgx_perm, &qp->msg_perm); 372*0Sstevel@tonic-gate qp->msg_perm.ipc_mode &= ~(MSG_RWAIT|MSG_WWAIT); 373*0Sstevel@tonic-gate ds64.msgx_cbytes = qp->msg_cbytes; 374*0Sstevel@tonic-gate ds64.msgx_qnum = qp->msg_qnum; 375*0Sstevel@tonic-gate ds64.msgx_qbytes = qp->msg_qbytes; 376*0Sstevel@tonic-gate ds64.msgx_lspid = qp->msg_lspid; 377*0Sstevel@tonic-gate ds64.msgx_lrpid = qp->msg_lrpid; 378*0Sstevel@tonic-gate ds64.msgx_stime = qp->msg_stime; 379*0Sstevel@tonic-gate ds64.msgx_rtime = qp->msg_rtime; 380*0Sstevel@tonic-gate ds64.msgx_ctime = qp->msg_ctime; 381*0Sstevel@tonic-gate break; 382*0Sstevel@tonic-gate 383*0Sstevel@tonic-gate default: 384*0Sstevel@tonic-gate mutex_exit(lock); 385*0Sstevel@tonic-gate return (set_errno(EINVAL)); 386*0Sstevel@tonic-gate } 387*0Sstevel@tonic-gate 388*0Sstevel@tonic-gate mutex_exit(lock); 389*0Sstevel@tonic-gate 390*0Sstevel@tonic-gate /* 391*0Sstevel@tonic-gate * Do copyout last (after releasing mutex). 392*0Sstevel@tonic-gate */ 393*0Sstevel@tonic-gate switch (cmd) { 394*0Sstevel@tonic-gate case IPC_STAT: 395*0Sstevel@tonic-gate if (copyout(STRUCT_BUF(ds), arg, STRUCT_SIZE(ds))) 396*0Sstevel@tonic-gate return (set_errno(EFAULT)); 397*0Sstevel@tonic-gate break; 398*0Sstevel@tonic-gate 399*0Sstevel@tonic-gate case IPC_STAT64: 400*0Sstevel@tonic-gate if (copyout(&ds64, arg, sizeof (struct msqid_ds64))) 401*0Sstevel@tonic-gate return (set_errno(EFAULT)); 402*0Sstevel@tonic-gate break; 403*0Sstevel@tonic-gate } 404*0Sstevel@tonic-gate 405*0Sstevel@tonic-gate return (0); 406*0Sstevel@tonic-gate } 407*0Sstevel@tonic-gate 408*0Sstevel@tonic-gate /* 409*0Sstevel@tonic-gate * Remove all message queues associated with a given zone. Called by 410*0Sstevel@tonic-gate * zone_shutdown when the zone is halted. 411*0Sstevel@tonic-gate */ 412*0Sstevel@tonic-gate /*ARGSUSED1*/ 413*0Sstevel@tonic-gate static void 414*0Sstevel@tonic-gate msg_remove_zone(zoneid_t zoneid, void *arg) 415*0Sstevel@tonic-gate { 416*0Sstevel@tonic-gate ipc_remove_zone(msq_svc, zoneid); 417*0Sstevel@tonic-gate } 418*0Sstevel@tonic-gate 419*0Sstevel@tonic-gate /* 420*0Sstevel@tonic-gate * msgget system call. 421*0Sstevel@tonic-gate */ 422*0Sstevel@tonic-gate static int 423*0Sstevel@tonic-gate msgget(key_t key, int msgflg) 424*0Sstevel@tonic-gate { 425*0Sstevel@tonic-gate kmsqid_t *qp; 426*0Sstevel@tonic-gate kmutex_t *lock; 427*0Sstevel@tonic-gate int id, error; 428*0Sstevel@tonic-gate proc_t *pp = curproc; 429*0Sstevel@tonic-gate 430*0Sstevel@tonic-gate top: 431*0Sstevel@tonic-gate if (error = ipc_get(msq_svc, key, msgflg, (kipc_perm_t **)&qp, &lock)) 432*0Sstevel@tonic-gate return (set_errno(error)); 433*0Sstevel@tonic-gate 434*0Sstevel@tonic-gate if (IPC_FREE(&qp->msg_perm)) { 435*0Sstevel@tonic-gate mutex_exit(lock); 436*0Sstevel@tonic-gate mutex_exit(&pp->p_lock); 437*0Sstevel@tonic-gate 438*0Sstevel@tonic-gate list_create(&qp->msg_list, sizeof (struct msg), 439*0Sstevel@tonic-gate offsetof(struct msg, msg_node)); 440*0Sstevel@tonic-gate qp->msg_qnum = 0; 441*0Sstevel@tonic-gate qp->msg_lspid = qp->msg_lrpid = 0; 442*0Sstevel@tonic-gate qp->msg_stime = qp->msg_rtime = 0; 443*0Sstevel@tonic-gate qp->msg_ctime = gethrestime_sec(); 444*0Sstevel@tonic-gate qp->msg_rcv_cnt = qp->msg_snd_cnt = 0; 445*0Sstevel@tonic-gate 446*0Sstevel@tonic-gate if (error = ipc_commit_begin(msq_svc, key, msgflg, 447*0Sstevel@tonic-gate (kipc_perm_t *)qp)) { 448*0Sstevel@tonic-gate if (error == EAGAIN) 449*0Sstevel@tonic-gate goto top; 450*0Sstevel@tonic-gate return (set_errno(error)); 451*0Sstevel@tonic-gate } 452*0Sstevel@tonic-gate qp->msg_qbytes = rctl_enforced_value(rc_process_msgmnb, 453*0Sstevel@tonic-gate pp->p_rctls, pp); 454*0Sstevel@tonic-gate qp->msg_qmax = rctl_enforced_value(rc_process_msgtql, 455*0Sstevel@tonic-gate pp->p_rctls, pp); 456*0Sstevel@tonic-gate lock = ipc_commit_end(msq_svc, &qp->msg_perm); 457*0Sstevel@tonic-gate } 458*0Sstevel@tonic-gate #ifdef C2_AUDIT 459*0Sstevel@tonic-gate if (audit_active) 460*0Sstevel@tonic-gate audit_ipcget(AT_IPC_MSG, (void *)qp); 461*0Sstevel@tonic-gate #endif 462*0Sstevel@tonic-gate id = qp->msg_perm.ipc_id; 463*0Sstevel@tonic-gate mutex_exit(lock); 464*0Sstevel@tonic-gate return (id); 465*0Sstevel@tonic-gate } 466*0Sstevel@tonic-gate 467*0Sstevel@tonic-gate /* 468*0Sstevel@tonic-gate * msgrcv system call. 469*0Sstevel@tonic-gate */ 470*0Sstevel@tonic-gate static ssize_t 471*0Sstevel@tonic-gate msgrcv(int msqid, struct ipcmsgbuf *msgp, size_t msgsz, long msgtyp, int msgflg) 472*0Sstevel@tonic-gate { 473*0Sstevel@tonic-gate struct msg *mp; /* ptr to msg on q */ 474*0Sstevel@tonic-gate struct msg *smp; /* ptr to best msg on q */ 475*0Sstevel@tonic-gate kmsqid_t *qp; /* ptr to associated q */ 476*0Sstevel@tonic-gate kmutex_t *lock; 477*0Sstevel@tonic-gate size_t xtsz; /* transfer byte count */ 478*0Sstevel@tonic-gate int error = 0, copyerror = 0; 479*0Sstevel@tonic-gate int cvres; 480*0Sstevel@tonic-gate STRUCT_HANDLE(ipcmsgbuf, umsgp); 481*0Sstevel@tonic-gate model_t mdl = get_udatamodel(); 482*0Sstevel@tonic-gate 483*0Sstevel@tonic-gate CPU_STATS_ADDQ(CPU, sys, msg, 1); /* bump msg send/rcv count */ 484*0Sstevel@tonic-gate STRUCT_SET_HANDLE(umsgp, mdl, msgp); 485*0Sstevel@tonic-gate 486*0Sstevel@tonic-gate if ((lock = ipc_lookup(msq_svc, msqid, (kipc_perm_t **)&qp)) == NULL) 487*0Sstevel@tonic-gate return ((ssize_t)set_errno(EINVAL)); 488*0Sstevel@tonic-gate ipc_hold(msq_svc, (kipc_perm_t *)qp); 489*0Sstevel@tonic-gate 490*0Sstevel@tonic-gate if (error = ipcperm_access(&qp->msg_perm, MSG_R, CRED())) 491*0Sstevel@tonic-gate goto msgrcv_out; 492*0Sstevel@tonic-gate 493*0Sstevel@tonic-gate findmsg: 494*0Sstevel@tonic-gate smp = NULL; 495*0Sstevel@tonic-gate mp = list_head(&qp->msg_list); 496*0Sstevel@tonic-gate if (msgtyp == 0) { 497*0Sstevel@tonic-gate smp = mp; 498*0Sstevel@tonic-gate } else { 499*0Sstevel@tonic-gate for (; mp; mp = list_next(&qp->msg_list, mp)) { 500*0Sstevel@tonic-gate if (msgtyp > 0) { 501*0Sstevel@tonic-gate if (msgtyp != mp->msg_type) 502*0Sstevel@tonic-gate continue; 503*0Sstevel@tonic-gate smp = mp; 504*0Sstevel@tonic-gate break; 505*0Sstevel@tonic-gate } 506*0Sstevel@tonic-gate if (mp->msg_type <= -msgtyp) { 507*0Sstevel@tonic-gate if (smp && smp->msg_type <= mp->msg_type) 508*0Sstevel@tonic-gate continue; 509*0Sstevel@tonic-gate smp = mp; 510*0Sstevel@tonic-gate } 511*0Sstevel@tonic-gate } 512*0Sstevel@tonic-gate } 513*0Sstevel@tonic-gate 514*0Sstevel@tonic-gate if (smp) { 515*0Sstevel@tonic-gate /* 516*0Sstevel@tonic-gate * Message found. 517*0Sstevel@tonic-gate */ 518*0Sstevel@tonic-gate if ((smp->msg_flags & MSG_RCVCOPY) == 0) { 519*0Sstevel@tonic-gate /* 520*0Sstevel@tonic-gate * No one else is copying this message. Copy it. 521*0Sstevel@tonic-gate */ 522*0Sstevel@tonic-gate if (msgsz < smp->msg_size) { 523*0Sstevel@tonic-gate if ((msgflg & MSG_NOERROR) == 0) { 524*0Sstevel@tonic-gate error = E2BIG; 525*0Sstevel@tonic-gate goto msgrcv_out; 526*0Sstevel@tonic-gate } else { 527*0Sstevel@tonic-gate xtsz = msgsz; 528*0Sstevel@tonic-gate } 529*0Sstevel@tonic-gate } else { 530*0Sstevel@tonic-gate xtsz = smp->msg_size; 531*0Sstevel@tonic-gate } 532*0Sstevel@tonic-gate 533*0Sstevel@tonic-gate /* 534*0Sstevel@tonic-gate * Mark message as being copied out. Release mutex 535*0Sstevel@tonic-gate * while copying out. 536*0Sstevel@tonic-gate */ 537*0Sstevel@tonic-gate ASSERT((smp->msg_flags & MSG_RCVCOPY) == 0); 538*0Sstevel@tonic-gate smp->msg_flags |= MSG_RCVCOPY; 539*0Sstevel@tonic-gate msg_hold(smp); 540*0Sstevel@tonic-gate mutex_exit(lock); 541*0Sstevel@tonic-gate 542*0Sstevel@tonic-gate if (mdl == DATAMODEL_NATIVE) { 543*0Sstevel@tonic-gate copyerror = copyout(&smp->msg_type, msgp, 544*0Sstevel@tonic-gate sizeof (smp->msg_type)); 545*0Sstevel@tonic-gate } else { 546*0Sstevel@tonic-gate /* 547*0Sstevel@tonic-gate * 32-bit callers need an imploded msg type. 548*0Sstevel@tonic-gate */ 549*0Sstevel@tonic-gate int32_t msg_type32 = smp->msg_type; 550*0Sstevel@tonic-gate 551*0Sstevel@tonic-gate copyerror = copyout(&msg_type32, msgp, 552*0Sstevel@tonic-gate sizeof (msg_type32)); 553*0Sstevel@tonic-gate } 554*0Sstevel@tonic-gate 555*0Sstevel@tonic-gate if (copyerror == 0 && xtsz) 556*0Sstevel@tonic-gate copyerror = copyout(smp->msg_addr, 557*0Sstevel@tonic-gate STRUCT_FADDR(umsgp, mtext), xtsz); 558*0Sstevel@tonic-gate 559*0Sstevel@tonic-gate /* 560*0Sstevel@tonic-gate * Reclaim mutex, make sure queue still exists, 561*0Sstevel@tonic-gate * and remove message. 562*0Sstevel@tonic-gate */ 563*0Sstevel@tonic-gate lock = ipc_lock(msq_svc, qp->msg_perm.ipc_id); 564*0Sstevel@tonic-gate ASSERT(smp->msg_flags & MSG_RCVCOPY); 565*0Sstevel@tonic-gate smp->msg_flags &= ~MSG_RCVCOPY; 566*0Sstevel@tonic-gate msg_rele(smp); 567*0Sstevel@tonic-gate 568*0Sstevel@tonic-gate if (IPC_FREE(&qp->msg_perm)) { 569*0Sstevel@tonic-gate error = EIDRM; 570*0Sstevel@tonic-gate goto msgrcv_out; 571*0Sstevel@tonic-gate } 572*0Sstevel@tonic-gate cv_broadcast(&qp->msg_rcv_cv); 573*0Sstevel@tonic-gate 574*0Sstevel@tonic-gate if (copyerror) { 575*0Sstevel@tonic-gate error = EFAULT; 576*0Sstevel@tonic-gate goto msgrcv_out; 577*0Sstevel@tonic-gate } 578*0Sstevel@tonic-gate qp->msg_lrpid = ttoproc(curthread)->p_pid; 579*0Sstevel@tonic-gate qp->msg_rtime = gethrestime_sec(); 580*0Sstevel@tonic-gate msgunlink(qp, smp); 581*0Sstevel@tonic-gate goto msgrcv_out; 582*0Sstevel@tonic-gate } 583*0Sstevel@tonic-gate 584*0Sstevel@tonic-gate } else { 585*0Sstevel@tonic-gate /* 586*0Sstevel@tonic-gate * No message found. 587*0Sstevel@tonic-gate */ 588*0Sstevel@tonic-gate if (msgflg & IPC_NOWAIT) { 589*0Sstevel@tonic-gate error = ENOMSG; 590*0Sstevel@tonic-gate goto msgrcv_out; 591*0Sstevel@tonic-gate } 592*0Sstevel@tonic-gate } 593*0Sstevel@tonic-gate 594*0Sstevel@tonic-gate /* Wait for new message */ 595*0Sstevel@tonic-gate qp->msg_rcv_cnt++; 596*0Sstevel@tonic-gate cvres = cv_wait_sig(&qp->msg_rcv_cv, lock); 597*0Sstevel@tonic-gate lock = ipc_relock(msq_svc, qp->msg_perm.ipc_id, lock); 598*0Sstevel@tonic-gate qp->msg_rcv_cnt--; 599*0Sstevel@tonic-gate 600*0Sstevel@tonic-gate if (IPC_FREE(&qp->msg_perm)) { 601*0Sstevel@tonic-gate error = EIDRM; 602*0Sstevel@tonic-gate goto msgrcv_out; 603*0Sstevel@tonic-gate } 604*0Sstevel@tonic-gate if (cvres == 0) { 605*0Sstevel@tonic-gate error = EINTR; 606*0Sstevel@tonic-gate goto msgrcv_out; 607*0Sstevel@tonic-gate } 608*0Sstevel@tonic-gate 609*0Sstevel@tonic-gate goto findmsg; 610*0Sstevel@tonic-gate 611*0Sstevel@tonic-gate msgrcv_out: 612*0Sstevel@tonic-gate ipc_rele(msq_svc, (kipc_perm_t *)qp); 613*0Sstevel@tonic-gate if (error) 614*0Sstevel@tonic-gate return ((ssize_t)set_errno(error)); 615*0Sstevel@tonic-gate return ((ssize_t)xtsz); 616*0Sstevel@tonic-gate } 617*0Sstevel@tonic-gate 618*0Sstevel@tonic-gate /* 619*0Sstevel@tonic-gate * msgids system call. 620*0Sstevel@tonic-gate */ 621*0Sstevel@tonic-gate static int 622*0Sstevel@tonic-gate msgids(int *buf, uint_t nids, uint_t *pnids) 623*0Sstevel@tonic-gate { 624*0Sstevel@tonic-gate int error; 625*0Sstevel@tonic-gate 626*0Sstevel@tonic-gate if (error = ipc_ids(msq_svc, buf, nids, pnids)) 627*0Sstevel@tonic-gate return (set_errno(error)); 628*0Sstevel@tonic-gate 629*0Sstevel@tonic-gate return (0); 630*0Sstevel@tonic-gate } 631*0Sstevel@tonic-gate 632*0Sstevel@tonic-gate #define RND(x) roundup((x), sizeof (size_t)) 633*0Sstevel@tonic-gate #define RND32(x) roundup((x), sizeof (size32_t)) 634*0Sstevel@tonic-gate 635*0Sstevel@tonic-gate /* 636*0Sstevel@tonic-gate * msgsnap system call. 637*0Sstevel@tonic-gate */ 638*0Sstevel@tonic-gate static int 639*0Sstevel@tonic-gate msgsnap(int msqid, caddr_t buf, size_t bufsz, long msgtyp) 640*0Sstevel@tonic-gate { 641*0Sstevel@tonic-gate struct msg *mp; /* ptr to msg on q */ 642*0Sstevel@tonic-gate kmsqid_t *qp; /* ptr to associated q */ 643*0Sstevel@tonic-gate kmutex_t *lock; 644*0Sstevel@tonic-gate size_t size; 645*0Sstevel@tonic-gate size_t nmsg; 646*0Sstevel@tonic-gate struct msg **snaplist; 647*0Sstevel@tonic-gate int error, i; 648*0Sstevel@tonic-gate model_t mdl = get_udatamodel(); 649*0Sstevel@tonic-gate STRUCT_DECL(msgsnap_head, head); 650*0Sstevel@tonic-gate STRUCT_DECL(msgsnap_mhead, mhead); 651*0Sstevel@tonic-gate 652*0Sstevel@tonic-gate STRUCT_INIT(head, mdl); 653*0Sstevel@tonic-gate STRUCT_INIT(mhead, mdl); 654*0Sstevel@tonic-gate 655*0Sstevel@tonic-gate if (bufsz < STRUCT_SIZE(head)) 656*0Sstevel@tonic-gate return (set_errno(EINVAL)); 657*0Sstevel@tonic-gate 658*0Sstevel@tonic-gate if ((lock = ipc_lookup(msq_svc, msqid, (kipc_perm_t **)&qp)) == NULL) 659*0Sstevel@tonic-gate return (set_errno(EINVAL)); 660*0Sstevel@tonic-gate 661*0Sstevel@tonic-gate if (error = ipcperm_access(&qp->msg_perm, MSG_R, CRED())) { 662*0Sstevel@tonic-gate mutex_exit(lock); 663*0Sstevel@tonic-gate return (set_errno(error)); 664*0Sstevel@tonic-gate } 665*0Sstevel@tonic-gate ipc_hold(msq_svc, (kipc_perm_t *)qp); 666*0Sstevel@tonic-gate 667*0Sstevel@tonic-gate /* 668*0Sstevel@tonic-gate * First compute the required buffer size and 669*0Sstevel@tonic-gate * the number of messages on the queue. 670*0Sstevel@tonic-gate */ 671*0Sstevel@tonic-gate size = nmsg = 0; 672*0Sstevel@tonic-gate for (mp = list_head(&qp->msg_list); mp; 673*0Sstevel@tonic-gate mp = list_next(&qp->msg_list, mp)) { 674*0Sstevel@tonic-gate if (msgtyp == 0 || 675*0Sstevel@tonic-gate (msgtyp > 0 && msgtyp == mp->msg_type) || 676*0Sstevel@tonic-gate (msgtyp < 0 && mp->msg_type <= -msgtyp)) { 677*0Sstevel@tonic-gate nmsg++; 678*0Sstevel@tonic-gate if (mdl == DATAMODEL_NATIVE) 679*0Sstevel@tonic-gate size += RND(mp->msg_size); 680*0Sstevel@tonic-gate else 681*0Sstevel@tonic-gate size += RND32(mp->msg_size); 682*0Sstevel@tonic-gate } 683*0Sstevel@tonic-gate } 684*0Sstevel@tonic-gate 685*0Sstevel@tonic-gate size += STRUCT_SIZE(head) + nmsg * STRUCT_SIZE(mhead); 686*0Sstevel@tonic-gate if (size > bufsz) 687*0Sstevel@tonic-gate nmsg = 0; 688*0Sstevel@tonic-gate 689*0Sstevel@tonic-gate if (nmsg > 0) { 690*0Sstevel@tonic-gate /* 691*0Sstevel@tonic-gate * Mark the messages as being copied. 692*0Sstevel@tonic-gate */ 693*0Sstevel@tonic-gate snaplist = (struct msg **)kmem_alloc(nmsg * 694*0Sstevel@tonic-gate sizeof (struct msg *), KM_SLEEP); 695*0Sstevel@tonic-gate i = 0; 696*0Sstevel@tonic-gate for (mp = list_head(&qp->msg_list); mp; 697*0Sstevel@tonic-gate mp = list_next(&qp->msg_list, mp)) { 698*0Sstevel@tonic-gate if (msgtyp == 0 || 699*0Sstevel@tonic-gate (msgtyp > 0 && msgtyp == mp->msg_type) || 700*0Sstevel@tonic-gate (msgtyp < 0 && mp->msg_type <= -msgtyp)) { 701*0Sstevel@tonic-gate msg_hold(mp); 702*0Sstevel@tonic-gate snaplist[i] = mp; 703*0Sstevel@tonic-gate i++; 704*0Sstevel@tonic-gate } 705*0Sstevel@tonic-gate } 706*0Sstevel@tonic-gate } 707*0Sstevel@tonic-gate mutex_exit(lock); 708*0Sstevel@tonic-gate 709*0Sstevel@tonic-gate /* 710*0Sstevel@tonic-gate * Copy out the buffer header. 711*0Sstevel@tonic-gate */ 712*0Sstevel@tonic-gate STRUCT_FSET(head, msgsnap_size, size); 713*0Sstevel@tonic-gate STRUCT_FSET(head, msgsnap_nmsg, nmsg); 714*0Sstevel@tonic-gate if (copyout(STRUCT_BUF(head), buf, STRUCT_SIZE(head))) 715*0Sstevel@tonic-gate error = EFAULT; 716*0Sstevel@tonic-gate 717*0Sstevel@tonic-gate buf += STRUCT_SIZE(head); 718*0Sstevel@tonic-gate 719*0Sstevel@tonic-gate /* 720*0Sstevel@tonic-gate * Now copy out the messages one by one. 721*0Sstevel@tonic-gate */ 722*0Sstevel@tonic-gate for (i = 0; i < nmsg; i++) { 723*0Sstevel@tonic-gate mp = snaplist[i]; 724*0Sstevel@tonic-gate if (error == 0) { 725*0Sstevel@tonic-gate STRUCT_FSET(mhead, msgsnap_mlen, mp->msg_size); 726*0Sstevel@tonic-gate STRUCT_FSET(mhead, msgsnap_mtype, mp->msg_type); 727*0Sstevel@tonic-gate if (copyout(STRUCT_BUF(mhead), buf, STRUCT_SIZE(mhead))) 728*0Sstevel@tonic-gate error = EFAULT; 729*0Sstevel@tonic-gate buf += STRUCT_SIZE(mhead); 730*0Sstevel@tonic-gate 731*0Sstevel@tonic-gate if (error == 0 && 732*0Sstevel@tonic-gate mp->msg_size != 0 && 733*0Sstevel@tonic-gate copyout(mp->msg_addr, buf, mp->msg_size)) 734*0Sstevel@tonic-gate error = EFAULT; 735*0Sstevel@tonic-gate if (mdl == DATAMODEL_NATIVE) 736*0Sstevel@tonic-gate buf += RND(mp->msg_size); 737*0Sstevel@tonic-gate else 738*0Sstevel@tonic-gate buf += RND32(mp->msg_size); 739*0Sstevel@tonic-gate } 740*0Sstevel@tonic-gate lock = ipc_lock(msq_svc, qp->msg_perm.ipc_id); 741*0Sstevel@tonic-gate msg_rele(mp); 742*0Sstevel@tonic-gate /* Check for msg q deleted or reallocated */ 743*0Sstevel@tonic-gate if (IPC_FREE(&qp->msg_perm)) 744*0Sstevel@tonic-gate error = EIDRM; 745*0Sstevel@tonic-gate mutex_exit(lock); 746*0Sstevel@tonic-gate } 747*0Sstevel@tonic-gate 748*0Sstevel@tonic-gate (void) ipc_lock(msq_svc, qp->msg_perm.ipc_id); 749*0Sstevel@tonic-gate ipc_rele(msq_svc, (kipc_perm_t *)qp); 750*0Sstevel@tonic-gate 751*0Sstevel@tonic-gate if (nmsg > 0) 752*0Sstevel@tonic-gate kmem_free(snaplist, nmsg * sizeof (struct msg *)); 753*0Sstevel@tonic-gate 754*0Sstevel@tonic-gate if (error) 755*0Sstevel@tonic-gate return (set_errno(error)); 756*0Sstevel@tonic-gate return (0); 757*0Sstevel@tonic-gate } 758*0Sstevel@tonic-gate 759*0Sstevel@tonic-gate /* 760*0Sstevel@tonic-gate * msgsnd system call. 761*0Sstevel@tonic-gate */ 762*0Sstevel@tonic-gate static int 763*0Sstevel@tonic-gate msgsnd(int msqid, struct ipcmsgbuf *msgp, size_t msgsz, int msgflg) 764*0Sstevel@tonic-gate { 765*0Sstevel@tonic-gate kmsqid_t *qp; 766*0Sstevel@tonic-gate kmutex_t *lock; 767*0Sstevel@tonic-gate struct msg *mp = NULL; 768*0Sstevel@tonic-gate long type; 769*0Sstevel@tonic-gate int error = 0; 770*0Sstevel@tonic-gate model_t mdl = get_udatamodel(); 771*0Sstevel@tonic-gate STRUCT_HANDLE(ipcmsgbuf, umsgp); 772*0Sstevel@tonic-gate 773*0Sstevel@tonic-gate CPU_STATS_ADDQ(CPU, sys, msg, 1); /* bump msg send/rcv count */ 774*0Sstevel@tonic-gate STRUCT_SET_HANDLE(umsgp, mdl, msgp); 775*0Sstevel@tonic-gate 776*0Sstevel@tonic-gate if (mdl == DATAMODEL_NATIVE) { 777*0Sstevel@tonic-gate if (copyin(msgp, &type, sizeof (type))) 778*0Sstevel@tonic-gate return (set_errno(EFAULT)); 779*0Sstevel@tonic-gate } else { 780*0Sstevel@tonic-gate int32_t type32; 781*0Sstevel@tonic-gate if (copyin(msgp, &type32, sizeof (type32))) 782*0Sstevel@tonic-gate return (set_errno(EFAULT)); 783*0Sstevel@tonic-gate type = type32; 784*0Sstevel@tonic-gate } 785*0Sstevel@tonic-gate 786*0Sstevel@tonic-gate if (type < 1) 787*0Sstevel@tonic-gate return (set_errno(EINVAL)); 788*0Sstevel@tonic-gate 789*0Sstevel@tonic-gate if ((lock = ipc_lookup(msq_svc, msqid, (kipc_perm_t **)&qp)) == NULL) 790*0Sstevel@tonic-gate return (set_errno(EINVAL)); 791*0Sstevel@tonic-gate ipc_hold(msq_svc, (kipc_perm_t *)qp); 792*0Sstevel@tonic-gate 793*0Sstevel@tonic-gate if (msgsz > qp->msg_qbytes) { 794*0Sstevel@tonic-gate error = EINVAL; 795*0Sstevel@tonic-gate goto msgsnd_out; 796*0Sstevel@tonic-gate } 797*0Sstevel@tonic-gate 798*0Sstevel@tonic-gate if (error = ipcperm_access(&qp->msg_perm, MSG_W, CRED())) 799*0Sstevel@tonic-gate goto msgsnd_out; 800*0Sstevel@tonic-gate 801*0Sstevel@tonic-gate top: 802*0Sstevel@tonic-gate /* 803*0Sstevel@tonic-gate * Allocate space on q, message header, & buffer space. 804*0Sstevel@tonic-gate */ 805*0Sstevel@tonic-gate ASSERT(qp->msg_qnum <= qp->msg_qmax); 806*0Sstevel@tonic-gate while ((msgsz > qp->msg_qbytes - qp->msg_cbytes) || 807*0Sstevel@tonic-gate (qp->msg_qnum == qp->msg_qmax)) { 808*0Sstevel@tonic-gate int cvres; 809*0Sstevel@tonic-gate 810*0Sstevel@tonic-gate if (msgflg & IPC_NOWAIT) { 811*0Sstevel@tonic-gate error = EAGAIN; 812*0Sstevel@tonic-gate goto msgsnd_out; 813*0Sstevel@tonic-gate } 814*0Sstevel@tonic-gate 815*0Sstevel@tonic-gate qp->msg_snd_cnt++; 816*0Sstevel@tonic-gate cvres = cv_wait_sig(&qp->msg_snd_cv, lock); 817*0Sstevel@tonic-gate lock = ipc_relock(msq_svc, qp->msg_perm.ipc_id, lock); 818*0Sstevel@tonic-gate qp->msg_snd_cnt--; 819*0Sstevel@tonic-gate 820*0Sstevel@tonic-gate if (IPC_FREE(&qp->msg_perm)) { 821*0Sstevel@tonic-gate error = EIDRM; 822*0Sstevel@tonic-gate goto msgsnd_out; 823*0Sstevel@tonic-gate } 824*0Sstevel@tonic-gate 825*0Sstevel@tonic-gate if (cvres == 0) { 826*0Sstevel@tonic-gate error = EINTR; 827*0Sstevel@tonic-gate goto msgsnd_out; 828*0Sstevel@tonic-gate } 829*0Sstevel@tonic-gate } 830*0Sstevel@tonic-gate 831*0Sstevel@tonic-gate if (mp == NULL) { 832*0Sstevel@tonic-gate int failure; 833*0Sstevel@tonic-gate 834*0Sstevel@tonic-gate mutex_exit(lock); 835*0Sstevel@tonic-gate mp = kmem_zalloc(sizeof (struct msg), KM_SLEEP); 836*0Sstevel@tonic-gate mp->msg_addr = kmem_zalloc(msgsz, KM_SLEEP); 837*0Sstevel@tonic-gate mp->msg_size = msgsz; 838*0Sstevel@tonic-gate mp->msg_copycnt = 1; 839*0Sstevel@tonic-gate 840*0Sstevel@tonic-gate failure = msgsz && (copyin(STRUCT_FADDR(umsgp, mtext), 841*0Sstevel@tonic-gate mp->msg_addr, msgsz) == -1); 842*0Sstevel@tonic-gate lock = ipc_lock(msq_svc, qp->msg_perm.ipc_id); 843*0Sstevel@tonic-gate if (IPC_FREE(&qp->msg_perm)) { 844*0Sstevel@tonic-gate error = EIDRM; 845*0Sstevel@tonic-gate goto msgsnd_out; 846*0Sstevel@tonic-gate } 847*0Sstevel@tonic-gate if (failure) { 848*0Sstevel@tonic-gate error = EFAULT; 849*0Sstevel@tonic-gate goto msgsnd_out; 850*0Sstevel@tonic-gate } 851*0Sstevel@tonic-gate goto top; 852*0Sstevel@tonic-gate } 853*0Sstevel@tonic-gate 854*0Sstevel@tonic-gate /* 855*0Sstevel@tonic-gate * Everything is available, put msg on q. 856*0Sstevel@tonic-gate */ 857*0Sstevel@tonic-gate qp->msg_qnum++; 858*0Sstevel@tonic-gate qp->msg_cbytes += msgsz; 859*0Sstevel@tonic-gate qp->msg_lspid = curproc->p_pid; 860*0Sstevel@tonic-gate qp->msg_stime = gethrestime_sec(); 861*0Sstevel@tonic-gate mp->msg_type = type; 862*0Sstevel@tonic-gate mp->msg_flags = 0; 863*0Sstevel@tonic-gate list_insert_tail(&qp->msg_list, mp); 864*0Sstevel@tonic-gate if (qp->msg_rcv_cnt) 865*0Sstevel@tonic-gate cv_broadcast(&qp->msg_rcv_cv); 866*0Sstevel@tonic-gate 867*0Sstevel@tonic-gate msgsnd_out: 868*0Sstevel@tonic-gate ipc_rele(msq_svc, (kipc_perm_t *)qp); /* drops lock */ 869*0Sstevel@tonic-gate 870*0Sstevel@tonic-gate if (error) { 871*0Sstevel@tonic-gate if (mp) 872*0Sstevel@tonic-gate msg_rele(mp); 873*0Sstevel@tonic-gate return (set_errno(error)); 874*0Sstevel@tonic-gate } 875*0Sstevel@tonic-gate 876*0Sstevel@tonic-gate return (0); 877*0Sstevel@tonic-gate } 878*0Sstevel@tonic-gate 879*0Sstevel@tonic-gate /* 880*0Sstevel@tonic-gate * msgsys - System entry point for msgctl, msgget, msgrcv, and msgsnd 881*0Sstevel@tonic-gate * system calls. 882*0Sstevel@tonic-gate */ 883*0Sstevel@tonic-gate static ssize_t 884*0Sstevel@tonic-gate msgsys(int opcode, uintptr_t a1, uintptr_t a2, uintptr_t a3, 885*0Sstevel@tonic-gate uintptr_t a4, uintptr_t a5) 886*0Sstevel@tonic-gate { 887*0Sstevel@tonic-gate ssize_t error; 888*0Sstevel@tonic-gate 889*0Sstevel@tonic-gate switch (opcode) { 890*0Sstevel@tonic-gate case MSGGET: 891*0Sstevel@tonic-gate error = msgget((key_t)a1, (int)a2); 892*0Sstevel@tonic-gate break; 893*0Sstevel@tonic-gate case MSGCTL: 894*0Sstevel@tonic-gate error = msgctl((int)a1, (int)a2, (void *)a3); 895*0Sstevel@tonic-gate break; 896*0Sstevel@tonic-gate case MSGRCV: 897*0Sstevel@tonic-gate error = msgrcv((int)a1, (struct ipcmsgbuf *)a2, 898*0Sstevel@tonic-gate (size_t)a3, (long)a4, (int)a5); 899*0Sstevel@tonic-gate break; 900*0Sstevel@tonic-gate case MSGSND: 901*0Sstevel@tonic-gate error = msgsnd((int)a1, (struct ipcmsgbuf *)a2, 902*0Sstevel@tonic-gate (size_t)a3, (int)a4); 903*0Sstevel@tonic-gate break; 904*0Sstevel@tonic-gate case MSGIDS: 905*0Sstevel@tonic-gate error = msgids((int *)a1, (uint_t)a2, (uint_t *)a3); 906*0Sstevel@tonic-gate break; 907*0Sstevel@tonic-gate case MSGSNAP: 908*0Sstevel@tonic-gate error = msgsnap((int)a1, (caddr_t)a2, (size_t)a3, (long)a4); 909*0Sstevel@tonic-gate break; 910*0Sstevel@tonic-gate default: 911*0Sstevel@tonic-gate error = set_errno(EINVAL); 912*0Sstevel@tonic-gate break; 913*0Sstevel@tonic-gate } 914*0Sstevel@tonic-gate 915*0Sstevel@tonic-gate return (error); 916*0Sstevel@tonic-gate } 917*0Sstevel@tonic-gate 918*0Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 919*0Sstevel@tonic-gate /* 920*0Sstevel@tonic-gate * msgsys32 - System entry point for msgctl, msgget, msgrcv, and msgsnd 921*0Sstevel@tonic-gate * system calls for 32-bit callers on LP64 kernel. 922*0Sstevel@tonic-gate */ 923*0Sstevel@tonic-gate static ssize32_t 924*0Sstevel@tonic-gate msgsys32(int opcode, uint32_t a1, uint32_t a2, uint32_t a3, 925*0Sstevel@tonic-gate uint32_t a4, uint32_t a5) 926*0Sstevel@tonic-gate { 927*0Sstevel@tonic-gate ssize_t error; 928*0Sstevel@tonic-gate 929*0Sstevel@tonic-gate switch (opcode) { 930*0Sstevel@tonic-gate case MSGGET: 931*0Sstevel@tonic-gate error = msgget((key_t)a1, (int)a2); 932*0Sstevel@tonic-gate break; 933*0Sstevel@tonic-gate case MSGCTL: 934*0Sstevel@tonic-gate error = msgctl((int)a1, (int)a2, (void *)(uintptr_t)a3); 935*0Sstevel@tonic-gate break; 936*0Sstevel@tonic-gate case MSGRCV: 937*0Sstevel@tonic-gate error = msgrcv((int)a1, (struct ipcmsgbuf *)(uintptr_t)a2, 938*0Sstevel@tonic-gate (size_t)a3, (long)(int32_t)a4, (int)a5); 939*0Sstevel@tonic-gate break; 940*0Sstevel@tonic-gate case MSGSND: 941*0Sstevel@tonic-gate error = msgsnd((int)a1, (struct ipcmsgbuf *)(uintptr_t)a2, 942*0Sstevel@tonic-gate (size_t)(int32_t)a3, (int)a4); 943*0Sstevel@tonic-gate break; 944*0Sstevel@tonic-gate case MSGIDS: 945*0Sstevel@tonic-gate error = msgids((int *)(uintptr_t)a1, (uint_t)a2, 946*0Sstevel@tonic-gate (uint_t *)(uintptr_t)a3); 947*0Sstevel@tonic-gate break; 948*0Sstevel@tonic-gate case MSGSNAP: 949*0Sstevel@tonic-gate error = msgsnap((int)a1, (caddr_t)(uintptr_t)a2, (size_t)a3, 950*0Sstevel@tonic-gate (long)(int32_t)a4); 951*0Sstevel@tonic-gate break; 952*0Sstevel@tonic-gate default: 953*0Sstevel@tonic-gate error = set_errno(EINVAL); 954*0Sstevel@tonic-gate break; 955*0Sstevel@tonic-gate } 956*0Sstevel@tonic-gate 957*0Sstevel@tonic-gate return (error); 958*0Sstevel@tonic-gate } 959*0Sstevel@tonic-gate #endif /* SYSCALL32_IMPL */ 960