--- a/sys/kern/sys_process.c +++ b/sys/kern/sys_process.c @@ -142,6 +142,8 @@ int write, tmp; int t; + struct ucred *tracer_cred, *target_cred; + write = 0; if (req == PT_TRACE_ME) { p = curp; @@ -150,7 +152,18 @@ if ((p = pfind(pid)) == NULL) return ESRCH; } - if (!PRISON_CHECK(curp->p_ucred, p->p_ucred)) { + /* + * Snapshot both credentials so a concurrent set*uid in either + * process cannot free them under us while we evaluate policy. + */ + tracer_cred = curp->p_ucred; + crfhold(tracer_cred); + target_cred = p->p_ucred; + crfhold(target_cred); + + if (!PRISON_CHECK(tracer_cred, target_cred)) { + crfree(target_cred); + crfree(tracer_cred); PRELE(p); return (ESRCH); } @@ -199,12 +212,14 @@ } /* not owned by you, has done setuid (unless you're root) */ - if ((p->p_ucred->cr_ruid != curp->p_ucred->cr_ruid) || + if ((target_cred->cr_ruid != tracer_cred->cr_ruid) || (p->p_flags & P_SUGID)) { - error = caps_priv_check(curp->p_ucred, + error = caps_priv_check(tracer_cred, SYSCAP_RESTRICTEDROOT); if (error) { lwkt_reltoken(&p->p_token); + crfree(target_cred); + crfree(tracer_cred); PRELE(p); return error; } @@ -213,10 +228,16 @@ /* can't trace init when securelevel > 0 */ if (securelevel > 0 && p->p_pid == 1) { lwkt_reltoken(&p->p_token); + crfree(target_cred); + crfree(tracer_cred); PRELE(p); return EPERM; } + /* permission switch complete */ + crfree(target_cred); + crfree(tracer_cred); + /* OK */ break;