⬢ DragonFlyBSD Kernel Audit
DF-5574 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/bus/ppbus/ppb_msq.c b/sys/bus/ppbus/ppb_msq.c
--- a/sys/bus/ppbus/ppb_msq.c
+++ b/sys/bus/ppbus/ppb_msq.c
@@ -67,7 +67,7 @@
 		break;
 
 	default:
-		panic("%s: unknown opcode (%d)", __func__, opcode);
+		return (NULL);	/* DF-5576b: caller reports EINVAL */
 	}
 
 	/* retrieve the device operating mode */
@@ -90,15 +90,15 @@
 			index = EPP19_MSQ;
 			break;
 		default:
-			panic("%s: unknown EPP protocol (0x%x)!", __func__,
-				epp);
+			return (NULL);	/* DF-5576b */
 		}
 		break;
 	case PPB_ECP:
 		index = ECP_MSQ;
 		break;
 	default:
-		panic("%s: unknown mode (%d)", __func__, ppbdev->mode);
+		return (NULL);	/* DF-5576b; also retires the panic that
+				 * printed ppbdev->mode instead of the bus mode */
 	}
 
 	return (&table[index]);
@@ -116,6 +116,9 @@
 	struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev);
 	struct ppb_xfer *xfer = mode2xfer(bus, ppbdev, opcode);
 
+	if (xfer == NULL)
+		return (EINVAL);
+
 	xfer->loop = loop;
 
 	return (0);
@@ -163,7 +166,7 @@
 		  MS_SET(MS_UNKNOWN),		/* set size of transfer */
 	/* loop: */
 		  MS_CALL(0),			/* execute body */
-		  MS_DBRA(-1 /* loop: */),
+		  MS_DBRA(-2 /* loop: */),
 
 		  MS_CALL(0),			/* execute epilog */
 		  MS_RET(0)
@@ -203,6 +206,9 @@
 		type = MS_TYP(param);
 
 		/* check the instruction position */
+		if (ins >= PPB_MS_MAXLEN)
+			panic("%s: instruction out of range (%d)!",
+				__func__, ins);
 		if (arg >= PPB_MS_MAXARGS)
 			panic("%s: parameter out of range (0x%x)!",
 				__func__, param);
@@ -277,6 +283,11 @@
 			/* attempt to choose the best mode for the device */
 			xfer = mode2xfer(bus, ppbdev, mi->opcode);
 
+			if (xfer == NULL) {
+				error = EINVAL;	/* DF-5576b */
+				goto error;
+			}
+
 			/* figure out if we should use ieee1284 code */
 			if (!xfer->loop) {
 				if (mi->opcode == MS_OP_PUT) {
@@ -289,10 +300,23 @@
 					INCR_PC;
 					continue;
 				} else {
-					panic("%s: IEEE1284 read not supported", __func__);
+					/* DF-5576a: was panic() */
+					error = EOPNOTSUPP;
+					goto error;
 				}
 			}
 
+			/* DF-5574: enforce "the xfer microsequence should not
+			 * contain any MS_OP_PUT or MS_OP_GET!" -- the recursive
+			 * ppb_MS_microseq() calls below make a violating loop
+			 * recurse without any depth limit
+			 */
+			if (ppb->ppb_in_xfer) {
+				error = EINVAL;
+				goto error;
+			}
+			ppb->ppb_in_xfer = 1;
+
 			/* XXX should use ppb_MS_init_msq() */
 			initxfer[0].arg[0].p = mi->arg[0].p;
 			initxfer[1].arg[0].i = mi->arg[1].i;
@@ -300,16 +324,22 @@
 			/* initialize transfer */
 			ppb_MS_microseq(bus, dev, initxfer, &error);
 
-			if (error)
+			if (error) {
+				ppb->ppb_in_xfer = 0;
 				goto error;
+			}
 
 			/* the xfer microsequence should not contain any
 			 * MS_OP_PUT or MS_OP_GET!
 			 */
 			ppb_MS_microseq(bus, dev, xfer->loop, &error);
 
-			if (error)
+			if (error) {
+				ppb->ppb_in_xfer = 0;
 				goto error;
+			}
+
+			ppb->ppb_in_xfer = 0;
 
 			INCR_PC;
 			break;
diff --git a/sys/bus/ppbus/ppbconf.h b/sys/bus/ppbus/ppbconf.h
--- a/sys/bus/ppbus/ppbconf.h
+++ b/sys/bus/ppbus/ppbconf.h
@@ -244,6 +244,8 @@
 				 * NIBBLE, PS2, EPP or ECP */
 
 	void *ppb_owner;	/* device which owns the bus */
+
+	int ppb_in_xfer;	/* DF-5574: MS_OP_PUT/GET re-entry guard */
 };
 
 #ifdef _KERNEL