DragonFlyBSD Kernel Audit
DF-2753 / fix.diff
← back to finding ↓ download raw
fix.diff for DF-2753: initialize p2->p_pgrp/p_ucred (and the rest of the
startcopy region) BEFORE proc_add_allproc() publishes the SIDL child,
and filter SIDL in pfind()/allproc_scan().  Authored after guest
verification (panic reproduced in p_trespass+0x3f, fault VA 0xa0).

--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -476,34 +476,20 @@
 				M_SUBPROC, M_WAITOK | M_ZERO);
 
 	/*
-	 * Setup linkage for kernel based threading XXX lwp.  Also add the
-	 * process to the allproclist.
+	 * Initialize the section which is copied verbatim from the parent
+	 * and install the child's credentials BEFORE the process becomes
+	 * addressable.
 	 *
-	 * The process structure is addressable after this point.
-	 */
-	if (flags & RFTHREAD) {
-		p2->p_peers = p1->p_peers;
-		p1->p_peers = p2;
-		p2->p_leader = p1->p_leader;
-	} else {
-		p2->p_leader = p2;
-	}
-	proc_add_allproc(p2);
-
-	/*
-	 * Initialize the section which is copied verbatim from the parent.
+	 * The process structure becomes addressable once proc_add_allproc()
+	 * executes, and pfind()/allproc_scan() do not filter SIDL processes.
+	 * Consumers such as kill(-1) -> p_trespass() dereference p->p_ucred,
+	 * and getsid() dereferences p->p_pgrp (via p_session), without
+	 * holding p_token.  These fields MUST be valid before publication
+	 * or a concurrent lookup can take a NULL-pointer fault.
 	 */
 	bcopy(&p1->p_startcopy, &p2->p_startcopy,
 	      ((caddr_t)&p2->p_endcopy - (caddr_t)&p2->p_startcopy));
 
-	/*
-	 * Duplicate sub-structures as needed.  Increase reference counts
-	 * on shared objects.
-	 *
-	 * NOTE: because we are now on the allproc list it is possible for
-	 *	 other consumers to gain temporary references to p2
-	 *	 (p2->p_lock can change).
-	 */
 	if (p1->p_flags & P_PROFIL)
 		startprofclock(p2);
 	p2->p_ucred = crhold(lp1->lwp_thread->td_ucred);
@@ -514,6 +500,23 @@
 	if (p2->p_args)
 		refcount_acquire(&p2->p_args->ar_ref);
 
+	/*
+	 * Setup linkage for kernel based threading XXX lwp.  Also add the
+	 * process to the allproclist.
+	 *
+	 * The process structure is addressable after this point.  Other
+	 * consumers can gain temporary references to p2 from here on
+	 * (p2->p_lock can change).
+	 */
+	if (flags & RFTHREAD) {
+		p2->p_peers = p1->p_peers;
+		p1->p_peers = p2;
+		p2->p_leader = p1->p_leader;
+	} else {
+		p2->p_leader = p2;
+	}
+	proc_add_allproc(p2);
+
 	p2->p_usched = p1->p_usched;
 	/* XXX: verify copy of the secondary iosched stuff */
 	dsched_enter_proc(p2);
--- a/sys/kern/kern_proc.c
+++ b/sys/kern/kern_proc.c
@@ -521,7 +521,7 @@
 
 	lwkt_gettoken_shared(&prg->proc_token);
 	LIST_FOREACH(p, &prg->allproc, p_list) {
-		if (p->p_stat == SZOMB)
+		if (p->p_stat == SIDL || p->p_stat == SZOMB)
 			continue;
 		if (p->p_pid == pid) {
 			PHOLD(p);
@@ -1427,7 +1427,7 @@
 			continue;
 		lwkt_gettoken(&prg->proc_token);
 		LIST_FOREACH(p, &prg->allproc, p_list) {
-			if (p->p_stat == SZOMB)
+			if (p->p_stat == SIDL || p->p_stat == SZOMB)
 				continue;
 			PHOLD(p);
 			r = callback(p, data);
@@ -1481,7 +1481,7 @@
 			continue;
 		lwkt_gettoken(&prg->proc_token);
 		LIST_FOREACH(p, &prg->allproc, p_list) {
-			if (p->p_stat == SZOMB)
+			if (p->p_stat == SIDL || p->p_stat == SZOMB)
 				continue;
 			PHOLD(p);
 			lwkt_gettoken(&p->p_token);