Skip to content

Commit c51ce49

Browse files
j-c-hdavem330
authored andcommitted
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 <[email protected]> Signed-off-by: James Chapman <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 0c18337 commit c51ce49

File tree

2 files changed

+39
-3
lines changed

2 files changed

+39
-3
lines changed

net/l2tp/l2tp_ip.c

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,9 +239,16 @@ static int l2tp_ip_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
239239
{
240240
struct inet_sock *inet = inet_sk(sk);
241241
struct sockaddr_l2tpip *addr = (struct sockaddr_l2tpip *) uaddr;
242-
int ret = -EINVAL;
242+
int ret;
243243
int chk_addr_ret;
244244

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+
245252
ret = -EADDRINUSE;
246253
read_lock_bh(&l2tp_ip_lock);
247254
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)
272279
sk_del_node_init(sk);
273280
write_unlock_bh(&l2tp_ip_lock);
274281
ret = 0;
282+
sock_reset_flag(sk, SOCK_ZAPPED);
283+
275284
out:
276285
release_sock(sk);
277286

@@ -288,6 +297,9 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len
288297
struct sockaddr_l2tpip *lsa = (struct sockaddr_l2tpip *) uaddr;
289298
int rc;
290299

300+
if (sock_flag(sk, SOCK_ZAPPED)) /* Must bind first - autobinding does not work */
301+
return -EINVAL;
302+
291303
if (addr_len < sizeof(*lsa))
292304
return -EINVAL;
293305

@@ -311,6 +323,14 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len
311323
return rc;
312324
}
313325

326+
static 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+
314334
static int l2tp_ip_getname(struct socket *sock, struct sockaddr *uaddr,
315335
int *uaddr_len, int peer)
316336
{
@@ -530,7 +550,7 @@ static struct proto l2tp_ip_prot = {
530550
.close = l2tp_ip_close,
531551
.bind = l2tp_ip_bind,
532552
.connect = l2tp_ip_connect,
533-
.disconnect = udp_disconnect,
553+
.disconnect = l2tp_ip_disconnect,
534554
.ioctl = udp_ioctl,
535555
.destroy = l2tp_ip_destroy_sock,
536556
.setsockopt = ip_setsockopt,

net/l2tp/l2tp_ip6.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,10 @@ static int l2tp_ip6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
258258
int addr_type;
259259
int err;
260260

261+
if (!sock_flag(sk, SOCK_ZAPPED))
262+
return -EINVAL;
263+
if (addr->l2tp_family != AF_INET6)
264+
return -EINVAL;
261265
if (addr_len < sizeof(*addr))
262266
return -EINVAL;
263267

@@ -331,6 +335,7 @@ static int l2tp_ip6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
331335
sk_del_node_init(sk);
332336
write_unlock_bh(&l2tp_ip6_lock);
333337

338+
sock_reset_flag(sk, SOCK_ZAPPED);
334339
release_sock(sk);
335340
return 0;
336341

@@ -354,6 +359,9 @@ static int l2tp_ip6_connect(struct sock *sk, struct sockaddr *uaddr,
354359
int addr_type;
355360
int rc;
356361

362+
if (sock_flag(sk, SOCK_ZAPPED)) /* Must bind first - autobinding does not work */
363+
return -EINVAL;
364+
357365
if (addr_len < sizeof(*lsa))
358366
return -EINVAL;
359367

@@ -383,6 +391,14 @@ static int l2tp_ip6_connect(struct sock *sk, struct sockaddr *uaddr,
383391
return rc;
384392
}
385393

394+
static 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+
386402
static int l2tp_ip6_getname(struct socket *sock, struct sockaddr *uaddr,
387403
int *uaddr_len, int peer)
388404
{
@@ -689,7 +705,7 @@ static struct proto l2tp_ip6_prot = {
689705
.close = l2tp_ip6_close,
690706
.bind = l2tp_ip6_bind,
691707
.connect = l2tp_ip6_connect,
692-
.disconnect = udp_disconnect,
708+
.disconnect = l2tp_ip6_disconnect,
693709
.ioctl = udp_ioctl,
694710
.destroy = l2tp_ip6_destroy_sock,
695711
.setsockopt = ipv6_setsockopt,

0 commit comments

Comments
 (0)