| From foo@baz Fri Feb 23 12:01:27 CET 2018 |
| From: Nogah Frankel <nogahf@mellanox.com> |
| Date: Mon, 4 Dec 2017 13:31:11 +0200 |
| Subject: net_sched: red: Avoid illegal values |
| |
| From: Nogah Frankel <nogahf@mellanox.com> |
| |
| |
| [ Upstream commit 8afa10cbe281b10371fee5a87ab266e48d71a7f9 ] |
| |
| 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> |
| Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| include/net/red.h | 11 +++++++++++ |
| net/sched/sch_choke.c | 3 +++ |
| net/sched/sch_gred.c | 3 +++ |
| net/sched/sch_red.c | 2 ++ |
| net/sched/sch_sfq.c | 3 +++ |
| 5 files changed, 22 insertions(+) |
| |
| --- a/include/net/red.h |
| +++ b/include/net/red.h |
| @@ -167,6 +167,17 @@ static inline void red_set_vars(struct r |
| v->qcount = -1; |
| } |
| |
| +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, u32 max_P) |
| --- a/net/sched/sch_choke.c |
| +++ b/net/sched/sch_choke.c |
| @@ -431,6 +431,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 |
| @@ -388,6 +388,9 @@ static inline int gred_change_vq(struct |
| struct gred_sched *table = qdisc_priv(sch); |
| struct gred_sched_data *q = table->tab[dp]; |
| |
| + if (!red_check_params(ctl->qth_min, ctl->qth_max, ctl->Wlog)) |
| + return -EINVAL; |
| + |
| if (!q) { |
| table->tab[dp] = q = *prealloc; |
| *prealloc = NULL; |
| --- a/net/sched/sch_red.c |
| +++ b/net/sched/sch_red.c |
| @@ -199,6 +199,8 @@ static int red_change(struct Qdisc *sch, |
| max_P = tb[TCA_RED_MAX_P] ? nla_get_u32(tb[TCA_RED_MAX_P]) : 0; |
| |
| 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); |
| --- a/net/sched/sch_sfq.c |
| +++ b/net/sched/sch_sfq.c |
| @@ -653,6 +653,9 @@ static int sfq_change(struct Qdisc *sch, |
| if (ctl->divisor && |
| (!is_power_of_2(ctl->divisor) || ctl->divisor > 65536)) |
| return -EINVAL; |
| + if (ctl_v1 && !red_check_params(ctl_v1->qth_min, ctl_v1->qth_max, |
| + ctl_v1->Wlog)) |
| + return -EINVAL; |
| if (ctl_v1 && ctl_v1->qth_min) { |
| p = kmalloc(sizeof(*p), GFP_KERNEL); |
| if (!p) |