Message ID | 1508613983.30291.33.camel@edumazet-glaptop3.roam.corp.google.com |
---|---|
State | Accepted, archived |
Delegated to: | David Miller |
Headers | show |
Series | [net] ipv6: flowlabel: do not leave opt->tot_len with garbage | expand |
From: Eric Dumazet <eric.dumazet@gmail.com> Date: Sat, 21 Oct 2017 12:26:23 -0700 > From: Eric Dumazet <edumazet@google.com> > > When syzkaller team brought us a C repro for the crash [1] that > had been reported many times in the past, I finally could find > the root cause. > > If FlowLabel info is merged by fl6_merge_options(), we leave > part of the opt_space storage provided by udp/raw/l2tp with random value > in opt_space.tot_len, unless a control message was provided at sendmsg() > time. > > Then ip6_setup_cork() would use this random value to perform a kzalloc() > call. Undefined behavior and crashes. > > Fix is to properly set tot_len in fl6_merge_options() > > At the same time, we can also avoid consuming memory and cpu cycles > to clear it, if every option is copied via a kmemdup(). This is the > change in ip6_setup_cork(). Nice detective work. Applied and queued up for -stable.
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 8081bafe441b83f60f414114bfdc3529d6ea0a09..15535ee327c5780e80feb050c2ab4e0d1cc3e99c 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c @@ -315,6 +315,7 @@ struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions *opt_space, } opt_space->dst1opt = fopt->dst1opt; opt_space->opt_flen = fopt->opt_flen; + opt_space->tot_len = fopt->tot_len; return opt_space; } EXPORT_SYMBOL_GPL(fl6_merge_options); diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 43ca864327c73015f1724879d7ee8268a0de513b..5110a418cc4d0c1040506394460cb482698d8c15 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1161,11 +1161,11 @@ static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork, if (WARN_ON(v6_cork->opt)) return -EINVAL; - v6_cork->opt = kzalloc(opt->tot_len, sk->sk_allocation); + v6_cork->opt = kzalloc(sizeof(*opt), sk->sk_allocation); if (unlikely(!v6_cork->opt)) return -ENOBUFS; - v6_cork->opt->tot_len = opt->tot_len; + v6_cork->opt->tot_len = sizeof(*opt); v6_cork->opt->opt_flen = opt->opt_flen; v6_cork->opt->opt_nflen = opt->opt_nflen;