DragonFlyBSD Kernel Audit
DF-0382 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/net/dummynet3/ip_dummynet3.c b/sys/net/dummynet3/ip_dummynet3.c
--- a/sys/net/dummynet3/ip_dummynet3.c
+++ b/sys/net/dummynet3/ip_dummynet3.c
@@ -1343,6 +1343,18 @@
 {
 	int i;
 
+	/*
+	 * Reject RED parameters that would divide by zero in the c_1/c_3
+	 * computations below.  c_1 divides by (max_th - min_th); c_3 (gentle
+	 * RED only) divides by max_th.  Both sinks previously lacked any
+	 * zero-divisor check (XXX "should check errors" at the caller) and a
+	 * single setsockopt could panic the kernel.  (DF-0382)
+	 */
+	if (ioc_fs->max_th <= ioc_fs->min_th)
+		return EINVAL;
+	if ((ioc_fs->flags_fs & DN_IS_GENTLE_RED) && ioc_fs->max_th == 0)
+		return EINVAL;
+
 	x->w_q = ioc_fs->w_q;
 	x->min_th = SCALE(ioc_fs->min_th);
 	x->max_th = SCALE(ioc_fs->max_th);
@@ -1432,9 +1444,11 @@
 	id->fid_flags = ioc_id->u.ip.flags;
 }
 
-static void
+static int
 set_fs_parms(struct dn_flow_set *x, const struct dn_ioc_flowset *ioc_fs)
 {
+	int error;
+
 	x->flags_fs = ioc_fs->flags_fs;
 	x->qsize = ioc_fs->qsize;
 	x->plr = ioc_fs->plr;
@@ -1448,8 +1462,12 @@
 	}
 
 	/* Configuring RED */
-	if (x->flags_fs & DN_IS_RED)
-		config_red(ioc_fs, x);	/* XXX should check errors */
+	if (x->flags_fs & DN_IS_RED) {
+		error = config_red(ioc_fs, x);	/* DF-0382: check errors */
+		if (error)
+			return error;
+	}
+	return 0;
 }
 
 /*
@@ -1520,7 +1538,9 @@
 		x->numbytes = 0; /* Just in case... */
 		x->delay = ioc_pipe->delay;
 
-		set_fs_parms(&x->fs, ioc_fs);
+		error = set_fs_parms(&x->fs, ioc_fs);
+		if (error)
+			return error;
 
 		if (x->fs.rq == NULL) {	/* A new pipe */
 			struct dn_pipe_head *pipe_hdr;
@@ -1556,8 +1576,13 @@
 			x = fs;
 		}
 
-		set_fs_parms(x, ioc_fs);
-
+		error = set_fs_parms(x, ioc_fs);
+		if (error) {
+			/* x was freshly allocated above; free it on failure. */
+			if (fs == NULL)
+				kfree(x, M_DUMMYNET);
+			return error;
+		}
 		if (x->rq == NULL) {	/* A new flow_set */
 			struct dn_flowset_head *fs_hdr;