aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJames Chapman <jchapman@katalix.com>2012-05-29 19:13:23 -0400
committerLuis Henriques <luis.henriques@canonical.com>2012-07-03 11:29:03 -0400
commit37b639401f594ea9f1eb3c5e0096a159c4438614 (patch)
tree3195260573dc7d0c40b387b1e474609c691ffe62 /net
parentc62c612446a42a5de3559a1de7623ce86cc51636 (diff)
l2tp: fix oops in L2TP IP sockets for connect() AF_UNSPEC case
BugLink: http://bugs.launchpad.net/bugs/1013748 [ Upstream commit c51ce49735c183ef2592db70f918ee698716276b ] 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 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: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Herton Ronaldo Krzesinski <herton.krzesinski@canonical.com>
Diffstat (limited to 'net')
-rw-r--r--net/l2tp/l2tp_ip.c30
1 files changed, 24 insertions, 6 deletions
diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c
index ea52d028632..78bc442b2b6 100644
--- a/net/l2tp/l2tp_ip.c
+++ b/net/l2tp/l2tp_ip.c
@@ -251,9 +251,16 @@ static int l2tp_ip_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
251{ 251{
252 struct inet_sock *inet = inet_sk(sk); 252 struct inet_sock *inet = inet_sk(sk);
253 struct sockaddr_l2tpip *addr = (struct sockaddr_l2tpip *) uaddr; 253 struct sockaddr_l2tpip *addr = (struct sockaddr_l2tpip *) uaddr;
254 int ret = -EINVAL; 254 int ret;
255 int chk_addr_ret; 255 int chk_addr_ret;
256 256
257 if (!sock_flag(sk, SOCK_ZAPPED))
258 return -EINVAL;
259 if (addr_len < sizeof(struct sockaddr_l2tpip))
260 return -EINVAL;
261 if (addr->l2tp_family != AF_INET)
262 return -EINVAL;
263
257 ret = -EADDRINUSE; 264 ret = -EADDRINUSE;
258 read_lock_bh(&l2tp_ip_lock); 265 read_lock_bh(&l2tp_ip_lock);
259 if (__l2tp_ip_bind_lookup(&init_net, addr->l2tp_addr.s_addr, sk->sk_bound_dev_if, addr->l2tp_conn_id)) 266 if (__l2tp_ip_bind_lookup(&init_net, addr->l2tp_addr.s_addr, sk->sk_bound_dev_if, addr->l2tp_conn_id))
@@ -283,6 +290,8 @@ static int l2tp_ip_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
283 sk_del_node_init(sk); 290 sk_del_node_init(sk);
284 write_unlock_bh(&l2tp_ip_lock); 291 write_unlock_bh(&l2tp_ip_lock);
285 ret = 0; 292 ret = 0;
293 sock_reset_flag(sk, SOCK_ZAPPED);
294
286out: 295out:
287 release_sock(sk); 296 release_sock(sk);
288 297
@@ -303,13 +312,14 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len
303 __be32 saddr; 312 __be32 saddr;
304 int oif, rc; 313 int oif, rc;
305 314
306 rc = -EINVAL; 315 if (sock_flag(sk, SOCK_ZAPPED)) /* Must bind first - autobinding does not work */
316 return -EINVAL;
317
307 if (addr_len < sizeof(*lsa)) 318 if (addr_len < sizeof(*lsa))
308 goto out; 319 return -EINVAL;
309 320
310 rc = -EAFNOSUPPORT;
311 if (lsa->l2tp_family != AF_INET) 321 if (lsa->l2tp_family != AF_INET)
312 goto out; 322 return -EAFNOSUPPORT;
313 323
314 lock_sock(sk); 324 lock_sock(sk);
315 325
@@ -363,6 +373,14 @@ out:
363 return rc; 373 return rc;
364} 374}
365 375
376static int l2tp_ip_disconnect(struct sock *sk, int flags)
377{
378 if (sock_flag(sk, SOCK_ZAPPED))
379 return 0;
380
381 return udp_disconnect(sk, flags);
382}
383
366static int l2tp_ip_getname(struct socket *sock, struct sockaddr *uaddr, 384static int l2tp_ip_getname(struct socket *sock, struct sockaddr *uaddr,
367 int *uaddr_len, int peer) 385 int *uaddr_len, int peer)
368{ 386{
@@ -591,7 +609,7 @@ static struct proto l2tp_ip_prot = {
591 .close = l2tp_ip_close, 609 .close = l2tp_ip_close,
592 .bind = l2tp_ip_bind, 610 .bind = l2tp_ip_bind,
593 .connect = l2tp_ip_connect, 611 .connect = l2tp_ip_connect,
594 .disconnect = udp_disconnect, 612 .disconnect = l2tp_ip_disconnect,
595 .ioctl = udp_ioctl, 613 .ioctl = udp_ioctl,
596 .destroy = l2tp_ip_destroy_sock, 614 .destroy = l2tp_ip_destroy_sock,
597 .setsockopt = ip_setsockopt, 615 .setsockopt = ip_setsockopt,