⬢ DragonFlyBSD Kernel Audit
DF-4724 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/sound/pci/aureal.c
+++ b/sys/dev/sound/pci/aureal.c
@@ -629,12 +629,17 @@ au_pci_attach(device_t dev)
 	if (au_init(dev, au) == -1) {
 		device_printf(dev, "unable to initialize the card\n");
 		goto bad;
 	}
 
+	/*
+	 * NB: once mixer_init() succeeds it has published a world-writable
+	 * /dev/mixerN whose mixer holds `codec` (and through it `au`) as
+	 * devinfo.  Every later failure must mixer_uninit(dev) BEFORE au
+	 * is freed, otherwise the cdev dangles into freed memory (DF-4724,
+	 * DF-4156 mixer-UAF family).
+	 */
 	codec = AC97_CREATE(dev, au, au_ac97);
 	if (codec == NULL) goto bad;
 	if (mixer_init(dev, ac97_getmixerclass(), codec) == -1) goto bad;
 
 	if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2,
 		/*boundary*/0,
@@ -648,9 +653,15 @@ au_pci_attach(device_t dev)
 	snprintf(status, SND_STATUSLEN, "at %s 0x%lx irq %ld %s",
 		 (type[0] == SYS_RES_IOPORT)? "io" : "memory",
 		 rman_get_start(reg[0]), rman_get_start(irq),PCM_KLDSTRING(snd_aureal));
 
-	if (pcm_register(dev, au, 1, 1)) goto bad;
+	if (pcm_register(dev, au, 1, 1)) {
+		mixer_uninit(dev);	/* destroys /dev/mixerN + codec */
+		codec = NULL;
+		goto bad;
+	}
+	codec = NULL;			/* mixer owns it now */
 	/* pcm_addchan(dev, PCMDIR_REC, &au_chantemplate, au); */
 	pcm_addchan(dev, PCMDIR_PLAY, &auchan_class, au);
 	pcm_setstatus(dev, status);