| From a6a0f87941e458ac0e9190643edc429ea76a9fd8 Mon Sep 17 00:00:00 2001 |
| From: Eric Dumazet <eric.dumazet@gmail.com> |
| Date: Sat, 22 May 2010 20:37:44 +0000 |
| Subject: [PATCH] net_sched: Fix qdisc_notify() |
| |
| commit 53b0f08042f04813cd1a7473dacd3edfacb28eb3 upstream. |
| |
| 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> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c |
| index 145268c..df1dbf5 100644 |
| --- a/net/sched/sch_api.c |
| +++ b/net/sched/sch_api.c |
| @@ -1196,6 +1196,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 sk_buff *oskb, struct nlmsghdr *n, |
| u32 clid, struct Qdisc *old, struct Qdisc *new) |
| { |
| @@ -1206,11 +1211,11 @@ static int qdisc_notify(struct sk_buff *oskb, struct nlmsghdr *n, |
| 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) |
| -- |
| 1.7.9.7 |
| |