⬢ DragonFlyBSD Kernel Audit
DF-2885 / fix.diff
← back to finding ↓ download raw
--- 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;