diff options
author | Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> | 2015-03-20 10:37:17 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-03-20 13:32:38 -0400 |
commit | c4a6853d8fb2b122686bc6a7c472956e87090f4e (patch) | |
tree | 21c8e63f1db8c82c8e5266374a82cc89fff1c270 /net/ipv6/anycast.c | |
parent | 149d7549c22045bc777a377720809b108639f9e9 (diff) |
ipv6: invert join/leave anycast rtnl/socket locking order
Commit baf606d9c9b1 ("ipv4,ipv6: grab rtnl before locking the socket")
missed to update two setsockopt options, IPV6_JOIN_ANYCAST and
IPV6_LEAVE_ANYCAST, causing a lock inverstion regarding to the updated ones.
As ipv6_sock_ac_join and ipv6_sock_ac_leave are only called from
do_ipv6_setsockopt, we are good to just move the rtnl lock upper.
Fixes: baf606d9c9b1 ("ipv4,ipv6: grab rtnl before locking the socket")
Reported-by: Ying Huang <ying.huang@intel.com>
Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/anycast.c')
-rw-r--r-- | net/ipv6/anycast.c | 12 |
1 files changed, 5 insertions, 7 deletions
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index baf2742d1ec4..9e6b0ee563f0 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c | |||
@@ -60,6 +60,8 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
60 | int ishost = !net->ipv6.devconf_all->forwarding; | 60 | int ishost = !net->ipv6.devconf_all->forwarding; |
61 | int err = 0; | 61 | int err = 0; |
62 | 62 | ||
63 | ASSERT_RTNL(); | ||
64 | |||
63 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) | 65 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
64 | return -EPERM; | 66 | return -EPERM; |
65 | if (ipv6_addr_is_multicast(addr)) | 67 | if (ipv6_addr_is_multicast(addr)) |
@@ -73,7 +75,6 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
73 | pac->acl_next = NULL; | 75 | pac->acl_next = NULL; |
74 | pac->acl_addr = *addr; | 76 | pac->acl_addr = *addr; |
75 | 77 | ||
76 | rtnl_lock(); | ||
77 | if (ifindex == 0) { | 78 | if (ifindex == 0) { |
78 | struct rt6_info *rt; | 79 | struct rt6_info *rt; |
79 | 80 | ||
@@ -130,7 +131,6 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
130 | } | 131 | } |
131 | 132 | ||
132 | error: | 133 | error: |
133 | rtnl_unlock(); | ||
134 | if (pac) | 134 | if (pac) |
135 | sock_kfree_s(sk, pac, sizeof(*pac)); | 135 | sock_kfree_s(sk, pac, sizeof(*pac)); |
136 | return err; | 136 | return err; |
@@ -146,7 +146,8 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
146 | struct ipv6_ac_socklist *pac, *prev_pac; | 146 | struct ipv6_ac_socklist *pac, *prev_pac; |
147 | struct net *net = sock_net(sk); | 147 | struct net *net = sock_net(sk); |
148 | 148 | ||
149 | rtnl_lock(); | 149 | ASSERT_RTNL(); |
150 | |||
150 | prev_pac = NULL; | 151 | prev_pac = NULL; |
151 | for (pac = np->ipv6_ac_list; pac; pac = pac->acl_next) { | 152 | for (pac = np->ipv6_ac_list; pac; pac = pac->acl_next) { |
152 | if ((ifindex == 0 || pac->acl_ifindex == ifindex) && | 153 | if ((ifindex == 0 || pac->acl_ifindex == ifindex) && |
@@ -154,10 +155,8 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
154 | break; | 155 | break; |
155 | prev_pac = pac; | 156 | prev_pac = pac; |
156 | } | 157 | } |
157 | if (!pac) { | 158 | if (!pac) |
158 | rtnl_unlock(); | ||
159 | return -ENOENT; | 159 | return -ENOENT; |
160 | } | ||
161 | if (prev_pac) | 160 | if (prev_pac) |
162 | prev_pac->acl_next = pac->acl_next; | 161 | prev_pac->acl_next = pac->acl_next; |
163 | else | 162 | else |
@@ -166,7 +165,6 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
166 | dev = __dev_get_by_index(net, pac->acl_ifindex); | 165 | dev = __dev_get_by_index(net, pac->acl_ifindex); |
167 | if (dev) | 166 | if (dev) |
168 | ipv6_dev_ac_dec(dev, &pac->acl_addr); | 167 | ipv6_dev_ac_dec(dev, &pac->acl_addr); |
169 | rtnl_unlock(); | ||
170 | 168 | ||
171 | sock_kfree_s(sk, pac, sizeof(*pac)); | 169 | sock_kfree_s(sk, pac, sizeof(*pac)); |
172 | return 0; | 170 | return 0; |