int shmctl1(struct proc *p, int shmid, int cmd, caddr_t buf, int (*ds_copyin)(const void *, void *, size_t), int (*ds_copyout)(const void *, void *, size_t)) { struct ucred *cred = p->p_ucred; struct shmid_ds inbuf, *shmseg; int error; shmseg = shm_find_segment_by_shmid(shmid); if (shmseg == NULL) return (EINVAL); switch (cmd) { case IPC_STAT: if ((error = ipcperm(cred, &shmseg->shm_perm, IPC_R)) != 0) return (error); error = ds_copyout(shmseg, buf, sizeof(inbuf)); if (error) return (error); break; case IPC_SET: if ((error = ipcperm(cred, &shmseg->shm_perm, IPC_M)) != 0) return (error); error = ds_copyin(buf, &inbuf, sizeof(inbuf)); if (error) return (error); shmseg->shm_perm.uid = inbuf.shm_perm.uid; shmseg->shm_perm.gid = inbuf.shm_perm.gid; shmseg->shm_perm.mode = (shmseg->shm_perm.mode & ~ACCESSPERMS) | (inbuf.shm_perm.mode & ACCESSPERMS); shmseg->shm_ctime = time_second; break; case IPC_RMID: if ((error = ipcperm(cred, &shmseg->shm_perm, IPC_M)) != 0) return (error); shmseg->shm_perm.key = IPC_PRIVATE; shmseg->shm_perm.mode |= SHMSEG_REMOVED; if (shmseg->shm_nattch <= 0) { shm_deallocate_segment(shmseg); shm_last_free = IPCID_TO_IX(shmid); shmsegs[shm_last_free] = NULL; } break; case SHM_LOCK: case SHM_UNLOCK: default: return (EINVAL); } return (0); }
int msgctl1(struct proc *p, int msqid, int cmd, caddr_t buf, int (*ds_copyin)(const void *, void *, size_t), int (*ds_copyout)(const void *, void *, size_t)) { struct ucred *cred = p->p_ucred; struct msqid_ds msqbuf; struct msqid_kernel *msqkptr; struct msg *msghdr; int ix, error = 0; DPRINTF(("call to msgctl(%d, %d, %p)\n", msqid, cmd, buf)); ix = IPCID_TO_IX(msqid); if (ix < 0 || ix >= msginfo.msgmni) { DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", ix, msginfo.msgmni)); return (EINVAL); } msqkptr = &msqids[ix]; if (msqkptr->u.msg_qbytes == 0) { DPRINTF(("no such msqid\n")); return (EINVAL); } if (msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) { DPRINTF(("wrong sequence number\n")); return (EINVAL); } #ifdef MAC error = mac_sysvmsq_check_msqctl(cred, msqkptr, cmd); if (error) return (error); #endif switch (cmd) { case IPC_RMID: if ((error = ipcperm(cred, &msqkptr->u.msg_perm, IPC_M)) != 0) return (error); #ifdef MAC /* * Check that the process 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 * we discover that the process cannot free a certain msghdr. * The msq will get into an inconsistent state. */ for (msghdr = msqkptr->u.msg_first; msghdr != NULL; msghdr = msghdr->msg_next) { error = mac_sysvmsq_check_msgrmid(cred, msghdr); if (error) return (error); } #endif /* Free the message headers */ msghdr = msqkptr->u.msg_first; while (msghdr != NULL) { struct msg *msghdr_tmp; /* Free the segments of each message */ msqkptr->u.msg_cbytes -= msghdr->msg_ts; msqkptr->u.msg_qnum--; msghdr_tmp = msghdr; msghdr = msghdr->msg_next; msg_freehdr(msghdr_tmp); } #ifdef DIAGNOSTIC if (msqkptr->u.msg_cbytes != 0) panic("sys_msgctl: msg_cbytes is screwed up"); if (msqkptr->u.msg_qnum != 0) panic("sys_msgctl: msg_qnum is screwed up"); #endif #ifdef MAC mac_sysvmsq_cleanup(msqkptr); #endif msqkptr->u.msg_qbytes = 0; /* Mark it as free */ wakeup(msqkptr); break; case IPC_SET: if ((error = ipcperm(cred, &msqkptr->u.msg_perm, IPC_M))) return (error); if ((error = ds_copyin(buf, &msqbuf, sizeof(msqbuf))) != 0) return (error); if (msqbuf.msg_qbytes > msqkptr->u.msg_qbytes && cred->cr_uid != 0) return (EPERM); if (msqbuf.msg_qbytes > msginfo.msgmnb) { DPRINTF(("can't increase msg_qbytes beyond %d " "(truncating)\n", msginfo.msgmnb)); /* silently restrict qbytes to system limit */ msqbuf.msg_qbytes = msginfo.msgmnb; } if (msqbuf.msg_qbytes == 0) { DPRINTF(("can't reduce msg_qbytes to 0\n")); return (EINVAL); /* non-standard errno! */ } msqkptr->u.msg_perm.uid = msqbuf.msg_perm.uid; msqkptr->u.msg_perm.gid = msqbuf.msg_perm.gid; msqkptr->u.msg_perm.mode = (msqkptr->u.msg_perm.mode & ~0777) | (msqbuf.msg_perm.mode & 0777); msqkptr->u.msg_qbytes = msqbuf.msg_qbytes; msqkptr->u.msg_ctime = time_second; break; case IPC_STAT: if ((error = ipcperm(cred, &msqkptr->u.msg_perm, IPC_R))) { DPRINTF(("requester doesn't have read access\n")); return (error); } error = ds_copyout(&msqkptr->u, buf, sizeof(struct msqid_ds)); break; default: DPRINTF(("invalid command %d\n", cmd)); return (EINVAL); } return (error); }