/* * msgctl system call. * * gets q lock (via ipc_lookup), releases before return. * may call users of msg_lock */ static int msgctl(int msgid, int cmd, void *arg) { STRUCT_DECL(msqid_ds, ds); /* SVR4 queue work area */ kmsqid_t *qp; /* ptr to associated q */ int error; struct cred *cr; model_t mdl = get_udatamodel(); struct msqid_ds64 ds64; kmutex_t *lock; proc_t *pp = curproc; STRUCT_INIT(ds, mdl); cr = CRED(); /* * Perform pre- or non-lookup actions (e.g. copyins, RMID). */ switch (cmd) { case IPC_SET: if (copyin(arg, STRUCT_BUF(ds), STRUCT_SIZE(ds))) return (set_errno(EFAULT)); break; case IPC_SET64: if (copyin(arg, &ds64, sizeof (struct msqid_ds64))) return (set_errno(EFAULT)); break; case IPC_RMID: if (error = ipc_rmid(msq_svc, msgid, cr)) return (set_errno(error)); return (0); } /* * get msqid_ds for this msgid */ if ((lock = ipc_lookup(msq_svc, msgid, (kipc_perm_t **)&qp)) == NULL) return (set_errno(EINVAL)); switch (cmd) { case IPC_SET: if (STRUCT_FGET(ds, msg_qbytes) > qp->msg_qbytes && secpolicy_ipc_config(cr) != 0) { mutex_exit(lock); return (set_errno(EPERM)); } if (error = ipcperm_set(msq_svc, cr, &qp->msg_perm, &STRUCT_BUF(ds)->msg_perm, mdl)) { mutex_exit(lock); return (set_errno(error)); } qp->msg_qbytes = STRUCT_FGET(ds, msg_qbytes); qp->msg_ctime = gethrestime_sec(); break; case IPC_STAT: if (error = ipcperm_access(&qp->msg_perm, MSG_R, cr)) { mutex_exit(lock); return (set_errno(error)); } if (qp->msg_rcv_cnt) qp->msg_perm.ipc_mode |= MSG_RWAIT; if (qp->msg_snd_cnt) qp->msg_perm.ipc_mode |= MSG_WWAIT; ipcperm_stat(&STRUCT_BUF(ds)->msg_perm, &qp->msg_perm, mdl); qp->msg_perm.ipc_mode &= ~(MSG_RWAIT|MSG_WWAIT); STRUCT_FSETP(ds, msg_first, NULL); /* kernel addr */ STRUCT_FSETP(ds, msg_last, NULL); STRUCT_FSET(ds, msg_cbytes, qp->msg_cbytes); STRUCT_FSET(ds, msg_qnum, qp->msg_qnum); STRUCT_FSET(ds, msg_qbytes, qp->msg_qbytes); STRUCT_FSET(ds, msg_lspid, qp->msg_lspid); STRUCT_FSET(ds, msg_lrpid, qp->msg_lrpid); STRUCT_FSET(ds, msg_stime, qp->msg_stime); STRUCT_FSET(ds, msg_rtime, qp->msg_rtime); STRUCT_FSET(ds, msg_ctime, qp->msg_ctime); break; case IPC_SET64: mutex_enter(&pp->p_lock); if ((ds64.msgx_qbytes > qp->msg_qbytes) && secpolicy_ipc_config(cr) != 0 && rctl_test(rc_process_msgmnb, pp->p_rctls, pp, ds64.msgx_qbytes, RCA_SAFE) & RCT_DENY) { mutex_exit(&pp->p_lock); mutex_exit(lock); return (set_errno(EPERM)); } mutex_exit(&pp->p_lock); if (error = ipcperm_set64(msq_svc, cr, &qp->msg_perm, &ds64.msgx_perm)) { mutex_exit(lock); return (set_errno(error)); } qp->msg_qbytes = ds64.msgx_qbytes; qp->msg_ctime = gethrestime_sec(); break; case IPC_STAT64: if (qp->msg_rcv_cnt) qp->msg_perm.ipc_mode |= MSG_RWAIT; if (qp->msg_snd_cnt) qp->msg_perm.ipc_mode |= MSG_WWAIT; ipcperm_stat64(&ds64.msgx_perm, &qp->msg_perm); qp->msg_perm.ipc_mode &= ~(MSG_RWAIT|MSG_WWAIT); ds64.msgx_cbytes = qp->msg_cbytes; ds64.msgx_qnum = qp->msg_qnum; ds64.msgx_qbytes = qp->msg_qbytes; ds64.msgx_lspid = qp->msg_lspid; ds64.msgx_lrpid = qp->msg_lrpid; ds64.msgx_stime = qp->msg_stime; ds64.msgx_rtime = qp->msg_rtime; ds64.msgx_ctime = qp->msg_ctime; break; default: mutex_exit(lock); return (set_errno(EINVAL)); } mutex_exit(lock); /* * Do copyout last (after releasing mutex). */ switch (cmd) { case IPC_STAT: if (copyout(STRUCT_BUF(ds), arg, STRUCT_SIZE(ds))) return (set_errno(EFAULT)); break; case IPC_STAT64: if (copyout(&ds64, arg, sizeof (struct msqid_ds64))) return (set_errno(EFAULT)); break; } return (0); }
/* * semget - Semget system call. */ static int semget(key_t key, int nsems, int semflg) { ksemid_t *sp; kmutex_t *lock; int id, error; proc_t *pp = curproc; top: if (error = ipc_get(sem_svc, key, semflg, (kipc_perm_t **)&sp, &lock)) return (set_errno(error)); if (!IPC_FREE(&sp->sem_perm)) { /* * A semaphore with the requested key exists. */ if (!((nsems >= 0) && (nsems <= sp->sem_nsems))) { mutex_exit(lock); return (set_errno(EINVAL)); } } else { /* * This is a new semaphore set. Finish initialization. */ if (nsems <= 0 || (rctl_test(rc_process_semmsl, pp->p_rctls, pp, nsems, RCA_SAFE) & RCT_DENY)) { mutex_exit(lock); mutex_exit(&pp->p_lock); ipc_cleanup(sem_svc, (kipc_perm_t *)sp); return (set_errno(EINVAL)); } mutex_exit(lock); mutex_exit(&pp->p_lock); /* * We round the allocation up to coherency granularity * so that multiple semaphore allocations won't result * in the false sharing of their sem structures. */ sp->sem_base = kmem_zalloc(P2ROUNDUP(nsems * sizeof (struct sem), 64), KM_SLEEP); sp->sem_binary = (nsems == 1); sp->sem_nsems = (ushort_t)nsems; sp->sem_ctime = gethrestime_sec(); sp->sem_otime = 0; list_create(&sp->sem_undos, sizeof (struct sem_undo), offsetof(struct sem_undo, un_list)); if (error = ipc_commit_begin(sem_svc, key, semflg, (kipc_perm_t *)sp)) { if (error == EAGAIN) goto top; return (set_errno(error)); } sp->sem_maxops = rctl_enforced_value(rc_process_semopm, pp->p_rctls, pp); if (rctl_test(rc_process_semmsl, pp->p_rctls, pp, nsems, RCA_SAFE) & RCT_DENY) { ipc_cleanup(sem_svc, (kipc_perm_t *)sp); return (set_errno(EINVAL)); } lock = ipc_commit_end(sem_svc, &sp->sem_perm); } if (audit_active) audit_ipcget(AT_IPC_SEM, (void *)sp); id = sp->sem_perm.ipc_id; mutex_exit(lock); return (id); }