]>
Commit | Line | Data |
---|---|---|
da495922 GKH |
1 | From foo@baz Fri Jul 3 19:59:52 PDT 2015 |
2 | From: Nikolay Aleksandrov <razor@blackwall.org> | |
3 | Date: Mon, 15 Jun 2015 20:28:51 +0300 | |
4 | Subject: bridge: fix br_stp_set_bridge_priority race conditions | |
5 | ||
6 | From: Nikolay Aleksandrov <razor@blackwall.org> | |
7 | ||
8 | [ Upstream commit 2dab80a8b486f02222a69daca6859519e05781d9 ] | |
9 | ||
10 | After the ->set() spinlocks were removed br_stp_set_bridge_priority | |
11 | was left running without any protection when used via sysfs. It can | |
12 | race with port add/del and could result in use-after-free cases and | |
13 | corrupted lists. Tested by running port add/del in a loop with stp | |
14 | enabled while setting priority in a loop, crashes are easily | |
15 | reproducible. | |
16 | The spinlocks around sysfs ->set() were removed in commit: | |
17 | 14f98f258f19 ("bridge: range check STP parameters") | |
18 | There's also a race condition in the netlink priority support that is | |
19 | fixed by this change, but it was introduced recently and the fixes tag | |
20 | covers it, just in case it's needed the commit is: | |
21 | af615762e972 ("bridge: add ageing_time, stp_state, priority over netlink") | |
22 | ||
23 | Signed-off-by: Nikolay Aleksandrov <razor@blackwall.org> | |
24 | Fixes: 14f98f258f19 ("bridge: range check STP parameters") | |
25 | Signed-off-by: David S. Miller <davem@davemloft.net> | |
26 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
27 | --- | |
28 | net/bridge/br_ioctl.c | 2 -- | |
29 | net/bridge/br_stp_if.c | 4 +++- | |
30 | 2 files changed, 3 insertions(+), 3 deletions(-) | |
31 | ||
32 | --- a/net/bridge/br_ioctl.c | |
33 | +++ b/net/bridge/br_ioctl.c | |
34 | @@ -247,9 +247,7 @@ static int old_dev_ioctl(struct net_devi | |
35 | if (!ns_capable(dev_net(dev)->user_ns, CAP_NET_ADMIN)) | |
36 | return -EPERM; | |
37 | ||
38 | - spin_lock_bh(&br->lock); | |
39 | br_stp_set_bridge_priority(br, args[1]); | |
40 | - spin_unlock_bh(&br->lock); | |
41 | return 0; | |
42 | ||
43 | case BRCTL_SET_PORT_PRIORITY: | |
44 | --- a/net/bridge/br_stp_if.c | |
45 | +++ b/net/bridge/br_stp_if.c | |
46 | @@ -243,12 +243,13 @@ bool br_stp_recalculate_bridge_id(struct | |
47 | return true; | |
48 | } | |
49 | ||
50 | -/* called under bridge lock */ | |
51 | +/* Acquires and releases bridge lock */ | |
52 | void br_stp_set_bridge_priority(struct net_bridge *br, u16 newprio) | |
53 | { | |
54 | struct net_bridge_port *p; | |
55 | int wasroot; | |
56 | ||
57 | + spin_lock_bh(&br->lock); | |
58 | wasroot = br_is_root_bridge(br); | |
59 | ||
60 | list_for_each_entry(p, &br->port_list, list) { | |
61 | @@ -266,6 +267,7 @@ void br_stp_set_bridge_priority(struct n | |
62 | br_port_state_selection(br); | |
63 | if (br_is_root_bridge(br) && !wasroot) | |
64 | br_become_root_bridge(br); | |
65 | + spin_unlock_bh(&br->lock); | |
66 | } | |
67 | ||
68 | /* called under bridge lock */ |