systrace_lock(); if ((strp = p->p_systrace) == NULL) { systrace_unlock(); goto nougid; }  fst = strp->parent; lockmgr(&fst->lock, LK_EXCLUSIVE, NULL, p); systrace_unlock();
systrace_redirect(int code, struct proc *p, void *v, register_t *retval){	struct sysent *callp;	struct str_process *strp;	struct str_policy *strpolicy;	struct fsystrace *fst = NULL;	struct emul *oldemul;	struct pcred *pc;	uid_t olduid;	gid_t oldgid;	int policy, error = 0, report = 0, maycontrol = 0, issuser = 0;	systrace_lock();	strp = p->p_systrace;	if (strp == NULL) {		systrace_unlock();		return (EINVAL);	}	if (code < 0 || code >= p->p_emul->e_nsysent) {		systrace_unlock();		return (EINVAL);	}	KASSERT(strp->proc == p);	fst = strp->parent;	lockmgr(&fst->lock, LK_EXCLUSIVE, NULL, p);	systrace_unlock();	/*	 * We can not monitor a SUID process unless we are root,	 * but we wait until it executes something unprivileged.	 * A non-root user may only monitor if the real uid and	 * real gid match the monitored process.  Changing the	 * uid or gid causes P_SUGID to be set.	 */	if (fst->issuser) {		maycontrol = 1;		issuser =1 ;	} else if (!(p->p_flag & P_SUGID)) {		maycontrol = fst->p_ruid == p->p_cred->p_ruid &&		    fst->p_rgid == p->p_cred->p_rgid;	}	if (!maycontrol) {		policy = SYSTR_POLICY_PERMIT;	} else {		/* Find out current policy */		if ((strpolicy = strp->policy) == NULL)			policy = SYSTR_POLICY_ASK;		else {			if (code >= strpolicy->nsysent)				policy = SYSTR_POLICY_NEVER;			else				policy = strpolicy->sysent[code];		}	}	callp = p->p_emul->e_sysent + code;	switch (policy) {	case SYSTR_POLICY_PERMIT:		break;	case SYSTR_POLICY_ASK:		/* Puts the current process to sleep, return unlocked */		error = systrace_msg_ask(fst, strp, code, callp->sy_argsize, v);		/* lock has been released in systrace_msg_ask() */		fst = NULL;		/* We might have detached by now for some reason */		if (!error && (strp = p->p_systrace) != NULL) {			/* XXX - do I need to lock here? */			if (strp->answer == SYSTR_POLICY_NEVER) {				error = strp->error;				if (strp->replace != NULL) {					free(strp->replace, M_XDATA);					strp->replace = NULL;				}			} else {				if (ISSET(strp->flags, STR_PROC_SYSCALLRES)) {					CLR(strp->flags, STR_PROC_SYSCALLRES);					report = 1;				}				/* Replace the arguments if necessary */				if (strp->replace != NULL) {					error = systrace_replace(strp, callp->sy_argsize, v);				}			}		}		break;	default:		if (policy > 0)			error = policy;		else			error = EPERM;		break;	}	if (fst) {		lockmgr(&fst->lock, LK_RELEASE, NULL, p);		fst = NULL;	}	if (error)		return (error);	oldemul = p->p_emul;	pc = p->p_cred;	olduid = pc->p_ruid;	oldgid = pc->p_rgid;			/* Elevate privileges as desired */	if (issuser) {		systrace_lock();		if ((strp = p->p_systrace) != NULL) {			if (ISSET(strp->flags, STR_PROC_SETEUID))				strp->saveuid = systrace_seteuid(p, strp->seteuid);			if (ISSET(strp->flags, STR_PROC_SETEGID))				strp->savegid = systrace_setegid(p, strp->setegid);		}		systrace_unlock();	} else		CLR(strp->flags, STR_PROC_SETEUID|STR_PROC_SETEGID);					error = (*callp->sy_call)(p, v, retval);	/* Return to old privileges */	if (issuser) {		systrace_lock();		if ((strp = p->p_systrace) != NULL) {			if (ISSET(strp->flags, STR_PROC_SETEUID)) {				if (pc->pc_ucred->cr_uid == strp->seteuid)					systrace_seteuid(p, strp->saveuid);				CLR(strp->flags, STR_PROC_SETEUID);			}			if (ISSET(strp->flags, STR_PROC_SETEGID)) {				if (pc->pc_ucred->cr_gid == strp->setegid)					systrace_setegid(p, strp->savegid);				CLR(strp->flags, STR_PROC_SETEGID);			}		}		systrace_unlock();	}	if (p->p_flag & P_SUGID) {		/* Stupid Locking not necessary */		if ((strp = p->p_systrace) == NULL ||		    (fst = strp->parent) == NULL)			return (error);		if (!fst->issuser)			return (error);	}	/* Report change in emulation */	systrace_lock();	strp = p->p_systrace;	/* See if we should force a report */	if (strp != NULL && ISSET(strp->flags, STR_PROC_REPORT)) {		CLR(strp->flags, STR_PROC_REPORT);		oldemul = NULL;	}	if (p->p_emul != oldemul && strp != NULL) {		fst = strp->parent;		lockmgr(&fst->lock, LK_EXCLUSIVE, NULL, p);		systrace_unlock();		/* Old policy is without meaning now */		if (strp->policy) {			systrace_closepolicy(fst, strp->policy);			strp->policy = NULL;		}		systrace_msg_emul(fst, strp);	} else		systrace_unlock();	/* Report if effective uid or gid changed */	if (olduid != p->p_cred->p_ruid ||	    oldgid != p->p_cred->p_rgid) {		systrace_lock();		if ((strp = p->p_systrace) == NULL) {			systrace_unlock();			goto nougid;		}		fst = strp->parent;		lockmgr(&fst->lock, LK_EXCLUSIVE, NULL, p);		systrace_unlock();		systrace_msg_ugid(fst, strp);	nougid:		;	}	/* Report result from system call */	systrace_lock();	if (report && (strp = p->p_systrace) != NULL) {		fst = strp->parent;		lockmgr(&fst->lock, LK_EXCLUSIVE, NULL, p);		systrace_unlock();		systrace_msg_result(fst, strp, error, code,		    callp->sy_argsize, v, retval);	} else		systrace_unlock();	return (error);}