aboutsummaryrefslogtreecommitdiff
path: root/net/ipv6/anycast.c
diff options
context:
space:
mode:
authorMarcelo Ricardo Leitner2015-03-20 11:37:17 -0300
committerDavid S. Miller2015-03-20 13:32:38 -0400
commitc4a6853d8fb2b122686bc6a7c472956e87090f4e (patch)
tree21c8e63f1db8c82c8e5266374a82cc89fff1c270 /net/ipv6/anycast.c
parent149d7549c22045bc777a377720809b108639f9e9 (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.c12
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)
int ishost = !net->ipv6.devconf_all->forwarding;
int err = 0;
+ ASSERT_RTNL();
+
if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
return -EPERM;
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)
pac->acl_next = NULL;
pac->acl_addr = *addr;
- rtnl_lock();
if (ifindex == 0) {
struct rt6_info *rt;
@@ -130,7 +131,6 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
}
error:
- rtnl_unlock();
if (pac)
sock_kfree_s(sk, pac, sizeof(*pac));
return err;
@@ -146,7 +146,8 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
struct ipv6_ac_socklist *pac, *prev_pac;
struct net *net = sock_net(sk);
- rtnl_lock();
+ ASSERT_RTNL();
+
prev_pac = NULL;
for (pac = np->ipv6_ac_list; pac; pac = pac->acl_next) {
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)
break;
prev_pac = pac;
}
- if (!pac) {
- rtnl_unlock();
+ if (!pac)
return -ENOENT;
- }
if (prev_pac)
prev_pac->acl_next = pac->acl_next;
else
@@ -166,7 +165,6 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
dev = __dev_get_by_index(net, pac->acl_ifindex);
if (dev)
ipv6_dev_ac_dec(dev, &pac->acl_addr);
- rtnl_unlock();
sock_kfree_s(sk, pac, sizeof(*pac));
return 0;