DF-4669 / fix.diff
--- a/sys/dev/misc/snp/snp.c +++ b/sys/dev/misc/snp/snp.c @@ -134,6 +134,19 @@ lwkt_gettoken(&snp_token); snp = tp->t_sc; + if (snp == NULL) { + /* + * The snoop line discipline can be installed on a tty via + * TIOCSETD without any SNPSTTY attach. t_sc is NULL in + * that case; do not run the snoop shutdown path on it. + * (DF-4668) + */ + lwkt_reltoken(&snp_token); + lwkt_gettoken(&tp->t_token); + error = ttylclose(tp, flag); + lwkt_reltoken(&tp->t_token); + return (error); + } error = snp_down(snp); if (error != 0) { lwkt_reltoken(&snp_token); @@ -557,10 +570,27 @@ return (EBUSY); } - if (snp->snp_target == NULL) { - tpo = snp->snp_tty; - if (tpo) + /* + * Properly un-poison the previous target tty before + * re-attaching. The old guard (snp->snp_target == NULL) + * was never true on re-attach because snp_target and + * snp_tty are only ever set and cleared together, so the + * old tty kept t_sc pointing at this snoop and its line + * discipline stuck on snooplinedisc; after the snp device + * is closed that leaves a dangling t_sc which snplclose + * later dereferences (double free). (DF-4669) + */ + tpo = snp->snp_tty; + if (tpo != NULL && tpo != tp) { + lwkt_gettoken(&tpo->t_token); + if ((tpo->t_sc == (caddr_t)snp) && + (tpo->t_state & TS_SNOOP) && + tpo->t_line == snooplinedisc) { + tpo->t_sc = NULL; tpo->t_state &= ~TS_SNOOP; + tpo->t_line = snp->snp_olddisc; + } + lwkt_reltoken(&tpo->t_token); } tp->t_sc = (caddr_t)snp; |