aboutsummaryrefslogtreecommitdiffstats
path: root/net/l2tp/l2tp_ip6.c
diff options
context:
space:
mode:
authorJames Chapman <jchapman@katalix.com>2012-05-28 23:30:42 -0400
committerDavid S. Miller <davem@davemloft.net>2012-05-29 17:19:44 -0400
commitc51ce49735c183ef2592db70f918ee698716276b (patch)
tree51387149e69b2d505fb784c40f7d27b79b6593ef /net/l2tp/l2tp_ip6.c
parent0c1833797a5a6ec23ea9261d979aa18078720b74 (diff)
l2tp: fix oops in L2TP IP sockets for connect() AF_UNSPEC case
An application may call connect() to disconnect a socket using an address with family AF_UNSPEC. The L2TP IP sockets were not handling this case when the socket is not bound and an attempt to connect() using AF_UNSPEC in such cases would result in an oops. This patch addresses the problem by protecting the sk_prot->disconnect() call against trying to unhash the socket before it is bound. The L2TP IPv4 and IPv6 sockets have the same problem. Both are fixed by this patch. The patch also adds more checks that the sockaddr supplied to bind() and connect() calls is valid. RIP: 0010:[<ffffffff82e133b0>] [<ffffffff82e133b0>] inet_unhash+0x50/0xd0 RSP: 0018:ffff88001989be28 EFLAGS: 00010293 Stack: ffff8800407a8000 0000000000000000 ffff88001989be78 ffffffff82e3a249 ffffffff82e3a050 ffff88001989bec8 ffff88001989be88 ffff8800407a8000 0000000000000010 ffff88001989bec8 ffff88001989bea8 ffffffff82e42639 Call Trace: [<ffffffff82e3a249>] udp_disconnect+0x1f9/0x290 [<ffffffff82e42639>] inet_dgram_connect+0x29/0x80 [<ffffffff82d012fc>] sys_connect+0x9c/0x100 Reported-by: Sasha Levin <levinsasha928@gmail.com> Signed-off-by: James Chapman <jchapman@katalix.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/l2tp/l2tp_ip6.c')
-rw-r--r--net/l2tp/l2tp_ip6.c18
1 files changed, 17 insertions, 1 deletions
diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c
index 0291d8d85f30..35e1e4bde587 100644
--- a/net/l2tp/l2tp_ip6.c
+++ b/net/l2tp/l2tp_ip6.c
@@ -258,6 +258,10 @@ static int l2tp_ip6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
258 int addr_type; 258 int addr_type;
259 int err; 259 int err;
260 260
261 if (!sock_flag(sk, SOCK_ZAPPED))
262 return -EINVAL;
263 if (addr->l2tp_family != AF_INET6)
264 return -EINVAL;
261 if (addr_len < sizeof(*addr)) 265 if (addr_len < sizeof(*addr))
262 return -EINVAL; 266 return -EINVAL;
263 267
@@ -331,6 +335,7 @@ static int l2tp_ip6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
331 sk_del_node_init(sk); 335 sk_del_node_init(sk);
332 write_unlock_bh(&l2tp_ip6_lock); 336 write_unlock_bh(&l2tp_ip6_lock);
333 337
338 sock_reset_flag(sk, SOCK_ZAPPED);
334 release_sock(sk); 339 release_sock(sk);
335 return 0; 340 return 0;
336 341
@@ -354,6 +359,9 @@ static int l2tp_ip6_connect(struct sock *sk, struct sockaddr *uaddr,
354 int addr_type; 359 int addr_type;
355 int rc; 360 int rc;
356 361
362 if (sock_flag(sk, SOCK_ZAPPED)) /* Must bind first - autobinding does not work */
363 return -EINVAL;
364
357 if (addr_len < sizeof(*lsa)) 365 if (addr_len < sizeof(*lsa))
358 return -EINVAL; 366 return -EINVAL;
359 367
@@ -383,6 +391,14 @@ static int l2tp_ip6_connect(struct sock *sk, struct sockaddr *uaddr,
383 return rc; 391 return rc;
384} 392}
385 393
394static int l2tp_ip6_disconnect(struct sock *sk, int flags)
395{
396 if (sock_flag(sk, SOCK_ZAPPED))
397 return 0;
398
399 return udp_disconnect(sk, flags);
400}
401
386static int l2tp_ip6_getname(struct socket *sock, struct sockaddr *uaddr, 402static int l2tp_ip6_getname(struct socket *sock, struct sockaddr *uaddr,
387 int *uaddr_len, int peer) 403 int *uaddr_len, int peer)
388{ 404{
@@ -689,7 +705,7 @@ static struct proto l2tp_ip6_prot = {
689 .close = l2tp_ip6_close, 705 .close = l2tp_ip6_close,
690 .bind = l2tp_ip6_bind, 706 .bind = l2tp_ip6_bind,
691 .connect = l2tp_ip6_connect, 707 .connect = l2tp_ip6_connect,
692 .disconnect = udp_disconnect, 708 .disconnect = l2tp_ip6_disconnect,
693 .ioctl = udp_ioctl, 709 .ioctl = udp_ioctl,
694 .destroy = l2tp_ip6_destroy_sock, 710 .destroy = l2tp_ip6_destroy_sock,
695 .setsockopt = ipv6_setsockopt, 711 .setsockopt = ipv6_setsockopt,