static int sysvmsg_modload(struct module *module, int cmd, void *arg) { int error = 0; switch (cmd) { case MOD_LOAD: error = msginit(); if (error != 0) msgunload(); break; case MOD_UNLOAD: error = msgunload(); break; case MOD_SHUTDOWN: break; default: error = EINVAL; break; } return (error); }
int msgsnd_nocancel(struct proc *p, struct msgsnd_nocancel_args *uap, int32_t *retval) { int msqid = uap->msqid; user_addr_t user_msgp = uap->msgp; size_t msgsz = (size_t)uap->msgsz; /* limit to 4G */ int msgflg = uap->msgflg; int segs_needed, eval; struct msqid_kernel *msqptr; struct msg *msghdr; short next; user_long_t msgtype; SYSV_MSG_SUBSYS_LOCK(); if (!msginit(0)) { eval = ENOMEM; goto msgsndout; } #ifdef MSG_DEBUG_OK printf("call to msgsnd(%d, 0x%qx, %ld, %d)\n", msqid, user_msgp, msgsz, msgflg); #endif AUDIT_ARG(svipc_id, msqid); msqid = IPCID_TO_IX(msqid); if (msqid < 0 || msqid >= msginfo.msgmni) { #ifdef MSG_DEBUG_OK printf("msqid (%d) out of range (0<=msqid<%d)\n", msqid, msginfo.msgmni); #endif eval = EINVAL; goto msgsndout; } msqptr = &msqids[msqid]; if (msqptr->u.msg_qbytes == 0) { #ifdef MSG_DEBUG_OK printf("no such message queue id\n"); #endif eval = EINVAL; goto msgsndout; } if (msqptr->u.msg_perm._seq != IPCID_TO_SEQ(uap->msqid)) { #ifdef MSG_DEBUG_OK printf("wrong sequence number\n"); #endif eval = EINVAL; goto msgsndout; } if ((eval = ipcperm(kauth_cred_get(), &msqptr->u.msg_perm, IPC_W))) { #ifdef MSG_DEBUG_OK printf("requester doesn't have write access\n"); #endif goto msgsndout; } #if CONFIG_MACF eval = mac_sysvmsq_check_msqsnd(kauth_cred_get(), msqptr); if (eval) goto msgsndout; #endif segs_needed = (msgsz + msginfo.msgssz - 1) / msginfo.msgssz; #ifdef MSG_DEBUG_OK printf("msgsz=%ld, msgssz=%d, segs_needed=%d\n", msgsz, msginfo.msgssz, segs_needed); #endif /* * If we suffer resource starvation, we will sleep in this loop and * wait for more resources to become available. This is a loop to * ensure reacquisition of the mutex following any sleep, since there * are multiple resources under contention. */ for (;;) { void *blocking_resource = NULL; /* * Check that we have not had the maximum message size change * out from under us and render our message invalid while we * slept waiting for some resource. */ if (msgsz > msqptr->u.msg_qbytes) { #ifdef MSG_DEBUG_OK printf("msgsz > msqptr->msg_qbytes\n"); #endif eval = EINVAL; goto msgsndout; } /* * If the user_msqid_ds is already locked, we need to sleep on * the queue until it's unlocked. */ if (msqptr->u.msg_perm.mode & MSG_LOCKED) { #ifdef MSG_DEBUG_OK printf("msqid is locked\n"); #endif blocking_resource = msqptr; } /* * If our message plus the messages already in the queue would * cause us to exceed the maximum number of bytes wer are * permitted to queue, then block on the queue until it drains. */ if (msgsz + msqptr->u.msg_cbytes > msqptr->u.msg_qbytes) { #ifdef MSG_DEBUG_OK printf("msgsz + msg_cbytes > msg_qbytes\n"); #endif blocking_resource = msqptr; } /* * Both message maps and message headers are protected by * sleeping on the address of the pointer to the list of free * message headers, since they are allocated and freed in * tandem. */ if (segs_needed > nfree_msgmaps) { #ifdef MSG_DEBUG_OK printf("segs_needed > nfree_msgmaps\n"); #endif blocking_resource = &free_msghdrs; } if (free_msghdrs == NULL) { #ifdef MSG_DEBUG_OK printf("no more msghdrs\n"); #endif blocking_resource = &free_msghdrs; } if (blocking_resource != NULL) { int we_own_it; if ((msgflg & IPC_NOWAIT) != 0) { #ifdef MSG_DEBUG_OK printf("need more resources but caller doesn't want to wait\n"); #endif eval = EAGAIN; goto msgsndout; } if ((msqptr->u.msg_perm.mode & MSG_LOCKED) != 0) { #ifdef MSG_DEBUG_OK printf("we don't own the user_msqid_ds\n"); #endif we_own_it = 0; } else { /* Force later arrivals to wait for our request */ #ifdef MSG_DEBUG_OK printf("we own the user_msqid_ds\n"); #endif msqptr->u.msg_perm.mode |= MSG_LOCKED; we_own_it = 1; } #ifdef MSG_DEBUG_OK printf("goodnight\n"); #endif eval = msleep(blocking_resource, &sysv_msg_subsys_mutex, (PZERO - 4) | PCATCH, "msgwait", 0); #ifdef MSG_DEBUG_OK printf("good morning, eval=%d\n", eval); #endif if (we_own_it) msqptr->u.msg_perm.mode &= ~MSG_LOCKED; if (eval != 0) { #ifdef MSG_DEBUG_OK printf("msgsnd: interrupted system call\n"); #endif eval = EINTR; goto msgsndout; } /* * Make sure that the msq queue still exists */ if (msqptr->u.msg_qbytes == 0) { #ifdef MSG_DEBUG_OK printf("msqid deleted\n"); #endif eval = EIDRM; goto msgsndout; } } else { #ifdef MSG_DEBUG_OK printf("got all the resources that we need\n"); #endif break; } } /* * We have the resources that we need. * Make sure! */ if (msqptr->u.msg_perm.mode & MSG_LOCKED) panic("msg_perm.mode & MSG_LOCKED"); if (segs_needed > nfree_msgmaps) panic("segs_needed > nfree_msgmaps"); if (msgsz + msqptr->u.msg_cbytes > msqptr->u.msg_qbytes) panic("msgsz + msg_cbytes > msg_qbytes"); if (free_msghdrs == NULL) panic("no more msghdrs"); /* * Re-lock the user_msqid_ds in case we page-fault when copying in * the message */ if ((msqptr->u.msg_perm.mode & MSG_LOCKED) != 0) panic("user_msqid_ds is already locked"); msqptr->u.msg_perm.mode |= MSG_LOCKED; /* * Allocate a message header */ msghdr = free_msghdrs; free_msghdrs = msghdr->msg_next; msghdr->msg_spot = -1; msghdr->msg_ts = msgsz; #if CONFIG_MACF mac_sysvmsg_label_associate(kauth_cred_get(), msqptr, msghdr); #endif /* * Allocate space for the message */ while (segs_needed > 0) { if (nfree_msgmaps <= 0) panic("not enough msgmaps"); if (free_msgmaps == -1) panic("nil free_msgmaps"); next = free_msgmaps; if (next <= -1) panic("next too low #1"); if (next >= msginfo.msgseg) panic("next out of range #1"); #ifdef MSG_DEBUG_OK printf("allocating segment %d to message\n", next); #endif free_msgmaps = msgmaps[next].next; nfree_msgmaps--; msgmaps[next].next = msghdr->msg_spot; msghdr->msg_spot = next; segs_needed--; } /* * Copy in the message type. For a 64 bit process, this is 64 bits, * but we only ever use the low 32 bits, so the cast is OK. */ if (IS_64BIT_PROCESS(p)) { SYSV_MSG_SUBSYS_UNLOCK(); eval = copyin(user_msgp, &msgtype, sizeof(msgtype)); SYSV_MSG_SUBSYS_LOCK(); msghdr->msg_type = CAST_DOWN(long,msgtype); user_msgp = user_msgp + sizeof(msgtype); /* ptr math */ } else {
int msgctl(struct proc *p, struct msgctl_args *uap, int32_t *retval) { int msqid = uap->msqid; int cmd = uap->cmd; kauth_cred_t cred = kauth_cred_get(); int rval, eval; struct user_msqid_ds msqbuf; struct msqid_kernel *msqptr; SYSV_MSG_SUBSYS_LOCK(); if (!msginit(0)) { eval = ENOMEM; goto msgctlout; } #ifdef MSG_DEBUG_OK printf("call to msgctl(%d, %d, 0x%qx)\n", msqid, cmd, uap->buf); #endif AUDIT_ARG(svipc_cmd, cmd); AUDIT_ARG(svipc_id, msqid); msqid = IPCID_TO_IX(msqid); if (msqid < 0 || msqid >= msginfo.msgmni) { #ifdef MSG_DEBUG_OK printf("msqid (%d) out of range (0<=msqid<%d)\n", msqid, msginfo.msgmni); #endif eval = EINVAL; goto msgctlout; } msqptr = &msqids[msqid]; if (msqptr->u.msg_qbytes == 0) { #ifdef MSG_DEBUG_OK printf("no such msqid\n"); #endif eval = EINVAL; goto msgctlout; } if (msqptr->u.msg_perm._seq != IPCID_TO_SEQ(uap->msqid)) { #ifdef MSG_DEBUG_OK printf("wrong sequence number\n"); #endif eval = EINVAL; goto msgctlout; } #if CONFIG_MACF eval = mac_sysvmsq_check_msqctl(kauth_cred_get(), msqptr, cmd); if (eval) goto msgctlout; #endif eval = 0; rval = 0; switch (cmd) { case IPC_RMID: { struct msg *msghdr; if ((eval = ipcperm(cred, &msqptr->u.msg_perm, IPC_M))) goto msgctlout; #if CONFIG_MACF /* * Check that the thread has MAC access permissions to * individual msghdrs. Note: We need to do this in a * separate loop because the actual loop alters the * msq/msghdr info as it progresses, and there is no going * back if half the way through we discover that the * thread cannot free a certain msghdr. The msq will get * into an inconsistent state. */ for (msghdr = msqptr->u.msg_first; msghdr != NULL; msghdr = msghdr->msg_next) { eval = mac_sysvmsq_check_msgrmid(kauth_cred_get(), msghdr); if (eval) goto msgctlout; } #endif /* Free the message headers */ msghdr = msqptr->u.msg_first; while (msghdr != NULL) { struct msg *msghdr_tmp; /* Free the segments of each message */ msqptr->u.msg_cbytes -= msghdr->msg_ts; msqptr->u.msg_qnum--; msghdr_tmp = msghdr; msghdr = msghdr->msg_next; msg_freehdr(msghdr_tmp); } if (msqptr->u.msg_cbytes != 0) panic("msg_cbytes is messed up"); if (msqptr->u.msg_qnum != 0) panic("msg_qnum is messed up"); msqptr->u.msg_qbytes = 0; /* Mark it as free */ #if CONFIG_MACF mac_sysvmsq_label_recycle(msqptr); #endif wakeup((caddr_t)msqptr); } break; case IPC_SET: if ((eval = ipcperm(cred, &msqptr->u.msg_perm, IPC_M))) goto msgctlout; SYSV_MSG_SUBSYS_UNLOCK(); if (IS_64BIT_PROCESS(p)) { struct user64_msqid_ds tmpds; eval = copyin(uap->buf, &tmpds, sizeof(tmpds)); msqid_ds_user64tokernel(&tmpds, &msqbuf); } else { struct user32_msqid_ds tmpds; eval = copyin(uap->buf, &tmpds, sizeof(tmpds)); msqid_ds_user32tokernel(&tmpds, &msqbuf); } if (eval) return(eval); SYSV_MSG_SUBSYS_LOCK(); if (msqbuf.msg_qbytes > msqptr->u.msg_qbytes) { eval = suser(cred, &p->p_acflag); if (eval) goto msgctlout; } /* compare (msglen_t) value against restrict (int) value */ if (msqbuf.msg_qbytes > (user_msglen_t)msginfo.msgmnb) { #ifdef MSG_DEBUG_OK printf("can't increase msg_qbytes beyond %d (truncating)\n", msginfo.msgmnb); #endif msqbuf.msg_qbytes = msginfo.msgmnb; /* silently restrict qbytes to system limit */ } if (msqbuf.msg_qbytes == 0) { #ifdef MSG_DEBUG_OK printf("can't reduce msg_qbytes to 0\n"); #endif eval = EINVAL; goto msgctlout; } msqptr->u.msg_perm.uid = msqbuf.msg_perm.uid; /* change the owner */ msqptr->u.msg_perm.gid = msqbuf.msg_perm.gid; /* change the owner */ msqptr->u.msg_perm.mode = (msqptr->u.msg_perm.mode & ~0777) | (msqbuf.msg_perm.mode & 0777); msqptr->u.msg_qbytes = msqbuf.msg_qbytes; msqptr->u.msg_ctime = sysv_msgtime(); break; case IPC_STAT: if ((eval = ipcperm(cred, &msqptr->u.msg_perm, IPC_R))) { #ifdef MSG_DEBUG_OK printf("requester doesn't have read access\n"); #endif goto msgctlout; } SYSV_MSG_SUBSYS_UNLOCK(); if (IS_64BIT_PROCESS(p)) { struct user64_msqid_ds msqid_ds64 = {}; msqid_ds_kerneltouser64(&msqptr->u, &msqid_ds64); eval = copyout(&msqid_ds64, uap->buf, sizeof(msqid_ds64)); } else { struct user32_msqid_ds msqid_ds32 = {}; msqid_ds_kerneltouser32(&msqptr->u, &msqid_ds32); eval = copyout(&msqid_ds32, uap->buf, sizeof(msqid_ds32)); } SYSV_MSG_SUBSYS_LOCK(); break; default: #ifdef MSG_DEBUG_OK printf("invalid command %d\n", cmd); #endif eval = EINVAL; goto msgctlout; } if (eval == 0) *retval = rval; msgctlout: SYSV_MSG_SUBSYS_UNLOCK(); return(eval); }
int msgget(__unused struct proc *p, struct msgget_args *uap, int32_t *retval) { int msqid, eval; int key = uap->key; int msgflg = uap->msgflg; kauth_cred_t cred = kauth_cred_get(); struct msqid_kernel *msqptr = NULL; SYSV_MSG_SUBSYS_LOCK(); if (!msginit(0)) { eval = ENOMEM; goto msggetout; } #ifdef MSG_DEBUG_OK printf("msgget(0x%x, 0%o)\n", key, msgflg); #endif if (key != IPC_PRIVATE) { for (msqid = 0; msqid < msginfo.msgmni; msqid++) { msqptr = &msqids[msqid]; if (msqptr->u.msg_qbytes != 0 && msqptr->u.msg_perm._key == key) break; } if (msqid < msginfo.msgmni) { #ifdef MSG_DEBUG_OK printf("found public key\n"); #endif if ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL)) { #ifdef MSG_DEBUG_OK printf("not exclusive\n"); #endif eval = EEXIST; goto msggetout; } if ((eval = ipcperm(cred, &msqptr->u.msg_perm, msgflg & 0700 ))) { #ifdef MSG_DEBUG_OK printf("requester doesn't have 0%o access\n", msgflg & 0700); #endif goto msggetout; } #if CONFIG_MACF eval = mac_sysvmsq_check_msqget(cred, msqptr); if (eval) goto msggetout; #endif goto found; } } #ifdef MSG_DEBUG_OK printf("need to allocate the user_msqid_ds\n"); #endif if (key == IPC_PRIVATE || (msgflg & IPC_CREAT)) { for (msqid = 0; msqid < msginfo.msgmni; msqid++) { /* * Look for an unallocated and unlocked user_msqid_ds. * user_msqid_ds's can be locked by msgsnd or msgrcv * while they are copying the message in/out. We * can't re-use the entry until they release it. */ msqptr = &msqids[msqid]; if (msqptr->u.msg_qbytes == 0 && (msqptr->u.msg_perm.mode & MSG_LOCKED) == 0) break; } if (msqid == msginfo.msgmni) { #ifdef MSG_DEBUG_OK printf("no more user_msqid_ds's available\n"); #endif eval = ENOSPC; goto msggetout; } #ifdef MSG_DEBUG_OK printf("msqid %d is available\n", msqid); #endif msqptr->u.msg_perm._key = key; msqptr->u.msg_perm.cuid = kauth_cred_getuid(cred); msqptr->u.msg_perm.uid = kauth_cred_getuid(cred); msqptr->u.msg_perm.cgid = kauth_cred_getgid(cred); msqptr->u.msg_perm.gid = kauth_cred_getgid(cred); msqptr->u.msg_perm.mode = (msgflg & 0777); /* Make sure that the returned msqid is unique */ msqptr->u.msg_perm._seq++; msqptr->u.msg_first = NULL; msqptr->u.msg_last = NULL; msqptr->u.msg_cbytes = 0; msqptr->u.msg_qnum = 0; msqptr->u.msg_qbytes = msginfo.msgmnb; msqptr->u.msg_lspid = 0; msqptr->u.msg_lrpid = 0; msqptr->u.msg_stime = 0; msqptr->u.msg_rtime = 0; msqptr->u.msg_ctime = sysv_msgtime(); #if CONFIG_MACF mac_sysvmsq_label_associate(cred, msqptr); #endif } else { #ifdef MSG_DEBUG_OK printf("didn't find it and wasn't asked to create it\n"); #endif eval = ENOENT; goto msggetout; } found: /* Construct the unique msqid */ *retval = IXSEQ_TO_IPCID(msqid, msqptr->u.msg_perm); AUDIT_ARG(svipc_id, *retval); eval = 0; msggetout: SYSV_MSG_SUBSYS_UNLOCK(); return(eval); }
static int readtrack(void) /* read a track chunk */ { /* This array is indexed by the high half of a status byte. It's */ /* value is either the number of bytes needed (1 or 2) for a channel */ /* message, or 0 (meaning it's not a channel message). */ static int chantype[] = { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 through 0x70 */ 2, 2, 2, 2, 1, 1, 2, 0 /* 0x80 through 0xf0 */ }; long lookfor; int c, c1, type; int sysexcontinue = 0; /* 1 if last message was an unfinished sysex */ int running = 0; /* 1 when running status used */ int status = 0; /* status value (e.g. 0x90==note-on) */ int needed; if (readmt("MTrk") == EOF) return(0); Mf_toberead = read32bit(); Mf_currtime = 0; if (Mf_starttrack) (*Mf_starttrack)(); while (Mf_toberead > 0) { Mf_currtime += readvarinum(); /* delta time */ c = egetc(); if (sysexcontinue && c != 0xf7) mferror("didn't find expected continuation of a sysex"); if ((c & 0x80) == 0) { /* running status? */ if (status == 0) mferror("unexpected running status"); running = 1; c1 = c; c = status; } else if (c < 0xf0) { status = c; running = 0; } needed = chantype[(c>>4) & 0xf]; if (needed) { /* ie. is it a channel message? */ if (! running) c1 = egetc(); chanmessage(status, c1, (needed>1) ? egetc() : 0); continue;; } switch (c) { case 0xff: /* meta event */ type = egetc(); lookfor = Mf_toberead - readvarinum(); msginit(); while (Mf_toberead > lookfor) msgadd(egetc()); metaevent(type); break; case 0xf0: /* start of system exclusive */ lookfor = Mf_toberead - readvarinum(); msginit(); msgadd(0xf0); while (Mf_toberead > lookfor) msgadd(c = egetc()); if (c == 0xf7 || Mf_nomerge == 0) sysex(); else sysexcontinue = 1; /* merge into next msg */ break; case 0xf7: /* sysex continuation or arbitrary stuff */ lookfor = Mf_toberead - readvarinum(); if (! sysexcontinue) msginit(); while (Mf_toberead > lookfor) msgadd(c=egetc()); if ( ! sysexcontinue ) { if (Mf_arbitrary) (*Mf_arbitrary)(msgleng(),msg()); } else if (c == 0xf7) { sysex(); sysexcontinue = 0; } break; default: badbyte(c); break; } } if (Mf_endtrack) (*Mf_endtrack)(); return(1); }