⬢ DragonFlyBSD Kernel Audit
DF-4610 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/sound/pci/neomagic.c b/sys/dev/sound/pci/neomagic.c
index 6206653..5510614 100644
--- a/sys/dev/sound/pci/neomagic.c
+++ b/sys/dev/sound/pci/neomagic.c
@@ -690,10 +690,6 @@ nm_pci_attach(device_t dev)
 		goto bad;
 	}
 
-	codec = AC97_CREATE(dev, sc, nm_ac97);
-	if (codec == NULL) goto bad;
-	if (mixer_init(dev, ac97_getmixerclass(), codec) == -1) goto bad;
-
 	sc->irqid = 0;
 	sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid,
 					 RF_ACTIVE | RF_SHAREABLE);
@@ -702,11 +698,24 @@ nm_pci_attach(device_t dev)
 		goto bad;
 	}
 
+	if (pcm_register(dev, sc, 1, 1)) goto bad;
+
+	codec = AC97_CREATE(dev, sc, nm_ac97);
+	if (codec == NULL) goto bad;
+	if (mixer_init(dev, ac97_getmixerclass(), codec) == -1) {
+		/*
+		 * mixer_init() failed before the mixer cdev was
+		 * published; destroy the codec here so bad: never
+		 * frees an object a live /dev/mixerN still points at.
+		 */
+		ac97_destroy(codec);
+		codec = NULL;
+		goto bad;
+	}
+
 	ksnprintf(status, SND_STATUSLEN, "at memory 0x%lx, 0x%lx irq %ld %s",
 		 rman_get_start(sc->buf), rman_get_start(sc->reg),
 		 rman_get_start(sc->irq),PCM_KLDSTRING(snd_neomagic));
-
-	if (pcm_register(dev, sc, 1, 1)) goto bad;
 	pcm_addchan(dev, PCMDIR_REC, &nmchan_class, sc);
 	pcm_addchan(dev, PCMDIR_PLAY, &nmchan_class, sc);
 	pcm_setstatus(dev, status);
@@ -715,10 +724,10 @@ nm_pci_attach(device_t dev)
 
 bad:
 	if (codec) ac97_destroy(codec);
-	if (sc->buf) bus_release_resource(dev, SYS_RES_MEMORY, sc->bufid, sc->buf);
-	if (sc->reg) bus_release_resource(dev, SYS_RES_MEMORY, sc->regid, sc->reg);
 	if (sc->ih) bus_teardown_intr(dev, sc->irq, sc->ih);
 	if (sc->irq) bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
+	if (sc->buf) bus_release_resource(dev, SYS_RES_MEMORY, sc->bufid, sc->buf);
+	if (sc->reg) bus_release_resource(dev, SYS_RES_MEMORY, sc->regid, sc->reg);
 	kfree(sc, M_DEVBUF);
 	return ENXIO;
 }