aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@vyatta.com>2012-08-14 11:19:33 -0400
committerDavid S. Miller <davem@davemloft.net>2012-08-15 18:09:41 -0400
commitc03307eab68d583ea6db917681afa14ed1fb3b84 (patch)
treed2480b2fd892254e7a37b5b757be6f2c40c2ca6b /net
parent7bab3ae7608292fd987e390dec9fc21fd6dc4d7d (diff)
bridge: fix rcu dereference outside of rcu_read_lock
Alternative solution for problem found by Linux Driver Verification project (linuxtesting.org). As it noted in the comment before the br_handle_frame_finish function, this function should be called under rcu_read_lock. The problem callgraph: br_dev_xmit -> br_nf_pre_routing_finish_bridge_slow -> -> br_handle_frame_finish -> br_port_get_rcu -> rcu_dereference And in this case there is no read-lock section. Reported-by: Denis Efremov <yefremov.denis@gmail.com> Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/bridge/br_device.c3
1 files changed, 2 insertions, 1 deletions
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 32211fa5b506..070e8a68cfc6 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -31,9 +31,11 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
31 struct net_bridge_mdb_entry *mdst; 31 struct net_bridge_mdb_entry *mdst;
32 struct br_cpu_netstats *brstats = this_cpu_ptr(br->stats); 32 struct br_cpu_netstats *brstats = this_cpu_ptr(br->stats);
33 33
34 rcu_read_lock();
34#ifdef CONFIG_BRIDGE_NETFILTER 35#ifdef CONFIG_BRIDGE_NETFILTER
35 if (skb->nf_bridge && (skb->nf_bridge->mask & BRNF_BRIDGED_DNAT)) { 36 if (skb->nf_bridge && (skb->nf_bridge->mask & BRNF_BRIDGED_DNAT)) {
36 br_nf_pre_routing_finish_bridge_slow(skb); 37 br_nf_pre_routing_finish_bridge_slow(skb);
38 rcu_read_unlock();
37 return NETDEV_TX_OK; 39 return NETDEV_TX_OK;
38 } 40 }
39#endif 41#endif
@@ -48,7 +50,6 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
48 skb_reset_mac_header(skb); 50 skb_reset_mac_header(skb);
49 skb_pull(skb, ETH_HLEN); 51 skb_pull(skb, ETH_HLEN);
50 52
51 rcu_read_lock();
52 if (is_broadcast_ether_addr(dest)) 53 if (is_broadcast_ether_addr(dest))
53 br_flood_deliver(br, skb); 54 br_flood_deliver(br, skb);
54 else if (is_multicast_ether_addr(dest)) { 55 else if (is_multicast_ether_addr(dest)) {