⬢ DragonFlyBSD Kernel Audit
DF-2329 / fix.diff
← back to finding ↓ download raw
--- a/sys/bus/ppbus/ppbconf.c
+++ b/sys/bus/ppbus/ppbconf.c
@@ -484,14 +484,26 @@
 	while (!error) {
 		crit_enter();
 		if (ppb->ppb_owner) {
+			/*
+			 * DF-2329: ppb_release_bus's wakeup(ppb) can land
+			 * between the crit_exit() and the tsleep() -- a lost
+			 * wakeup that parks the requester forever
+			 * (uninterruptible with PPB_WAIT|PPB_NOINTR).
+			 * Interlock the sleep with the crit section (the
+			 * same tsleep_interlock/PINTERLOCKED pattern CAM's
+			 * sgread uses).
+			 */
+			tsleep_interlock(ppb, PCATCH);
 			crit_exit();
 			switch (how) {
 			case (PPB_WAIT | PPB_INTR):
-				error = tsleep(ppb, PCATCH, "ppbreq", 0);
+				error = tsleep(ppb,
+				    PCATCH | PINTERLOCKED, "ppbreq", 0);
 				break;
 
 			case (PPB_WAIT | PPB_NOINTR):
-				error = tsleep(ppb, 0, "ppbreq", 0);
+				error = tsleep(ppb, PINTERLOCKED,
+				    "ppbreq", 0);
 				break;
 
 			default: