FreeBSD/sys/kern/kern_prot.c
/*-
 * Determine whether td may debug p.
 * Returns: 0 for permitted, an errno value otherwise
 * Locks: Sufficient locks to protect various components of td and p
 *        must be held.  td must be curthread, and a lock must
 *        be held for p.
 * References: td and p must be valid for the lifetime of the call
 */
Determine whether td may debug p.
Returns: 0 for permitted, an errno value otherwise
Locks: Sufficient locks to protect various components of td and p
must be held.  td must be curthread, and a lock must
be held for p.
References: td and p must be valid for the lifetime of the call
Determine whether td may debug p . Returns : 0 for permitted an errno value otherwise Locks : Sufficient locks to protect various components of td and p must be held . td must be curthread and a lock must be held for p . References : td and p must be valid for the lifetime of the call
int
p_candebug(struct thread *td, struct proc *p)
{
	int credentialchanged, error, grpsubset, i, uidsubset;
	KASSERT(td == curthread, ("%s: td not curthread", __func__));
	PROC_LOCK_ASSERT(p, MA_OWNED);
	if (!unprivileged_proc_debug) {
		error = priv_check(td, PRIV_DEBUG_UNPRIV);
		if (error)
			return (error);
	}
	if (td->td_proc == p)
		return (0);
	if ((error = prison_check(td->td_ucred, p->p_ucred)))
		return (error);
#ifdef MAC
	if ((error = mac_proc_check_debug(td->td_ucred, p)))
		return (error);
#endif
	if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred)))
		return (error);
	if ((error = cr_seeothergids(td->td_ucred, p->p_ucred)))
		return (error);
	grpsubset = 1;
	for (i = 0; i < p->p_ucred->cr_ngroups; i++) {
		if (!groupmember(p->p_ucred->cr_groups[i], td->td_ucred)) {
			grpsubset = 0;
			break;
		}
	}
	grpsubset = grpsubset &&
	    groupmember(p->p_ucred->cr_rgid, td->td_ucred) &&
	    groupmember(p->p_ucred->cr_svgid, td->td_ucred);
	uidsubset = (td->td_ucred->cr_uid == p->p_ucred->cr_uid &&
	    td->td_ucred->cr_uid == p->p_ucred->cr_svuid &&
	    td->td_ucred->cr_uid == p->p_ucred->cr_ruid);
	credentialchanged = (p->p_flag & P_SUGID);
	if (!grpsubset || !uidsubset) {
		error = priv_check(td, PRIV_DEBUG_DIFFCRED);
		if (error)
			return (error);
	}
	if (credentialchanged) {
		error = priv_check(td, PRIV_DEBUG_SUGID);
		if (error)
			return (error);
	}
	if (p == initproc) {
		error = securelevel_gt(td->td_ucred, 0);
		if (error)
			return (error);
	}
	if ((p->p_flag & P_INEXEC) != 0)
		return (EBUSY);
	if ((p->p_flag2 & P2_NOTRACE) != 0) {
		error = priv_check(td, PRIV_DEBUG_DENIED);
		if (error != 0)
			return (error);
	}
	return (0);
}
int p_candebug ( struct thread * td , struct proc * p ) { int credentialchanged , error , grpsubset , i , uidsubset ; KASSERT ( td == curthread , ( " " , __func__ ) ) ; PROC_LOCK_ASSERT ( p , MA_OWNED ) ; if ( ! unprivileged_proc_debug ) { error = priv_check ( td , PRIV_DEBUG_UNPRIV ) ; if ( error ) return ( error ) ; } if ( td -> td_proc == p ) return ( 0 ) ; if ( ( error = prison_check ( td -> td_ucred , p -> p_ucred ) ) ) return ( error ) ; #ifdef MAC if ( ( error = mac_proc_check_debug ( td -> td_ucred , p ) ) ) return ( error ) ; #endif if ( ( error = cr_seeotheruids ( td -> td_ucred , p -> p_ucred ) ) ) return ( error ) ; if ( ( error = cr_seeothergids ( td -> td_ucred , p -> p_ucred ) ) ) return ( error ) ; grpsubset = 1 ; for ( i = 0 ; i < p -> p_ucred -> cr_ngroups ; i ++ ) { if ( ! groupmember ( p -> p_ucred -> cr_groups [ i ] , td -> td_ucred ) ) { grpsubset = 0 ; break ; } } grpsubset = grpsubset && groupmember ( p -> p_ucred -> cr_rgid , td -> td_ucred ) && groupmember ( p -> p_ucred -> cr_svgid , td -> td_ucred ) ; uidsubset = ( td -> td_ucred -> cr_uid == p -> p_ucred -> cr_uid && td -> td_ucred -> cr_uid == p -> p_ucred -> cr_svuid && td -> td_ucred -> cr_uid == p -> p_ucred -> cr_ruid ) ; credentialchanged = ( p -> p_flag & P_SUGID ) ; if ( ! grpsubset || ! uidsubset ) { error = priv_check ( td , PRIV_DEBUG_DIFFCRED ) ; if ( error ) return ( error ) ; } if ( credentialchanged ) { error = priv_check ( td , PRIV_DEBUG_SUGID ) ; if ( error ) return ( error ) ; } if ( p == initproc ) { error = securelevel_gt ( td -> td_ucred , 0 ) ; if ( error ) return ( error ) ; } if ( ( p -> p_flag & P_INEXEC ) != 0 ) return ( EBUSY ) ; if ( ( p -> p_flag2 & P2_NOTRACE ) != 0 ) { error = priv_check ( td , PRIV_DEBUG_DENIED ) ; if ( error != 0 ) return ( error ) ; } return ( 0 ) ; }
Determine whether td may debug p.
 Returns: 0 for permitted, an errno value otherwise
 Locks: Sufficient locks to protect various components of td and p
        must be held.
Determine whether td may debug p . Returns : 0 for permitted an errno value otherwise Locks : Sufficient locks to protect various components of td and p must be held .
/*
	 * Is p's group set a subset of td's effective group set?  This
	 * includes p's egid, group access list, rgid, and svgid.
	 */ /*
	 * Are the uids present in p's credential equal to td's
	 * effective uid?  This includes p's euid, svuid, and ruid.
	 */ /*
	 * Has the credential of the process changed since the last exec()?
	 */ /*
	 * If p's gids aren't a subset, or the uids aren't a subset,
	 * or the credential has changed, require appropriate privilege
	 * for td to debug p.
	 */ /* Can't trace init when securelevel > 0. */ /*
	 * Can't trace a process that's currently exec'ing.
	 *
	 * XXX: Note, this is not a security policy decision, it's a
	 * basic correctness/functionality decision.  Therefore, this check
	 * should be moved to the caller's of p_candebug().
	 */ /* Denied explicitely */