DF-4743 / fix.diff
--- a/sys/dev/sound/pci/via82c686.c +++ b/sys/dev/sound/pci/via82c686.c @@ -560,7 +560,7 @@ via_attach(device_t dev) /*maxsize*/via->bufsz, /*nsegments*/1, /*maxsegz*/0x3ffff, /*flags*/0, &via->parent_dmat) != 0) { device_printf(dev, "unable to create dma tag\n"); - goto bad; + goto bad_mixer; } /* @@ -576,7 +576,7 @@ via_attach(device_t dev) /*maxsize*/NSEGS * sizeof(struct via_dma_op), /*nsegments*/1, /*maxsegz*/0x3ffff, /*flags*/0, &via->sgd_dmat) != 0) { device_printf(dev, "unable to create dma tag\n"); - goto bad; + goto bad_mixer; } if (bus_dmamem_alloc(via->sgd_dmat, (void **)&via->sgd_table, @@ -584,10 +584,10 @@ via_attach(device_t dev) BUS_DMA_NOWAIT, &via->sgd_dmamap) != 0) - goto bad; + goto bad_mixer; if (bus_dmamap_load(via->sgd_dmat, via->sgd_dmamap, via->sgd_table, NSEGS * sizeof(struct via_dma_op), dma_cb, via, 0) != 0) - goto bad; + goto bad_mixer; ksnprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld %s", rman_get_start(via->reg), rman_get_start(via->irq), PCM_KLDSTRING(snd_via82c686)); /* Register */ - if (pcm_register(dev, via, 1, 1)) goto bad; + if (pcm_register(dev, via, 1, 1)) goto bad_mixer; pcm_addchan(dev, PCMDIR_PLAY, &viachan_class, via); pcm_addchan(dev, PCMDIR_REC, &viachan_class, via); pcm_setstatus(dev, status); return 0; +bad_mixer: + /* + * mixer_init() has published a world-writable /dev/mixerN whose + * mixer holds via->codec (and through it `via`) as devinfo. Retire + * it before freeing anything, or the cdev dangles into freed memory + * (DF-4743, DF-4156 mixer-UAF family). mixer_uninit() runs + * ac97mix_uninit() -> ac97_destroy() on the codec. + */ + mixer_uninit(dev); + via->codec = NULL; /* freed by ac97mix_uninit() above */ bad: if (via->codec) ac97_destroy(via->codec); if (via->reg) bus_release_resource(dev, SYS_RES_IOPORT, via->regid, via->reg); |