⬢ DragonFlyBSD Kernel Audit
DF-4157 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/sound/pci/maestro.c
+++ b/sys/dev/sound/pci/maestro.c
@@ -1090,6 +1090,15 @@
 	cur = wp_rdapu(ch->parent, 0, APUREG_CURPTR);
 	agg_unlock(ch->parent);
 	cur -= 0xffff & ((ch->srcphys - ch->base) >> 1);
+	/*
+	 * cur is derived from device register state (APU CURPTR).  If the
+	 * register file desyncs (APUs reprogrammed or powered down while a
+	 * stale interrupt feeds), the subtraction can underflow to ~2^32 and
+	 * drive interleave() arbitrarily far past the DMA ring.  Treat any
+	 * out-of-range value as "wrapped" instead of trusting the hardware.
+	 */
+	if (cur >= ch->buflen / 2)
+		cur = 0;
 	last = ch->hwptr;
 	src2 = ch->src + ch->parent->bufsz/4;
 
@@ -1129,6 +1138,10 @@
 	cur = wp_rdapu(ch->parent, 0, APUREG_CURPTR);
 	agg_unlock(ch->parent);
 	cur -= 0xffff & ((ch->phys - ch->base) >> 1);
+	/* Same desync guard as aggch_feed_adc_stereo(); the mono ring is
+	 * buflen samples (16-bit) wide. */
+	if (cur >= ch->buflen)
+		cur = 0;
 	last = ch->hwptr;
 
 	if (cur < last) {