[PATCH 3.2 031/140] net_sched: red: Avoid illegal values

Ben Hutchings
2018-02-28T15:27:11Z

From: Nogah Frankel <nogahf@mellanox.com>

commit 8afa10cbe281b10371fee5a87ab266e48d71a7f9 upstream.

Check the qmin & qmax values doesn't overflow for the given Wlog value.
Check that qmin <= qmax.

Fixes: a783474591f2 ("[PKT_SCHED]: Generic RED layer")
Signed-off-by: Nogah Frankel <nogahf@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
[bwh: Backported to 3.2:
- Drop changes in sch_sfq
- Adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
--- a/include/net/red.h
+++ b/include/net/red.h
@@ -124,6 +124,17 @@ static inline u32 red_rmask(u8 Plog)
return Plog < 32 ? ((1 << Plog) - 1) : ~0UL;
}

+static inline bool red_check_params(u32 qth_min, u32 qth_max, u8 Wlog)
+{
+ if (fls(qth_min) + Wlog > 32)
+ return false;
+ if (fls(qth_max) + Wlog > 32)
+ return false;
+ if (qth_max < qth_min)
+ return false;
+ return true;
+}
+
static inline void red_set_parms(struct red_parms *p,
u32 qth_min, u32 qth_max, u8 Wlog, u8 Plog,
u8 Scell_log, u8 *stab)
--- a/net/sched/sch_choke.c
+++ b/net/sched/sch_choke.c
@@ -479,6 +479,9 @@ static int choke_change(struct Qdisc *sc

ctl = nla_data(tb[TCA_CHOKE_PARMS]);

+ if (!red_check_params(ctl->qth_min, ctl->qth_max, ctl->Wlog))
+ return -EINVAL;
+
if (ctl->limit > CHOKE_MAX_QUEUE)
return -EINVAL;

--- a/net/sched/sch_gred.c
+++ b/net/sched/sch_gred.c
@@ -384,6 +384,9 @@ static inline int gred_change_vq(struct
struct gred_sched *table = qdisc_priv(sch);
struct gred_sched_data *q;

+ if (!red_check_params(ctl->qth_min, ctl->qth_max, ctl->Wlog))
+ return -EINVAL;
+
if (table->tab[dp] == NULL) {
table->tab[dp] = kzalloc(sizeof(*q), GFP_ATOMIC);
if (table->tab[dp] == NULL)
--- a/net/sched/sch_red.c
+++ b/net/sched/sch_red.c
@@ -189,6 +189,8 @@ static int red_change(struct Qdisc *sch,
return -EINVAL;

ctl = nla_data(tb[TCA_RED_PARMS]);
+ if (!red_check_params(ctl->qth_min, ctl->qth_max, ctl->Wlog))
+ return -EINVAL;

if (ctl->limit > 0) {
child = fifo_create_dflt(sch, &bfifo_qdisc_ops, ctl->limit);