On 12/2/20, Mateusz Guzik <m...@freebsd.org> wrote: > Author: mjg > Date: Wed Dec 2 00:48:15 2020 > New Revision: 368271 > URL: https://svnweb.freebsd.org/changeset/base/368271 > > Log: > select: make sure there are no wakeup attempts after selfdfree returns > > Prior to the patch returning selfdfree could still be racing against > doselwakeup > which set sf_si = NULL and now locks stp to wake up the other thread. > > A sufficiently unlucky pair can end up going all the way down to freeing > select-related structures before the lock/wakeup/unlock finishes. > > This started manifesting itself as crashes since select data started > getting > freed in r367714. >
Reported by: hps, mike tancsa > Modified: > head/sys/kern/sys_generic.c > > Modified: head/sys/kern/sys_generic.c > ============================================================================== > --- head/sys/kern/sys_generic.c Wed Dec 2 00:45:35 2020 > (r368270) > +++ head/sys/kern/sys_generic.c Wed Dec 2 00:48:15 2020 > (r368271) > @@ -1820,14 +1820,17 @@ doselwakeup(struct selinfo *sip, int pri) > */ > TAILQ_REMOVE(&sip->si_tdlist, sfp, sf_threads); > stp = sfp->sf_td; > - /* > - * Paired with selfdfree. > - */ > - atomic_store_rel_ptr((uintptr_t *)&sfp->sf_si, (uintptr_t)NULL); > mtx_lock(&stp->st_mtx); > stp->st_flags |= SELTD_PENDING; > cv_broadcastpri(&stp->st_wait, pri); > mtx_unlock(&stp->st_mtx); > + /* > + * Paired with selfdfree. > + * > + * Storing this only after the wakeup provides an invariant that > + * stp is not used after selfdfree returns. > + */ > + atomic_store_rel_ptr((uintptr_t *)&sfp->sf_si, (uintptr_t)NULL); > } > mtx_unlock(sip->si_mtx); > } > @@ -1837,14 +1840,18 @@ seltdinit(struct thread *td) > { > struct seltd *stp; > > - if ((stp = td->td_sel) != NULL) > - goto out; > - td->td_sel = stp = malloc(sizeof(*stp), M_SELECT, M_WAITOK|M_ZERO); > + stp = td->td_sel; > + if (stp != NULL) { > + MPASS(stp->st_flags == 0); > + MPASS(STAILQ_EMPTY(&stp->st_selq)); > + return; > + } > + stp = malloc(sizeof(*stp), M_SELECT, M_WAITOK|M_ZERO); > mtx_init(&stp->st_mtx, "sellck", NULL, MTX_DEF); > cv_init(&stp->st_wait, "select"); > -out: > stp->st_flags = 0; > STAILQ_INIT(&stp->st_selq); > + td->td_sel = stp; > } > > static int > @@ -1887,6 +1894,8 @@ seltdfini(struct thread *td) > stp = td->td_sel; > if (stp == NULL) > return; > + MPASS(stp->st_flags == 0); > + MPASS(STAILQ_EMPTY(&stp->st_selq)); > if (stp->st_free1) > free(stp->st_free1, M_SELFD); > if (stp->st_free2) > -- Mateusz Guzik <mjguzik gmail.com> _______________________________________________ svn-src-all@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"