fq_codel: reject silly quantum parameters
authorEric Dumazet <edumazet@google.com>
Fri, 3 Sep 2021 22:03:43 +0000 (15:03 -0700)
committerDavid S. Miller <davem@davemloft.net>
Sat, 4 Sep 2021 09:49:46 +0000 (10:49 +0100)
syzbot found that forcing a big quantum attribute would crash hosts fast,
essentially using this:

tc qd replace dev eth0 root fq_codel quantum 4294967295

This is because fq_codel_dequeue() would have to loop
~2^31 times in :

if (flow->deficit <= 0) {
flow->deficit += q->quantum;
list_move_tail(&flow->flowchain, &q->old_flows);
goto begin;
}

SFQ max quantum is 2^19 (half a megabyte)
Lets adopt a max quantum of one megabyte for FQ_CODEL.

Fixes: 4b549a2ef4be ("fq_codel: Fair Queue Codel AQM")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reported-by: syzbot <syzkaller@googlegroups.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/uapi/linux/pkt_sched.h
net/sched/sch_fq_codel.c

index 79a699f..ec88590 100644 (file)
@@ -827,6 +827,8 @@ struct tc_codel_xstats {
 
 /* FQ_CODEL */
 
+#define FQ_CODEL_QUANTUM_MAX (1 << 20)
+
 enum {
        TCA_FQ_CODEL_UNSPEC,
        TCA_FQ_CODEL_TARGET,
index c4afdd0..bb0cd6d 100644 (file)
@@ -369,6 +369,7 @@ static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt,
 {
        struct fq_codel_sched_data *q = qdisc_priv(sch);
        struct nlattr *tb[TCA_FQ_CODEL_MAX + 1];
+       u32 quantum = 0;
        int err;
 
        if (!opt)
@@ -386,6 +387,13 @@ static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt,
                    q->flows_cnt > 65536)
                        return -EINVAL;
        }
+       if (tb[TCA_FQ_CODEL_QUANTUM]) {
+               quantum = max(256U, nla_get_u32(tb[TCA_FQ_CODEL_QUANTUM]));
+               if (quantum > FQ_CODEL_QUANTUM_MAX) {
+                       NL_SET_ERR_MSG(extack, "Invalid quantum");
+                       return -EINVAL;
+               }
+       }
        sch_tree_lock(sch);
 
        if (tb[TCA_FQ_CODEL_TARGET]) {
@@ -412,8 +420,8 @@ static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt,
        if (tb[TCA_FQ_CODEL_ECN])
                q->cparams.ecn = !!nla_get_u32(tb[TCA_FQ_CODEL_ECN]);
 
-       if (tb[TCA_FQ_CODEL_QUANTUM])
-               q->quantum = max(256U, nla_get_u32(tb[TCA_FQ_CODEL_QUANTUM]));
+       if (quantum)
+               q->quantum = quantum;
 
        if (tb[TCA_FQ_CODEL_DROP_BATCH_SIZE])
                q->drop_batch_size = max(1U, nla_get_u32(tb[TCA_FQ_CODEL_DROP_BATCH_SIZE]));