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 | |
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')
-rw-r--r-- | net/ipv6/anycast.c | 12 | ||||
-rw-r--r-- | net/ipv6/ipv6_sockglue.c | 2 |
2 files changed, 7 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; |
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index cc5883791bac..9b2cb1444230 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
@@ -122,6 +122,8 @@ static bool setsockopt_needs_rtnl(int optname) | |||
122 | switch (optname) { | 122 | switch (optname) { |
123 | case IPV6_ADD_MEMBERSHIP: | 123 | case IPV6_ADD_MEMBERSHIP: |
124 | case IPV6_DROP_MEMBERSHIP: | 124 | case IPV6_DROP_MEMBERSHIP: |
125 | case IPV6_JOIN_ANYCAST: | ||
126 | case IPV6_LEAVE_ANYCAST: | ||
125 | case MCAST_JOIN_GROUP: | 127 | case MCAST_JOIN_GROUP: |
126 | case MCAST_LEAVE_GROUP: | 128 | case MCAST_LEAVE_GROUP: |
127 | case MCAST_JOIN_SOURCE_GROUP: | 129 | case MCAST_JOIN_SOURCE_GROUP: |