diff options
author | Eric Dumazet <edumazet@google.com> | 2012-07-08 17:45:10 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-07-09 17:50:54 -0400 |
commit | 91c68ce2b26319248a32d7baa1226f819d283758 (patch) | |
tree | eeeea052a0b13d2f97435fe33caa5139e4729a53 /net | |
parent | 96ca7ffe748bf91f851e6aa4479aa11c8b1122ba (diff) |
net: cgroup: fix out of bounds accesses
dev->priomap is allocated by extend_netdev_table() called from
update_netdev_tables().
And this is only called if write_priomap() is called.
But if write_priomap() is not called, it seems we can have out of bounds
accesses in cgrp_destroy(), read_priomap() & skb_update_prio()
With help from Gao Feng
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Neil Horman <nhorman@tuxdriver.com>
Cc: Gao feng <gaofeng@cn.fujitsu.com>
Acked-by: Gao feng <gaofeng@cn.fujitsu.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/core/dev.c | 8 | ||||
-rw-r--r-- | net/core/netprio_cgroup.c | 4 |
2 files changed, 8 insertions, 4 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index 84f01ba81a34..0f28a9e0b8ad 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -2444,8 +2444,12 @@ static void skb_update_prio(struct sk_buff *skb) | |||
2444 | { | 2444 | { |
2445 | struct netprio_map *map = rcu_dereference_bh(skb->dev->priomap); | 2445 | struct netprio_map *map = rcu_dereference_bh(skb->dev->priomap); |
2446 | 2446 | ||
2447 | if ((!skb->priority) && (skb->sk) && map) | 2447 | if (!skb->priority && skb->sk && map) { |
2448 | skb->priority = map->priomap[skb->sk->sk_cgrp_prioidx]; | 2448 | unsigned int prioidx = skb->sk->sk_cgrp_prioidx; |
2449 | |||
2450 | if (prioidx < map->priomap_len) | ||
2451 | skb->priority = map->priomap[prioidx]; | ||
2452 | } | ||
2449 | } | 2453 | } |
2450 | #else | 2454 | #else |
2451 | #define skb_update_prio(skb) | 2455 | #define skb_update_prio(skb) |
diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c index aa907ed466ea..3e953eaddbfc 100644 --- a/net/core/netprio_cgroup.c +++ b/net/core/netprio_cgroup.c | |||
@@ -142,7 +142,7 @@ static void cgrp_destroy(struct cgroup *cgrp) | |||
142 | rtnl_lock(); | 142 | rtnl_lock(); |
143 | for_each_netdev(&init_net, dev) { | 143 | for_each_netdev(&init_net, dev) { |
144 | map = rtnl_dereference(dev->priomap); | 144 | map = rtnl_dereference(dev->priomap); |
145 | if (map) | 145 | if (map && cs->prioidx < map->priomap_len) |
146 | map->priomap[cs->prioidx] = 0; | 146 | map->priomap[cs->prioidx] = 0; |
147 | } | 147 | } |
148 | rtnl_unlock(); | 148 | rtnl_unlock(); |
@@ -166,7 +166,7 @@ static int read_priomap(struct cgroup *cont, struct cftype *cft, | |||
166 | rcu_read_lock(); | 166 | rcu_read_lock(); |
167 | for_each_netdev_rcu(&init_net, dev) { | 167 | for_each_netdev_rcu(&init_net, dev) { |
168 | map = rcu_dereference(dev->priomap); | 168 | map = rcu_dereference(dev->priomap); |
169 | priority = map ? map->priomap[prioidx] : 0; | 169 | priority = (map && prioidx < map->priomap_len) ? map->priomap[prioidx] : 0; |
170 | cb->fill(cb, dev->name, priority); | 170 | cb->fill(cb, dev->name, priority); |
171 | } | 171 | } |
172 | rcu_read_unlock(); | 172 | rcu_read_unlock(); |