Skip to content

Commit

Permalink
l2tp: do not use udp_ioctl()
Browse files Browse the repository at this point in the history
commit 72fb96e upstream.

udp_ioctl(), as its name suggests, is used by UDP protocols,
but is also used by L2TP :(

L2TP should use its own handler, because it really does not
look the same.

SIOCINQ for instance should not assume UDP checksum or headers.

Thanks to Andrey and syzkaller team for providing the report
and a nice reproducer.

While crashes only happen on recent kernels (after commit
7c13f97 ("udp: do fwd memory scheduling on dequeue")), this
probably needs to be backported to older kernels.

Fixes: 7c13f97 ("udp: do fwd memory scheduling on dequeue")
Fixes: 8558467 ("udp: Fix udp_poll() and ioctl()")
Signed-off-by: Eric Dumazet <[email protected]>
Reported-by: Andrey Konovalov <[email protected]>
Acked-by: Paolo Abeni <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
Signed-off-by: Willy Tarreau <[email protected]>
  • Loading branch information
Eric Dumazet authored and wtarreau committed Jun 7, 2017
1 parent c6dfb87 commit 3d75337
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 2 deletions.
1 change: 1 addition & 0 deletions net/l2tp/l2tp_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ extern int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int

extern int l2tp_nl_register_ops(enum l2tp_pwtype pw_type, const struct l2tp_nl_cmd_ops *ops);
extern void l2tp_nl_unregister_ops(enum l2tp_pwtype pw_type);
int l2tp_ioctl(struct sock *sk, int cmd, unsigned long arg);

/* Session reference counts. Incremented when code obtains a reference
* to a session.
Expand Down
27 changes: 26 additions & 1 deletion net/l2tp/l2tp_ip.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <asm/ioctls.h>
#include <linux/icmp.h>
#include <linux/module.h>
#include <linux/skbuff.h>
Expand Down Expand Up @@ -554,6 +555,30 @@ static int l2tp_ip_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m
return err ? err : copied;
}

int l2tp_ioctl(struct sock *sk, int cmd, unsigned long arg)
{
struct sk_buff *skb;
int amount;

switch (cmd) {
case SIOCOUTQ:
amount = sk_wmem_alloc_get(sk);
break;
case SIOCINQ:
spin_lock_bh(&sk->sk_receive_queue.lock);
skb = skb_peek(&sk->sk_receive_queue);
amount = skb ? skb->len : 0;
spin_unlock_bh(&sk->sk_receive_queue.lock);
break;

default:
return -ENOIOCTLCMD;
}

return put_user(amount, (int __user *)arg);
}
EXPORT_SYMBOL(l2tp_ioctl);

static struct proto l2tp_ip_prot = {
.name = "L2TP/IP",
.owner = THIS_MODULE,
Expand All @@ -562,7 +587,7 @@ static struct proto l2tp_ip_prot = {
.bind = l2tp_ip_bind,
.connect = l2tp_ip_connect,
.disconnect = l2tp_ip_disconnect,
.ioctl = udp_ioctl,
.ioctl = l2tp_ioctl,
.destroy = l2tp_ip_destroy_sock,
.setsockopt = ip_setsockopt,
.getsockopt = ip_getsockopt,
Expand Down
2 changes: 1 addition & 1 deletion net/l2tp/l2tp_ip6.c
Original file line number Diff line number Diff line change
Expand Up @@ -716,7 +716,7 @@ static struct proto l2tp_ip6_prot = {
.bind = l2tp_ip6_bind,
.connect = l2tp_ip6_connect,
.disconnect = l2tp_ip6_disconnect,
.ioctl = udp_ioctl,
.ioctl = l2tp_ioctl,
.destroy = l2tp_ip6_destroy_sock,
.setsockopt = ipv6_setsockopt,
.getsockopt = ipv6_getsockopt,
Expand Down

0 comments on commit 3d75337

Please sign in to comment.