Example #1
0
static int
shm_delete_mapping(__unused struct proc *p, struct shmmap_state *shmmap_s,
	int deallocate)
{
	struct shmid_kernel *shmseg;
	int segnum, result;
	mach_vm_size_t size;

	segnum = IPCID_TO_IX(shmmap_s->shmid);
	shmseg = &shmsegs[segnum];
	size = mach_vm_round_page(shmseg->u.shm_segsz);	/* XXX done for us? */
	if (deallocate) {
	result = mach_vm_deallocate(current_map(), shmmap_s->va, size);
	if (result != KERN_SUCCESS)
		return EINVAL;
	}
	shmmap_s->shmid = SHMID_UNALLOCATED;
	shmseg->u.shm_dtime = sysv_shmtime();
	if ((--shmseg->u.shm_nattch <= 0) &&
	    (shmseg->u.shm_perm.mode & SHMSEG_REMOVED)) {
		shm_deallocate_segment(shmseg);
		shm_last_free = segnum;
	}
	return 0;
}
/* Handle a shmdt() request. */
int
handle_shmdt(pid_t pid, int shmid) {
	struct shmid_ds *shmseg;
	int segnum;
	struct shm_handle *handle;
	struct pid_attached *pidatt;
	struct id_attached *idatt;
	struct client *cl;

	sysvd_print("shmdt pid %d shmid %d\n", pid, shmid);
	/*if (!jail_sysvipc_allowed && td->td_cmsgcred->cr_prison != NULL)
	  return (ENOSYS);
	*/

	segnum = IPCID_TO_IX(shmid);
	shmseg = &shmsegs[segnum];
	handle = shmseg->shm_internal;

	/* Check if pid is attached. */
	LIST_FOREACH(pidatt, &handle->attached_list, link)
		if (pidatt->pid == pid)
			break;
	if (!pidatt) {
		sysvd_print_err("process %d is not attached to %d (1)\n",
				pid, shmid);
		return (EINVAL);
	}
	LIST_REMOVE(pidatt, link);

	/* Remove the segment from the list of attached segments of the pid.*/
	cl = _hash_lookup(clientshash, pid);
	LIST_FOREACH(idatt, &cl->ids_attached, link)
		if (idatt->shmid == shmid)
			break;
	if (!idatt) {
		sysvd_print_err("process %d is not attached to %d (2)\n",
				pid, shmid);
		return (EINVAL);
	}
	LIST_REMOVE(idatt, link);

	shmseg->shm_dtime = time(NULL);

	/* If no other process attaced remove the segment. */
	if ((--shmseg->shm_nattch <= 0) &&
			(shmseg->shm_perm.mode & SHMSEG_REMOVED)) {
		shm_deallocate_segment(segnum);
		shm_last_free = segnum;
	}

	return (0);
}
Example #3
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);
}
Example #4
0
int
shm_delete_mapping(struct vmspace *vm, struct shmmap_state *shmmap_s)
{
	struct shmid_ds *shmseg;
	int segnum;
	size_t size;

	segnum = IPCID_TO_IX(shmmap_s->shmid);
	if (segnum < 0 || segnum >= shminfo.shmmni ||
	    (shmseg = shmsegs[segnum]) == NULL)
		return (EINVAL);
	size = round_page(shmseg->shm_segsz);
	uvm_deallocate(&vm->vm_map, shmmap_s->va, size);
	shmmap_s->shmid = -1;
	shmseg->shm_dtime = time_second;
	if ((--shmseg->shm_nattch <= 0) &&
	    (shmseg->shm_perm.mode & SHMSEG_REMOVED)) {
		shm_deallocate_segment(shmseg);
		shm_last_free = segnum;
		shmsegs[shm_last_free] = NULL;
	}
	return (0);
}
/* Handle a shmctl() request. */
int
handle_shmctl(struct shmctl_msg *shmctl_msg,
		struct cmsgcred *cred ) {
	int error = 0;
	struct shmid_ds *shmseg, *inbuf;

	/*	if (!jail_sysvipc_allowed && td->td_cmsgcred->cr_prison != NULL)
		return (ENOSYS);
		*/
	shmseg = shm_find_segment_by_shmid(shmctl_msg->shmid);

	if (shmseg == NULL) {
		error = EINVAL;
		goto done;
	}

	switch (shmctl_msg->cmd) {
		case IPC_STAT:
			sysvd_print("IPC STAT\n");
			error = ipcperm(cred, &shmseg->shm_perm, IPC_R);
			if (error) {
				sysvd_print("IPC_STAT not allowed\n");
				break;
			}
			shmctl_msg->buf = *shmseg;
			break;
		case IPC_SET:
			sysvd_print("IPC SET\n");
			error = ipcperm(cred, &shmseg->shm_perm, IPC_M);
			if (error) {
				sysvd_print("IPC_SET not allowed\n");
				break;
			}
			inbuf = &shmctl_msg->buf;

			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(NULL);
			break;
		case IPC_RMID:
			sysvd_print("IPC RMID shmid = %d\n",
					shmctl_msg->shmid);
			error = ipcperm(cred, &shmseg->shm_perm, IPC_M);
			if (error) {
				sysvd_print("IPC_RMID not allowed\n");
				break;
			}
			shmseg->shm_perm.key = IPC_PRIVATE;
			shmseg->shm_perm.mode |= SHMSEG_REMOVED;
			if (shmseg->shm_nattch <= 0) {
				shm_deallocate_segment(IPCID_TO_IX(shmctl_msg->shmid));
				shm_last_free = IPCID_TO_IX(shmctl_msg->shmid);
			}
			else {
				/* In sem and msg cases, other process must be
				 * noticed about the removal. */
				struct shm_handle *internal =
					(struct shm_handle *)shmseg->shm_internal;
				mark_segment_removed(shmctl_msg->shmid,
						internal->type);
			}
			break;
#if 0
		case SHM_LOCK:
		case SHM_UNLOCK:
#endif
		default:
			error = EINVAL;
			break;
	}
done:
	return (error);

}