diff options
author | Stephen Hemminger <shemminger@vyatta.com> | 2012-08-14 08:19:33 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-08-15 15:09:41 -0700 |
commit | c03307eab68d583ea6db917681afa14ed1fb3b84 (patch) | |
tree | d2480b2fd892254e7a37b5b757be6f2c40c2ca6b /net | |
parent | 7bab3ae7608292fd987e390dec9fc21fd6dc4d7d (diff) | |
download | linux-c03307eab68d583ea6db917681afa14ed1fb3b84.tar.gz linux-c03307eab68d583ea6db917681afa14ed1fb3b84.tar.bz2 linux-c03307eab68d583ea6db917681afa14ed1fb3b84.zip |
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.c | 3 |
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) struct net_bridge_mdb_entry *mdst; struct br_cpu_netstats *brstats = this_cpu_ptr(br->stats); + rcu_read_lock(); #ifdef CONFIG_BRIDGE_NETFILTER if (skb->nf_bridge && (skb->nf_bridge->mask & BRNF_BRIDGED_DNAT)) { br_nf_pre_routing_finish_bridge_slow(skb); + rcu_read_unlock(); return NETDEV_TX_OK; } #endif @@ -48,7 +50,6 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) skb_reset_mac_header(skb); skb_pull(skb, ETH_HLEN); - rcu_read_lock(); if (is_broadcast_ether_addr(dest)) br_flood_deliver(br, skb); else if (is_multicast_ether_addr(dest)) { |