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;