net_sched: Fix qdisc_notify()
authorEric Dumazet <eric.dumazet@gmail.com>
Sat, 22 May 2010 20:37:44 +0000 (20:37 +0000)
committerDavid S. Miller <davem@davemloft.net>
Mon, 24 May 2010 06:11:07 +0000 (23:11 -0700)
Ben Pfaff reported a kernel oops and provided a test program to
reproduce it.

https://kerneltrap.org/mailarchive/linux-netdev/2010/5/21/6277805

tc_fill_qdisc() should not be called for builtin qdisc, or it
dereference a NULL pointer to get device ifindex.

Fix is to always use tc_qdisc_dump_ignore() before calling
tc_fill_qdisc().

Reported-by: Ben Pfaff <blp@nicira.com>
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/sched/sch_api.c

index fe35c1f338c2b25d7c2a4e4ae19123bf4023f6b5..b9e8c3b7d406aacd9cc2319ddbffe0440cc6c311 100644 (file)
@@ -1195,6 +1195,11 @@ nla_put_failure:
        return -1;
 }
 
+static bool tc_qdisc_dump_ignore(struct Qdisc *q)
+{
+       return (q->flags & TCQ_F_BUILTIN) ? true : false;
+}
+
 static int qdisc_notify(struct net *net, struct sk_buff *oskb,
                        struct nlmsghdr *n, u32 clid,
                        struct Qdisc *old, struct Qdisc *new)
@@ -1206,11 +1211,11 @@ static int qdisc_notify(struct net *net, struct sk_buff *oskb,
        if (!skb)
                return -ENOBUFS;
 
-       if (old && old->handle) {
+       if (old && !tc_qdisc_dump_ignore(old)) {
                if (tc_fill_qdisc(skb, old, clid, pid, n->nlmsg_seq, 0, RTM_DELQDISC) < 0)
                        goto err_out;
        }
-       if (new) {
+       if (new && !tc_qdisc_dump_ignore(new)) {
                if (tc_fill_qdisc(skb, new, clid, pid, n->nlmsg_seq, old ? NLM_F_REPLACE : 0, RTM_NEWQDISC) < 0)
                        goto err_out;
        }
@@ -1223,11 +1228,6 @@ err_out:
        return -EINVAL;
 }
 
-static bool tc_qdisc_dump_ignore(struct Qdisc *q)
-{
-       return (q->flags & TCQ_F_BUILTIN) ? true : false;
-}
-
 static int tc_dump_qdisc_root(struct Qdisc *root, struct sk_buff *skb,
                              struct netlink_callback *cb,
                              int *q_idx_p, int s_q_idx)