aboutsummaryrefslogtreecommitdiffstats
path: root/net/l2tp
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2015-11-29 22:37:57 -0500
committerDavid S. Miller <davem@davemloft.net>2015-12-02 23:37:16 -0500
commit45f6fad84cc305103b28d73482b344d7f5b76f39 (patch)
tree283dbc3a6cd4a26288a3526d0de48cf8c2e27b75 /net/l2tp
parent01b3f52157ff5a47d6d8d796f396a4b34a53c61d (diff)
ipv6: add complete rcu protection around np->opt
This patch addresses multiple problems : UDP/RAW sendmsg() need to get a stable struct ipv6_txoptions while socket is not locked : Other threads can change np->opt concurrently. Dmitry posted a syzkaller (http://github.com/google/syzkaller) program desmonstrating use-after-free. Starting with TCP/DCCP lockless listeners, tcp_v6_syn_recv_sock() and dccp_v6_request_recv_sock() also need to use RCU protection to dereference np->opt once (before calling ipv6_dup_options()) This patch adds full RCU protection to np->opt Reported-by: Dmitry Vyukov <dvyukov@google.com> Signed-off-by: Eric Dumazet <edumazet@google.com> Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/l2tp')
-rw-r--r--net/l2tp/l2tp_ip6.c8
1 files changed, 6 insertions, 2 deletions
diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c
index aca38d8aed8e..a2c8747d2936 100644
--- a/net/l2tp/l2tp_ip6.c
+++ b/net/l2tp/l2tp_ip6.c
@@ -486,6 +486,7 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
486 DECLARE_SOCKADDR(struct sockaddr_l2tpip6 *, lsa, msg->msg_name); 486 DECLARE_SOCKADDR(struct sockaddr_l2tpip6 *, lsa, msg->msg_name);
487 struct in6_addr *daddr, *final_p, final; 487 struct in6_addr *daddr, *final_p, final;
488 struct ipv6_pinfo *np = inet6_sk(sk); 488 struct ipv6_pinfo *np = inet6_sk(sk);
489 struct ipv6_txoptions *opt_to_free = NULL;
489 struct ipv6_txoptions *opt = NULL; 490 struct ipv6_txoptions *opt = NULL;
490 struct ip6_flowlabel *flowlabel = NULL; 491 struct ip6_flowlabel *flowlabel = NULL;
491 struct dst_entry *dst = NULL; 492 struct dst_entry *dst = NULL;
@@ -575,8 +576,10 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
575 opt = NULL; 576 opt = NULL;
576 } 577 }
577 578
578 if (opt == NULL) 579 if (!opt) {
579 opt = np->opt; 580 opt = txopt_get(np);
581 opt_to_free = opt;
582 }
580 if (flowlabel) 583 if (flowlabel)
581 opt = fl6_merge_options(&opt_space, flowlabel, opt); 584 opt = fl6_merge_options(&opt_space, flowlabel, opt);
582 opt = ipv6_fixup_options(&opt_space, opt); 585 opt = ipv6_fixup_options(&opt_space, opt);
@@ -631,6 +634,7 @@ done:
631 dst_release(dst); 634 dst_release(dst);
632out: 635out:
633 fl6_sock_release(flowlabel); 636 fl6_sock_release(flowlabel);
637 txopt_put(opt_to_free);
634 638
635 return err < 0 ? err : len; 639 return err < 0 ? err : len;
636 640