⬢ DragonFlyBSD Kernel Audit
DF-5823 / fix.diff
← back to finding ↓ download raw
--- a/sys/kern/kern_proc.c
+++ b/sys/kern/kern_proc.c
@@ -1732,19 +1732,42 @@ sysctl_kern_proc(SYSCTL_HANDLER_ARGS)
 			 */
 			switch (oid) {
 			case KERN_PROC_PGRP:
-				/* could do this by traversing pgrp */
-				if (p->p_pgrp == NULL || 
-				    p->p_pgrp->pg_id != (pid_t)name[0])
+				/*
+				 * enterpgrp()/leavepgrp() replace p_pgrp
+				 * under p_token and the trailing pgrel()
+				 * pair can free the pgrp while (p) is
+				 * still scannable here.  Read the filter
+				 * chain under p_token.
+				 */
+				lwkt_gettoken_shared(&p->p_token);
+				if (p->p_pgrp == NULL ||
+				    p->p_pgrp->pg_id != (pid_t)name[0]) {
+					lwkt_reltoken(&p->p_token);
 					continue;
+				}
+				lwkt_reltoken(&p->p_token);
 				break;
 
 			case KERN_PROC_TTY:
+				/*
+				 * p_session is a macro through p_pgrp, so
+				 * the old p_session == NULL guard could
+				 * never fire.  Walk the chain explicitly
+				 * under p_token so the session/tty cannot
+				 * be torn down mid-deref.
+				 */
+				lwkt_gettoken_shared(&p->p_token);
 				if ((p->p_flags & P_CONTROLT) == 0 ||
-				    p->p_session == NULL ||
-				    p->p_session->s_ttyp == NULL ||
-				    devid_from_dev(p->p_session->s_ttyp->t_dev) !=
-					(dev_t)name[0])
+				    p->p_pgrp == NULL ||
+				    p->p_pgrp->pg_session == NULL ||
+				    p->p_pgrp->pg_session->s_ttyp == NULL ||
+				    devid_from_dev(
+				      p->p_pgrp->pg_session->s_ttyp->t_dev) !=
+					(dev_t)name[0]) {
+					lwkt_reltoken(&p->p_token);
 					continue;
+				}
+				lwkt_reltoken(&p->p_token);
 				break;
 
 			case KERN_PROC_UID: