⬢ DragonFlyBSD Kernel Audit
DF-4421 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/sound/pci/ich.c b/sys/dev/sound/pci/ich.c
index 5736c16..7d010a3 100644
--- a/sys/dev/sound/pci/ich.c
+++ b/sys/dev/sound/pci/ich.c
@@ -1028,8 +1028,6 @@ ich_pci_attach(device_t dev)
 		break;
 	}
 
-	mixer_init(dev, ac97_getmixerclass(), sc->codec);
-
 	/* check and set VRA function */
 	extcaps = ac97_getextcaps(sc->codec);
 	sc->hasvra = extcaps & AC97_EXTCAP_VRA;
@@ -1069,6 +1067,19 @@ ich_pci_attach(device_t dev)
 	if (pcm_register(dev, sc, 1, (sc->hasmic) ? 2 : 1))
 		goto bad;
 
+	/*
+	 * pcm_register() must precede mixer_init(): mixer_init() publishes a
+	 * 0666 /dev/mixerN whose devinfo is the AC97 codec.  Were any of the
+	 * earlier failure paths (or pcm_register itself) to unwind after a
+	 * successful mixer_init(), the bad: path below would ac97_destroy()
+	 * the codec and kfree() the softc while /dev/mixerN still dispatches
+	 * ioctls into them (UAF) -- DF-4421, same family as DF-4156/DF-4193/
+	 * DF-4299/DF-4334/DF-4344.  With pcm_register() first, no failure
+	 * path remains after the mixer cdev is created.
+	 */
+	if (mixer_init(dev, ac97_getmixerclass(), sc->codec))
+		goto bad;
+
 	pcm_addchan(dev, PCMDIR_PLAY, &ichchan_class, sc);		/* play */
 	pcm_addchan(dev, PCMDIR_REC, &ichchan_class, sc);		/* record */
 	if (sc->hasmic)