/* This function does some common audit and permissions check for some IPC_XXX cmd and is called from semctl_down, shmctl_down and msgctl_down. It must be called without any lock held and */
struct kern_ipc_perm* ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd, struct ipc64_perm *perm, int extra_perm)
/* This function does some common audit and permissions check for some IPC_XXX cmd and is called from semctl_down, shmctl_down and msgctl_down. It must be called without any lock held and */
struct kern_ipc_perm* ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd, struct ipc64_perm *perm, int extra_perm)
{
	struct kern_ipc_perm *ipcp;
	uid_t euid;
	int err;
	down_write(&ids->rw_mutex);
	ipcp = ipc_lock_check(ids, id);
	if (IS_ERR(ipcp)) {
		err = PTR_ERR(ipcp);
		goto out_up;
	}
	audit_ipc_obj(ipcp);
	if (cmd == IPC_SET)
		audit_ipc_set_perm(extra_perm, perm->uid,
					 perm->gid, perm->mode);
	euid = current_euid();
	if (euid == ipcp->cuid ||
	    euid == ipcp->uid  || capable(CAP_SYS_ADMIN))
		return ipcp;
	err = -EPERM;
	ipc_unlock(ipcp);
out_up:
	up_write(&ids->rw_mutex);
	return ERR_PTR(err);
}