--- 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: