aboutsummaryrefslogtreecommitdiffstats
path: root/net/l2tp/l2tp_ip6.c
diff options
context:
space:
mode:
authorGuillaume Nault <g.nault@alphalink.fr>2016-11-29 07:09:46 -0500
committerDavid S. Miller <davem@davemloft.net>2016-11-30 14:14:08 -0500
commitd5e3a190937a1e386671266202c62565741f0f1a (patch)
tree45bbcc04837eaeeb95ed3995c03ebd718505c07a /net/l2tp/l2tp_ip6.c
parenta3c18422a4b4e108bcf6a2328f48867e1003fd95 (diff)
l2tp: fix racy socket lookup in l2tp_ip and l2tp_ip6 bind()
It's not enough to check for sockets bound to same address at the beginning of l2tp_ip{,6}_bind(): even if no socket is found at that time, a socket with the same address could be bound before we take the l2tp lock again. This patch moves the lookup right before inserting the new socket, so that no change can ever happen to the list between address lookup and socket insertion. Care is taken to avoid side effects on the socket in case of failure. That is, modifications of the socket are done after the lookup, when binding is guaranteed to succeed, and before releasing the l2tp lock, so that concurrent lookups will always see fully initialised sockets. For l2tp_ip, 'ret' is set to -EINVAL before checking the SOCK_ZAPPED bit. Error code was mistakenly set to -EADDRINUSE on error by commit 32c231164b76 ("l2tp: fix racy SOCK_ZAPPED flag check in l2tp_ip{,6}_bind()"). Using -EINVAL restores original behaviour. For l2tp_ip6, the lookup is now always done with the correct bound device. Before this patch, when binding to a link-local address, the lookup was done with the original sk->sk_bound_dev_if, which was later overwritten with addr->l2tp_scope_id. Lookup is now performed with the final sk->sk_bound_dev_if value. Finally, the (addr_len >= sizeof(struct sockaddr_in6)) check has been dropped: addr is a sockaddr_l2tpip6 not sockaddr_in6 and addr_len has already been checked at this point (this part of the code seems to have been copy-pasted from net/ipv6/raw.c). Signed-off-by: Guillaume Nault <g.nault@alphalink.fr> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/l2tp/l2tp_ip6.c')
-rw-r--r--net/l2tp/l2tp_ip6.c43
1 files changed, 20 insertions, 23 deletions
diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c
index e3fc7786f188..5f2ae615c5f9 100644
--- a/net/l2tp/l2tp_ip6.c
+++ b/net/l2tp/l2tp_ip6.c
@@ -267,6 +267,7 @@ static int l2tp_ip6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
267 struct sockaddr_l2tpip6 *addr = (struct sockaddr_l2tpip6 *) uaddr; 267 struct sockaddr_l2tpip6 *addr = (struct sockaddr_l2tpip6 *) uaddr;
268 struct net *net = sock_net(sk); 268 struct net *net = sock_net(sk);
269 __be32 v4addr = 0; 269 __be32 v4addr = 0;
270 int bound_dev_if;
270 int addr_type; 271 int addr_type;
271 int err; 272 int err;
272 273
@@ -285,13 +286,6 @@ static int l2tp_ip6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
285 if (addr_type & IPV6_ADDR_MULTICAST) 286 if (addr_type & IPV6_ADDR_MULTICAST)
286 return -EADDRNOTAVAIL; 287 return -EADDRNOTAVAIL;
287 288
288 err = -EADDRINUSE;
289 read_lock_bh(&l2tp_ip6_lock);
290 if (__l2tp_ip6_bind_lookup(net, &addr->l2tp_addr,
291 sk->sk_bound_dev_if, addr->l2tp_conn_id))
292 goto out_in_use;
293 read_unlock_bh(&l2tp_ip6_lock);
294
295 lock_sock(sk); 289 lock_sock(sk);
296 290
297 err = -EINVAL; 291 err = -EINVAL;
@@ -301,28 +295,25 @@ static int l2tp_ip6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
301 if (sk->sk_state != TCP_CLOSE) 295 if (sk->sk_state != TCP_CLOSE)
302 goto out_unlock; 296 goto out_unlock;
303 297
298 bound_dev_if = sk->sk_bound_dev_if;
299
304 /* Check if the address belongs to the host. */ 300 /* Check if the address belongs to the host. */
305 rcu_read_lock(); 301 rcu_read_lock();
306 if (addr_type != IPV6_ADDR_ANY) { 302 if (addr_type != IPV6_ADDR_ANY) {
307 struct net_device *dev = NULL; 303 struct net_device *dev = NULL;
308 304
309 if (addr_type & IPV6_ADDR_LINKLOCAL) { 305 if (addr_type & IPV6_ADDR_LINKLOCAL) {
310 if (addr_len >= sizeof(struct sockaddr_in6) && 306 if (addr->l2tp_scope_id)
311 addr->l2tp_scope_id) { 307 bound_dev_if = addr->l2tp_scope_id;
312 /* Override any existing binding, if another
313 * one is supplied by user.
314 */
315 sk->sk_bound_dev_if = addr->l2tp_scope_id;
316 }
317 308
318 /* Binding to link-local address requires an 309 /* Binding to link-local address requires an
319 interface */ 310 * interface.
320 if (!sk->sk_bound_dev_if) 311 */
312 if (!bound_dev_if)
321 goto out_unlock_rcu; 313 goto out_unlock_rcu;
322 314
323 err = -ENODEV; 315 err = -ENODEV;
324 dev = dev_get_by_index_rcu(sock_net(sk), 316 dev = dev_get_by_index_rcu(sock_net(sk), bound_dev_if);
325 sk->sk_bound_dev_if);
326 if (!dev) 317 if (!dev)
327 goto out_unlock_rcu; 318 goto out_unlock_rcu;
328 } 319 }
@@ -337,13 +328,22 @@ static int l2tp_ip6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
337 } 328 }
338 rcu_read_unlock(); 329 rcu_read_unlock();
339 330
340 inet->inet_rcv_saddr = inet->inet_saddr = v4addr; 331 write_lock_bh(&l2tp_ip6_lock);
332 if (__l2tp_ip6_bind_lookup(net, &addr->l2tp_addr, bound_dev_if,
333 addr->l2tp_conn_id)) {
334 write_unlock_bh(&l2tp_ip6_lock);
335 err = -EADDRINUSE;
336 goto out_unlock;
337 }
338
339 inet->inet_saddr = v4addr;
340 inet->inet_rcv_saddr = v4addr;
341 sk->sk_bound_dev_if = bound_dev_if;
341 sk->sk_v6_rcv_saddr = addr->l2tp_addr; 342 sk->sk_v6_rcv_saddr = addr->l2tp_addr;
342 np->saddr = addr->l2tp_addr; 343 np->saddr = addr->l2tp_addr;
343 344
344 l2tp_ip6_sk(sk)->conn_id = addr->l2tp_conn_id; 345 l2tp_ip6_sk(sk)->conn_id = addr->l2tp_conn_id;
345 346
346 write_lock_bh(&l2tp_ip6_lock);
347 sk_add_bind_node(sk, &l2tp_ip6_bind_table); 347 sk_add_bind_node(sk, &l2tp_ip6_bind_table);
348 sk_del_node_init(sk); 348 sk_del_node_init(sk);
349 write_unlock_bh(&l2tp_ip6_lock); 349 write_unlock_bh(&l2tp_ip6_lock);
@@ -356,10 +356,7 @@ out_unlock_rcu:
356 rcu_read_unlock(); 356 rcu_read_unlock();
357out_unlock: 357out_unlock:
358 release_sock(sk); 358 release_sock(sk);
359 return err;
360 359
361out_in_use:
362 read_unlock_bh(&l2tp_ip6_lock);
363 return err; 360 return err;
364} 361}
365 362