Esempio n. 1
0
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);
}
Esempio n. 2
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);
}