]>
Commit | Line | Data |
---|---|---|
3ee990c1 GKH |
1 | From foo@baz Wed Mar 11 11:43:33 CET 2015 |
2 | From: Jiri Pirko <jiri@resnulli.us> | |
3 | Date: Mon, 23 Feb 2015 14:02:54 +0100 | |
4 | Subject: team: fix possible null pointer dereference in team_handle_frame | |
5 | ||
6 | From: Jiri Pirko <jiri@resnulli.us> | |
7 | ||
8 | [ Upstream commit 57e595631904c827cfa1a0f7bbd7cc9a49da5745 ] | |
9 | ||
10 | Currently following race is possible in team: | |
11 | ||
12 | CPU0 CPU1 | |
13 | team_port_del | |
14 | team_upper_dev_unlink | |
15 | priv_flags &= ~IFF_TEAM_PORT | |
16 | team_handle_frame | |
17 | team_port_get_rcu | |
18 | team_port_exists | |
19 | priv_flags & IFF_TEAM_PORT == 0 | |
20 | return NULL (instead of port got | |
21 | from rx_handler_data) | |
22 | netdev_rx_handler_unregister | |
23 | ||
24 | The thing is that the flag is removed before rx_handler is unregistered. | |
25 | If team_handle_frame is called in between, team_port_exists returns 0 | |
26 | and team_port_get_rcu will return NULL. | |
27 | So do not check the flag here. It is guaranteed by netdev_rx_handler_unregister | |
28 | that team_handle_frame will always see valid rx_handler_data pointer. | |
29 | ||
30 | Signed-off-by: Jiri Pirko <jiri@resnulli.us> | |
31 | Fixes: 3d249d4ca7d0 ("net: introduce ethernet teaming device") | |
32 | Signed-off-by: David S. Miller <davem@davemloft.net> | |
33 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
34 | --- | |
35 | drivers/net/team/team.c | 4 +--- | |
36 | 1 file changed, 1 insertion(+), 3 deletions(-) | |
37 | ||
38 | --- a/drivers/net/team/team.c | |
39 | +++ b/drivers/net/team/team.c | |
40 | @@ -42,9 +42,7 @@ | |
41 | ||
42 | static struct team_port *team_port_get_rcu(const struct net_device *dev) | |
43 | { | |
44 | - struct team_port *port = rcu_dereference(dev->rx_handler_data); | |
45 | - | |
46 | - return team_port_exists(dev) ? port : NULL; | |
47 | + return rcu_dereference(dev->rx_handler_data); | |
48 | } | |
49 | ||
50 | static struct team_port *team_port_get_rtnl(const struct net_device *dev) |