aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge
diff options
context:
space:
mode:
authorNikolay Aleksandrov <razor@blackwall.org>2015-06-15 13:28:51 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-07-10 12:49:28 -0400
commit08be544ef5d8453b7778bd57f3da8eeebcf1cd65 (patch)
tree00cbcdd5020fc86280580304c22ad337807827ab /net/bridge
parentbd0a0d20ebd08f250af9023530b5de4bc433ebaa (diff)
bridge: fix br_stp_set_bridge_priority race conditions
[ Upstream commit 2dab80a8b486f02222a69daca6859519e05781d9 ] After the ->set() spinlocks were removed br_stp_set_bridge_priority was left running without any protection when used via sysfs. It can race with port add/del and could result in use-after-free cases and corrupted lists. Tested by running port add/del in a loop with stp enabled while setting priority in a loop, crashes are easily reproducible. The spinlocks around sysfs ->set() were removed in commit: 14f98f258f19 ("bridge: range check STP parameters") There's also a race condition in the netlink priority support that is fixed by this change, but it was introduced recently and the fixes tag covers it, just in case it's needed the commit is: af615762e972 ("bridge: add ageing_time, stp_state, priority over netlink") Signed-off-by: Nikolay Aleksandrov <razor@blackwall.org> Fixes: 14f98f258f19 ("bridge: range check STP parameters") Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'net/bridge')
-rw-r--r--net/bridge/br_ioctl.c2
-rw-r--r--net/bridge/br_stp_if.c4
2 files changed, 3 insertions, 3 deletions
diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c
index a9a4a1b7863d..8d423bc649b9 100644
--- a/net/bridge/br_ioctl.c
+++ b/net/bridge/br_ioctl.c
@@ -247,9 +247,7 @@ static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
247 if (!ns_capable(dev_net(dev)->user_ns, CAP_NET_ADMIN)) 247 if (!ns_capable(dev_net(dev)->user_ns, CAP_NET_ADMIN))
248 return -EPERM; 248 return -EPERM;
249 249
250 spin_lock_bh(&br->lock);
251 br_stp_set_bridge_priority(br, args[1]); 250 br_stp_set_bridge_priority(br, args[1]);
252 spin_unlock_bh(&br->lock);
253 return 0; 251 return 0;
254 252
255 case BRCTL_SET_PORT_PRIORITY: 253 case BRCTL_SET_PORT_PRIORITY:
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
index 41146872c1b4..7832d07f48f6 100644
--- a/net/bridge/br_stp_if.c
+++ b/net/bridge/br_stp_if.c
@@ -243,12 +243,13 @@ bool br_stp_recalculate_bridge_id(struct net_bridge *br)
243 return true; 243 return true;
244} 244}
245 245
246/* called under bridge lock */ 246/* Acquires and releases bridge lock */
247void br_stp_set_bridge_priority(struct net_bridge *br, u16 newprio) 247void br_stp_set_bridge_priority(struct net_bridge *br, u16 newprio)
248{ 248{
249 struct net_bridge_port *p; 249 struct net_bridge_port *p;
250 int wasroot; 250 int wasroot;
251 251
252 spin_lock_bh(&br->lock);
252 wasroot = br_is_root_bridge(br); 253 wasroot = br_is_root_bridge(br);
253 254
254 list_for_each_entry(p, &br->port_list, list) { 255 list_for_each_entry(p, &br->port_list, list) {
@@ -266,6 +267,7 @@ void br_stp_set_bridge_priority(struct net_bridge *br, u16 newprio)
266 br_port_state_selection(br); 267 br_port_state_selection(br);
267 if (br_is_root_bridge(br) && !wasroot) 268 if (br_is_root_bridge(br) && !wasroot)
268 br_become_root_bridge(br); 269 br_become_root_bridge(br);
270 spin_unlock_bh(&br->lock);
269} 271}
270 272
271/* called under bridge lock */ 273/* called under bridge lock */