aboutsummaryrefslogtreecommitdiffstats
path: root/net
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
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')
-rw-r--r--net/l2tp/l2tp_ip.c24
-rw-r--r--net/l2tp/l2tp_ip6.c18
2 files changed, 39 insertions, 3 deletions
diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c
index 889f5d13d7ba..70614e7affab 100644
--- a/net/l2tp/l2tp_ip.c
+++ b/net/l2tp/l2tp_ip.c
@@ -239,9 +239,16 @@ static int l2tp_ip_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
239{ 239{
240 struct inet_sock *inet = inet_sk(sk); 240 struct inet_sock *inet = inet_sk(sk);
241 struct sockaddr_l2tpip *addr = (struct sockaddr_l2tpip *) uaddr; 241 struct sockaddr_l2tpip *addr = (struct sockaddr_l2tpip *) uaddr;
242 int ret = -EINVAL; 242 int ret;
243 int chk_addr_ret; 243 int chk_addr_ret;
244 244
245 if (!sock_flag(sk, SOCK_ZAPPED))
246 return -EINVAL;
247 if (addr_len < sizeof(struct sockaddr_l2tpip))
248 return -EINVAL;
249 if (addr->l2tp_family != AF_INET)
250 return -EINVAL;
251
245 ret = -EADDRINUSE; 252 ret = -EADDRINUSE;
246 read_lock_bh(&l2tp_ip_lock); 253 read_lock_bh(&l2tp_ip_lock);
247 if (__l2tp_ip_bind_lookup(&init_net, addr->l2tp_addr.s_addr, sk->sk_bound_dev_if, addr->l2tp_conn_id)) 254 if (__l2tp_ip_bind_lookup(&init_net, addr->l2tp_addr.s_addr, sk->sk_bound_dev_if, addr->l2tp_conn_id))
@@ -272,6 +279,8 @@ static int l2tp_ip_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
272 sk_del_node_init(sk); 279 sk_del_node_init(sk);
273 write_unlock_bh(&l2tp_ip_lock); 280 write_unlock_bh(&l2tp_ip_lock);
274 ret = 0; 281 ret = 0;
282 sock_reset_flag(sk, SOCK_ZAPPED);
283
275out: 284out:
276 release_sock(sk); 285 release_sock(sk);
277 286
@@ -288,6 +297,9 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len
288 struct sockaddr_l2tpip *lsa = (struct sockaddr_l2tpip *) uaddr; 297 struct sockaddr_l2tpip *lsa = (struct sockaddr_l2tpip *) uaddr;
289 int rc; 298 int rc;
290 299
300 if (sock_flag(sk, SOCK_ZAPPED)) /* Must bind first - autobinding does not work */
301 return -EINVAL;
302
291 if (addr_len < sizeof(*lsa)) 303 if (addr_len < sizeof(*lsa))
292 return -EINVAL; 304 return -EINVAL;
293 305
@@ -311,6 +323,14 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len
311 return rc; 323 return rc;
312} 324}
313 325
326static int l2tp_ip_disconnect(struct sock *sk, int flags)
327{
328 if (sock_flag(sk, SOCK_ZAPPED))
329 return 0;
330
331 return udp_disconnect(sk, flags);
332}
333
314static int l2tp_ip_getname(struct socket *sock, struct sockaddr *uaddr, 334static int l2tp_ip_getname(struct socket *sock, struct sockaddr *uaddr,
315 int *uaddr_len, int peer) 335 int *uaddr_len, int peer)
316{ 336{
@@ -530,7 +550,7 @@ static struct proto l2tp_ip_prot = {
530 .close = l2tp_ip_close, 550 .close = l2tp_ip_close,
531 .bind = l2tp_ip_bind, 551 .bind = l2tp_ip_bind,
532 .connect = l2tp_ip_connect, 552 .connect = l2tp_ip_connect,
533 .disconnect = udp_disconnect, 553 .disconnect = l2tp_ip_disconnect,
534 .ioctl = udp_ioctl, 554 .ioctl = udp_ioctl,
535 .destroy = l2tp_ip_destroy_sock, 555 .destroy = l2tp_ip_destroy_sock,
536 .setsockopt = ip_setsockopt, 556 .setsockopt = ip_setsockopt,
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,