All of lore.kernel.org
 help / color / mirror / Atom feed
From: Luis Henriques <luis.henriques@canonical.com>
To: linux-kernel@vger.kernel.org, stable@vger.kernel.org,
	kernel-team@lists.ubuntu.com
Cc: Eric Dumazet <edumazet@google.com>,
	"David S. Miller" <davem@davemloft.net>,
	Luis Henriques <luis.henriques@canonical.com>
Subject: [PATCH 3.16.y-ckt 051/126] ipv6: add complete rcu protection around np->opt
Date: Wed,  6 Jan 2016 10:36:20 +0000	[thread overview]
Message-ID: <1452076655-12851-52-git-send-email-luis.henriques@canonical.com> (raw)
In-Reply-To: <1452076655-12851-1-git-send-email-luis.henriques@canonical.com>

3.16.7-ckt22 -stable review patch.  If anyone has any objections, please let me know.

------------------

From: Eric Dumazet <edumazet@google.com>

commit 45f6fad84cc305103b28d73482b344d7f5b76f39 upstream.

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>
[ luis: backported to 3.16: adjusted context ]
Signed-off-by: Luis Henriques <luis.henriques@canonical.com>
---
 include/linux/ipv6.h             |  2 +-
 include/net/ipv6.h               | 21 ++++++++++++++++++++-
 net/dccp/ipv6.c                  | 33 +++++++++++++++++++++------------
 net/ipv6/af_inet6.c              | 13 +++++++++----
 net/ipv6/datagram.c              |  4 +++-
 net/ipv6/exthdrs.c               |  3 ++-
 net/ipv6/inet6_connection_sock.c | 11 ++++++++---
 net/ipv6/ipv6_sockglue.c         | 36 ++++++++++++++++++++++++------------
 net/ipv6/raw.c                   |  8 ++++++--
 net/ipv6/syncookies.c            |  2 +-
 net/ipv6/tcp_ipv6.c              | 28 +++++++++++++++++-----------
 net/ipv6/udp.c                   |  8 ++++++--
 net/l2tp/l2tp_ip6.c              |  8 ++++++--
 13 files changed, 124 insertions(+), 53 deletions(-)

diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 2faef339d8f2..f3d5d11b8871 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -210,7 +210,7 @@ struct ipv6_pinfo {
 	struct ipv6_ac_socklist	*ipv6_ac_list;
 	struct ipv6_fl_socklist __rcu *ipv6_fl_list;
 
-	struct ipv6_txoptions	*opt;
+	struct ipv6_txoptions __rcu	*opt;
 	struct sk_buff		*pktoptions;
 	struct sk_buff		*rxpmtu;
 	struct {
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index a73a6bb0134d..9aca37aa9796 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -205,6 +205,7 @@ extern rwlock_t ip6_ra_lock;
  */
 
 struct ipv6_txoptions {
+	atomic_t		refcnt;
 	/* Length of this structure */
 	int			tot_len;
 
@@ -217,7 +218,7 @@ struct ipv6_txoptions {
 	struct ipv6_opt_hdr	*dst0opt;
 	struct ipv6_rt_hdr	*srcrt;	/* Routing Header */
 	struct ipv6_opt_hdr	*dst1opt;
-
+	struct rcu_head		rcu;
 	/* Option buffer, as read by IPV6_PKTOPTIONS, starts here. */
 };
 
@@ -250,6 +251,24 @@ struct ipv6_fl_socklist {
 	struct rcu_head			rcu;
 };
 
+static inline struct ipv6_txoptions *txopt_get(const struct ipv6_pinfo *np)
+{
+	struct ipv6_txoptions *opt;
+
+	rcu_read_lock();
+	opt = rcu_dereference(np->opt);
+	if (opt && !atomic_inc_not_zero(&opt->refcnt))
+		opt = NULL;
+	rcu_read_unlock();
+	return opt;
+}
+
+static inline void txopt_put(struct ipv6_txoptions *opt)
+{
+	if (opt && atomic_dec_and_test(&opt->refcnt))
+		kfree_rcu(opt, rcu);
+}
+
 struct ip6_flowlabel *fl6_sock_lookup(struct sock *sk, __be32 label);
 struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions *opt_space,
 					 struct ip6_flowlabel *fl,
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 4db3c2a1679c..1149e345bba9 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -238,7 +238,9 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req)
 	security_req_classify_flow(req, flowi6_to_flowi(&fl6));
 
 
-	final_p = fl6_update_dst(&fl6, np->opt, &final);
+	rcu_read_lock();
+	final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt), &final);
+	rcu_read_unlock();
 
 	dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
 	if (IS_ERR(dst)) {
@@ -255,7 +257,10 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req)
 							 &ireq->ir_v6_loc_addr,
 							 &ireq->ir_v6_rmt_addr);
 		fl6.daddr = ireq->ir_v6_rmt_addr;
-		err = ip6_xmit(sk, skb, &fl6, np->opt, np->tclass);
+		rcu_read_lock();
+		err = ip6_xmit(sk, skb, &fl6, rcu_dereference(np->opt),
+			       np->tclass);
+		rcu_read_unlock();
 		err = net_xmit_eval(err);
 	}
 
@@ -450,6 +455,7 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
 {
 	struct inet_request_sock *ireq = inet_rsk(req);
 	struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
+	struct ipv6_txoptions *opt;
 	struct inet_sock *newinet;
 	struct dccp6_sock *newdp6;
 	struct sock *newsk;
@@ -573,13 +579,15 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
 	 * Yes, keeping reference count would be much more clever, but we make
 	 * one more one thing there: reattach optmem to newsk.
 	 */
-	if (np->opt != NULL)
-		newnp->opt = ipv6_dup_options(newsk, np->opt);
-
+	opt = rcu_dereference(np->opt);
+	if (opt) {
+		opt = ipv6_dup_options(newsk, opt);
+		RCU_INIT_POINTER(newnp->opt, opt);
+	}
 	inet_csk(newsk)->icsk_ext_hdr_len = 0;
-	if (newnp->opt != NULL)
-		inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
-						     newnp->opt->opt_flen);
+	if (opt)
+		inet_csk(newsk)->icsk_ext_hdr_len = opt->opt_nflen +
+						    opt->opt_flen;
 
 	dccp_sync_mss(newsk, dst_mtu(dst));
 
@@ -831,6 +839,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct dccp_sock *dp = dccp_sk(sk);
 	struct in6_addr *saddr = NULL, *final_p, final;
+	struct ipv6_txoptions *opt;
 	struct flowi6 fl6;
 	struct dst_entry *dst;
 	int addr_type;
@@ -932,7 +941,8 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
 	fl6.fl6_sport = inet->inet_sport;
 	security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
 
-	final_p = fl6_update_dst(&fl6, np->opt, &final);
+	opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk));
+	final_p = fl6_update_dst(&fl6, opt, &final);
 
 	dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
 	if (IS_ERR(dst)) {
@@ -952,9 +962,8 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
 	__ip6_dst_store(sk, dst, NULL, NULL);
 
 	icsk->icsk_ext_hdr_len = 0;
-	if (np->opt != NULL)
-		icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
-					  np->opt->opt_nflen);
+	if (opt)
+		icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen;
 
 	inet->inet_dport = usin->sin6_port;
 
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 7cb4392690dd..8966f3ca0d59 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -425,9 +425,11 @@ void inet6_destroy_sock(struct sock *sk)
 
 	/* Free tx options */
 
-	opt = xchg(&np->opt, NULL);
-	if (opt != NULL)
-		sock_kfree_s(sk, opt, opt->tot_len);
+	opt = xchg((__force struct ipv6_txoptions **)&np->opt, NULL);
+	if (opt) {
+		atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
+		txopt_put(opt);
+	}
 }
 EXPORT_SYMBOL_GPL(inet6_destroy_sock);
 
@@ -656,7 +658,10 @@ int inet6_sk_rebuild_header(struct sock *sk)
 		fl6.fl6_sport = inet->inet_sport;
 		security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
 
-		final_p = fl6_update_dst(&fl6, np->opt, &final);
+		rcu_read_lock();
+		final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt),
+					 &final);
+		rcu_read_unlock();
 
 		dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
 		if (IS_ERR(dst)) {
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index 6b89b2a1ac74..ec4c8be39488 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -167,8 +167,10 @@ ipv4_connected:
 
 	security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
 
-	opt = flowlabel ? flowlabel->opt : np->opt;
+	rcu_read_lock();
+	opt = flowlabel ? flowlabel->opt : rcu_dereference(np->opt);
 	final_p = fl6_update_dst(&fl6, opt, &final);
+	rcu_read_unlock();
 
 	dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
 	err = 0;
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 8d67900aa003..33dbd6c1a00d 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -727,6 +727,7 @@ ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
 			*((char **)&opt2->dst1opt) += dif;
 		if (opt2->srcrt)
 			*((char **)&opt2->srcrt) += dif;
+		atomic_set(&opt2->refcnt, 1);
 	}
 	return opt2;
 }
@@ -790,7 +791,7 @@ ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
 		return ERR_PTR(-ENOBUFS);
 
 	memset(opt2, 0, tot_len);
-
+	atomic_set(&opt2->refcnt, 1);
 	opt2->tot_len = tot_len;
 	p = (char *)(opt2 + 1);
 
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index a245e5ddffbd..c3f50bbf6746 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -78,7 +78,9 @@ struct dst_entry *inet6_csk_route_req(struct sock *sk,
 	memset(fl6, 0, sizeof(*fl6));
 	fl6->flowi6_proto = IPPROTO_TCP;
 	fl6->daddr = ireq->ir_v6_rmt_addr;
-	final_p = fl6_update_dst(fl6, np->opt, &final);
+	rcu_read_lock();
+	final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final);
+	rcu_read_unlock();
 	fl6->saddr = ireq->ir_v6_loc_addr;
 	fl6->flowi6_oif = ireq->ir_iif;
 	fl6->flowi6_mark = ireq->ir_mark;
@@ -212,7 +214,9 @@ static struct dst_entry *inet6_csk_route_socket(struct sock *sk,
 	fl6->fl6_dport = inet->inet_dport;
 	security_sk_classify_flow(sk, flowi6_to_flowi(fl6));
 
-	final_p = fl6_update_dst(fl6, np->opt, &final);
+	rcu_read_lock();
+	final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final);
+	rcu_read_unlock();
 
 	dst = __inet6_csk_dst_check(sk, np->dst_cookie);
 	if (!dst) {
@@ -245,7 +249,8 @@ int inet6_csk_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl_unused
 	/* Restore final destination back after routing done */
 	fl6.daddr = sk->sk_v6_daddr;
 
-	res = ip6_xmit(sk, skb, &fl6, np->opt, np->tclass);
+	res = ip6_xmit(sk, skb, &fl6, rcu_dereference(np->opt),
+		       np->tclass);
 	rcu_read_unlock();
 	return res;
 }
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index edb58aff4ae7..acda3ed4ba7e 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -110,10 +110,12 @@ struct ipv6_txoptions *ipv6_update_options(struct sock *sk,
 			icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen;
 			icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie);
 		}
-		opt = xchg(&inet6_sk(sk)->opt, opt);
+		opt = xchg((__force struct ipv6_txoptions **)&inet6_sk(sk)->opt,
+			   opt);
 	} else {
 		spin_lock(&sk->sk_dst_lock);
-		opt = xchg(&inet6_sk(sk)->opt, opt);
+		opt = xchg((__force struct ipv6_txoptions **)&inet6_sk(sk)->opt,
+			   opt);
 		spin_unlock(&sk->sk_dst_lock);
 	}
 	sk_dst_reset(sk);
@@ -213,9 +215,12 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
 				sk->sk_socket->ops = &inet_dgram_ops;
 				sk->sk_family = PF_INET;
 			}
-			opt = xchg(&np->opt, NULL);
-			if (opt)
-				sock_kfree_s(sk, opt, opt->tot_len);
+			opt = xchg((__force struct ipv6_txoptions **)&np->opt,
+				   NULL);
+			if (opt) {
+				atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
+				txopt_put(opt);
+			}
 			pktopt = xchg(&np->pktoptions, NULL);
 			kfree_skb(pktopt);
 
@@ -385,7 +390,8 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
 		if (optname != IPV6_RTHDR && !ns_capable(net->user_ns, CAP_NET_RAW))
 			break;
 
-		opt = ipv6_renew_options(sk, np->opt, optname,
+		opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk));
+		opt = ipv6_renew_options(sk, opt, optname,
 					 (struct ipv6_opt_hdr __user *)optval,
 					 optlen);
 		if (IS_ERR(opt)) {
@@ -414,8 +420,10 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
 		retv = 0;
 		opt = ipv6_update_options(sk, opt);
 sticky_done:
-		if (opt)
-			sock_kfree_s(sk, opt, opt->tot_len);
+		if (opt) {
+			atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
+			txopt_put(opt);
+		}
 		break;
 	}
 
@@ -468,6 +476,7 @@ sticky_done:
 			break;
 
 		memset(opt, 0, sizeof(*opt));
+		atomic_set(&opt->refcnt, 1);
 		opt->tot_len = sizeof(*opt) + optlen;
 		retv = -EFAULT;
 		if (copy_from_user(opt+1, optval, optlen))
@@ -484,8 +493,10 @@ update:
 		retv = 0;
 		opt = ipv6_update_options(sk, opt);
 done:
-		if (opt)
-			sock_kfree_s(sk, opt, opt->tot_len);
+		if (opt) {
+			atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
+			txopt_put(opt);
+		}
 		break;
 	}
 	case IPV6_UNICAST_HOPS:
@@ -1090,10 +1101,11 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
 	case IPV6_RTHDR:
 	case IPV6_DSTOPTS:
 	{
+		struct ipv6_txoptions *opt;
 
 		lock_sock(sk);
-		len = ipv6_getsockopt_sticky(sk, np->opt,
-					     optname, optval, len);
+		opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk));
+		len = ipv6_getsockopt_sticky(sk, opt, optname, optval, len);
 		release_sock(sk);
 		/* check if ipv6_getsockopt_sticky() returns err code */
 		if (len < 0)
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index fd377c4d8986..a652fdb6bd5d 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -737,6 +737,7 @@ static int rawv6_probe_proto_opt(struct flowi6 *fl6, struct msghdr *msg)
 static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
 		   struct msghdr *msg, size_t len)
 {
+	struct ipv6_txoptions *opt_to_free = NULL;
 	struct ipv6_txoptions opt_space;
 	DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name);
 	struct in6_addr *daddr, *final_p, final;
@@ -842,8 +843,10 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
 		if (!(opt->opt_nflen|opt->opt_flen))
 			opt = NULL;
 	}
-	if (opt == NULL)
-		opt = np->opt;
+	if (!opt) {
+		opt = txopt_get(np);
+		opt_to_free = opt;
+		}
 	if (flowlabel)
 		opt = fl6_merge_options(&opt_space, flowlabel, opt);
 	opt = ipv6_fixup_options(&opt_space, opt);
@@ -904,6 +907,7 @@ done:
 	dst_release(dst);
 out:
 	fl6_sock_release(flowlabel);
+	txopt_put(opt_to_free);
 	return err<0?err:len;
 do_confirm:
 	dst_confirm(dst);
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index a822b880689b..da22766765d3 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -241,7 +241,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
 		memset(&fl6, 0, sizeof(fl6));
 		fl6.flowi6_proto = IPPROTO_TCP;
 		fl6.daddr = ireq->ir_v6_rmt_addr;
-		final_p = fl6_update_dst(&fl6, np->opt, &final);
+		final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt), &final);
 		fl6.saddr = ireq->ir_v6_loc_addr;
 		fl6.flowi6_oif = sk->sk_bound_dev_if;
 		fl6.flowi6_mark = ireq->ir_mark;
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index f9f8bb3c2605..9a87a208732e 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -132,6 +132,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct tcp_sock *tp = tcp_sk(sk);
 	struct in6_addr *saddr = NULL, *final_p, final;
+	struct ipv6_txoptions *opt;
 	struct rt6_info *rt;
 	struct flowi6 fl6;
 	struct dst_entry *dst;
@@ -251,7 +252,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
 	fl6.fl6_dport = usin->sin6_port;
 	fl6.fl6_sport = inet->inet_sport;
 
-	final_p = fl6_update_dst(&fl6, np->opt, &final);
+	opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk));
+	final_p = fl6_update_dst(&fl6, opt, &final);
 
 	security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
 
@@ -280,9 +282,9 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
 		tcp_fetch_timewait_stamp(sk, dst);
 
 	icsk->icsk_ext_hdr_len = 0;
-	if (np->opt)
-		icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
-					  np->opt->opt_nflen);
+	if (opt)
+		icsk->icsk_ext_hdr_len = opt->opt_flen +
+					 opt->opt_nflen;
 
 	tp->rx_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
 
@@ -495,7 +497,8 @@ static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst,
 			fl6->flowlabel = ip6_flowlabel(ipv6_hdr(ireq->pktopts));
 
 		skb_set_queue_mapping(skb, queue_mapping);
-		err = ip6_xmit(sk, skb, fl6, np->opt, np->tclass);
+		err = ip6_xmit(sk, skb, fl6, rcu_dereference(np->opt),
+			       np->tclass);
 		err = net_xmit_eval(err);
 	}
 
@@ -1131,6 +1134,7 @@ static struct sock *tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
 {
 	struct inet_request_sock *ireq;
 	struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
+	struct ipv6_txoptions *opt;
 	struct tcp6_sock *newtcp6sk;
 	struct inet_sock *newinet;
 	struct tcp_sock *newtp;
@@ -1269,13 +1273,15 @@ static struct sock *tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
 	   but we make one more one thing there: reattach optmem
 	   to newsk.
 	 */
-	if (np->opt)
-		newnp->opt = ipv6_dup_options(newsk, np->opt);
-
+	opt = rcu_dereference(np->opt);
+	if (opt) {
+		opt = ipv6_dup_options(newsk, opt);
+		RCU_INIT_POINTER(newnp->opt, opt);
+	}
 	inet_csk(newsk)->icsk_ext_hdr_len = 0;
-	if (newnp->opt)
-		inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
-						     newnp->opt->opt_flen);
+	if (opt)
+		inet_csk(newsk)->icsk_ext_hdr_len = opt->opt_nflen +
+						    opt->opt_flen;
 
 	tcp_sync_mss(newsk, dst_mtu(dst));
 	newtp->advmss = dst_metric_advmss(dst);
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 72603a9af4bc..eb38829d8919 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -1082,6 +1082,7 @@ int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
 	DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name);
 	struct in6_addr *daddr, *final_p, final;
 	struct ipv6_txoptions *opt = NULL;
+	struct ipv6_txoptions *opt_to_free = NULL;
 	struct ip6_flowlabel *flowlabel = NULL;
 	struct flowi6 fl6;
 	struct dst_entry *dst;
@@ -1234,8 +1235,10 @@ do_udp_sendmsg:
 			opt = NULL;
 		connected = 0;
 	}
-	if (opt == NULL)
-		opt = np->opt;
+	if (!opt) {
+		opt = txopt_get(np);
+		opt_to_free = opt;
+	}
 	if (flowlabel)
 		opt = fl6_merge_options(&opt_space, flowlabel, opt);
 	opt = ipv6_fixup_options(&opt_space, opt);
@@ -1329,6 +1332,7 @@ do_append_data:
 out:
 	dst_release(dst);
 	fl6_sock_release(flowlabel);
+	txopt_put(opt_to_free);
 	if (!err)
 		return len;
 	/*
diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c
index f3f98a156cee..7c352ec09ec6 100644
--- a/net/l2tp/l2tp_ip6.c
+++ b/net/l2tp/l2tp_ip6.c
@@ -487,6 +487,7 @@ static int l2tp_ip6_sendmsg(struct kiocb *iocb, struct sock *sk,
 	DECLARE_SOCKADDR(struct sockaddr_l2tpip6 *, lsa, msg->msg_name);
 	struct in6_addr *daddr, *final_p, final;
 	struct ipv6_pinfo *np = inet6_sk(sk);
+	struct ipv6_txoptions *opt_to_free = NULL;
 	struct ipv6_txoptions *opt = NULL;
 	struct ip6_flowlabel *flowlabel = NULL;
 	struct dst_entry *dst = NULL;
@@ -576,8 +577,10 @@ static int l2tp_ip6_sendmsg(struct kiocb *iocb, struct sock *sk,
 			opt = NULL;
 	}
 
-	if (opt == NULL)
-		opt = np->opt;
+	if (!opt) {
+		opt = txopt_get(np);
+		opt_to_free = opt;
+	}
 	if (flowlabel)
 		opt = fl6_merge_options(&opt_space, flowlabel, opt);
 	opt = ipv6_fixup_options(&opt_space, opt);
@@ -632,6 +635,7 @@ done:
 	dst_release(dst);
 out:
 	fl6_sock_release(flowlabel);
+	txopt_put(opt_to_free);
 
 	return err < 0 ? err : len;
 

  parent reply	other threads:[~2016-01-06 11:07 UTC|newest]

Thread overview: 128+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-01-06 10:35 [3.16.y-ckt stable] Linux 3.16.7-ckt22 stable review Luis Henriques
2016-01-06 10:35 ` [PATCH 3.16.y-ckt 001/126] iio: lpc32xx_adc: fix warnings caused by enabling unprepared clock Luis Henriques
2016-01-06 10:35 ` [PATCH 3.16.y-ckt 002/126] iio:ad5064: Make sure ad5064_i2c_write() returns 0 on success Luis Henriques
2016-01-06 10:35 ` [PATCH 3.16.y-ckt 003/126] iio: ad5064: Fix ad5629/ad5669 shift Luis Henriques
2016-01-06 10:35 ` [PATCH 3.16.y-ckt 004/126] iio:ad7793: Fix ad7785 product ID Luis Henriques
2016-01-06 10:35 ` [PATCH 3.16.y-ckt 005/126] x86/fpu: Fix 32-bit signal frame handling Luis Henriques
2016-01-06 10:35 ` [PATCH 3.16.y-ckt 006/126] iio: adc: xilinx: Fix VREFN scale Luis Henriques
2016-01-06 10:35 ` [PATCH 3.16.y-ckt 007/126] drm/i915: quirk backlight present on Macbook 4, 1 Luis Henriques
2016-01-06 10:35 ` [PATCH 3.16.y-ckt 008/126] USB: qcserial: Add support for Quectel EC20 Mini PCIe module Luis Henriques
2016-01-06 10:35 ` [PATCH 3.16.y-ckt 009/126] USB: serial: option: add support for Novatel MiFi USB620L Luis Henriques
2016-01-06 10:35 ` [PATCH 3.16.y-ckt 010/126] USB: ti_usb_3410_5052: Add Honeywell HGI80 ID Luis Henriques
2016-01-06 10:35 ` [PATCH 3.16.y-ckt 011/126] drm/i915: get runtime PM reference around GEM set_caching IOCTL Luis Henriques
2016-01-06 10:35 ` [PATCH 3.16.y-ckt 012/126] drm/radeon: unconditionally set sysfs_initialized Luis Henriques
2016-01-06 10:35 ` [PATCH 3.16.y-ckt 013/126] USB: qcserial: Fix support for HP lt4112 LTE/HSPA+ Gobi 4G Modem Luis Henriques
2016-01-06 10:35 ` [PATCH 3.16.y-ckt 014/126] arm64: kernel: pause/unpause function graph tracer in cpu_suspend() Luis Henriques
2016-01-06 10:35 ` [PATCH 3.16.y-ckt 015/126] usb: dwc3: gadget: let us set lower max_speed Luis Henriques
2016-01-06 10:35 ` [PATCH 3.16.y-ckt 016/126] usb: chipidea: debug: disable usb irq while role switch Luis Henriques
2016-01-06 10:35 ` [PATCH 3.16.y-ckt 017/126] xhci: Workaround to get Intel xHCI reset working more reliably Luis Henriques
2016-01-06 10:35 ` [PATCH 3.16.y-ckt 018/126] xhci: Fix a race in usb2 LPM resume, blocking U3 for usb2 devices Luis Henriques
2016-01-06 10:35 ` [PATCH 3.16.y-ckt 019/126] x86/cpu: Fix SMAP check in PVOPS environments Luis Henriques
2016-01-06 10:35   ` Luis Henriques
2016-01-06 10:35 ` [PATCH 3.16.y-ckt 020/126] arm64: restore bogomips information in /proc/cpuinfo Luis Henriques
2016-01-06 10:35 ` [PATCH 3.16.y-ckt 021/126] USB: option: add XS Stick W100-2 from 4G Systems Luis Henriques
2016-01-06 10:35 ` [PATCH 3.16.y-ckt 022/126] usblp: do not set TASK_INTERRUPTIBLE before lock Luis Henriques
2016-01-06 10:35 ` [PATCH 3.16.y-ckt 023/126] fat: fix fake_offset handling on error path Luis Henriques
2016-01-06 10:35 ` [PATCH 3.16.y-ckt 024/126] kernel/signal.c: unexport sigsuspend() Luis Henriques
2016-01-06 10:35 ` [PATCH 3.16.y-ckt 025/126] ocfs2: fix umask ignored issue Luis Henriques
2016-01-06 10:35 ` [PATCH 3.16.y-ckt 026/126] parisc: Drop unused MADV_xxxK_PAGES flags from asm/mman.h Luis Henriques
2016-01-06 10:35 ` [PATCH 3.16.y-ckt 027/126] mmc: remove bondage between REQ_META and reliable write Luis Henriques
2016-01-06 10:35 ` [PATCH 3.16.y-ckt 028/126] tools/net: Use include/uapi with __EXPORTED_HEADERS__ Luis Henriques
2016-01-06 10:35 ` [PATCH 3.16.y-ckt 029/126] packet: do skb_probe_transport_header when we actually have data Luis Henriques
2016-01-06 10:35 ` [PATCH 3.16.y-ckt 030/126] packet: only allow extra vlan len on ethernet devices Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 031/126] packet: fix tpacket_snd max frame len Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 032/126] sctp: translate host order to network order when setting a hmacid Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 033/126] net/mlx4_core: Avoid returning success in case of an error flow Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 034/126] usb: musb: core: fix order of arguments to ulpi write callback Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 035/126] FS-Cache: Add missing initialization of ret in cachefiles_write_page() Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 036/126] macvlan: fix leak in macvlan_handle_frame Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 037/126] ARC: Fix silly typo in MAINTAINERS file Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 038/126] unix: avoid use-after-free in ep_remove_wait_queue Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 039/126] packet: always probe for transport header Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 040/126] packet: infer protocol from ethernet header if unset Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 041/126] ip_tunnel: disable preemption when updating per-cpu tstats Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 042/126] snmp: Remove duplicate OUTMCAST stat increment Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 043/126] net: qmi_wwan: add XS Stick W100-2 from 4G Systems Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 044/126] tcp: md5: fix lockdep annotation Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 045/126] tcp: initialize tp->copied_seq in case of cross SYN connection Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 046/126] net, scm: fix PaX detected msg_controllen overflow in scm_detach_fds Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 047/126] net: ipmr: fix static mfc/dev leaks on table destruction Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 048/126] net: ip6mr: " Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 049/126] broadcom: fix PHY_ID_BCM5481 entry in the id table Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 050/126] ipv6: distinguish frag queues by device for multicast and link-local packets Luis Henriques
2016-01-06 10:36 ` Luis Henriques [this message]
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 052/126] net/neighbour: fix crash at dumping device-agnostic proxy entries Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 053/126] ipv6: sctp: implement sctp_v6_destroy_sock() Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 054/126] xfs: allow inode allocations in post-growfs disk space Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 055/126] ALSA: usb-audio: add packet size quirk for the Medeli DD305 Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 056/126] ALSA: usb-audio: prevent CH345 multiport output SysEx corruption Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 057/126] ALSA: usb-audio: work around CH345 input " Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 058/126] dm thin: restore requested 'error_if_no_space' setting on OODS to WRITE transition Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 059/126] dm: fix ioctl retry termination with signal Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 060/126] MIPS: KVM: Fix ASID restoration logic Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 061/126] MIPS: KVM: Fix CACHE immediate offset sign extension Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 062/126] MIPS: KVM: Uninit VCPU in vcpu_create error path Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 063/126] ALSA: hda - Add fixup for Acer Aspire One Cloudbook 14 Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 064/126] mac: validate mac_partition is within sector Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 065/126] ALSA: hda - Apply HP headphone fixups more generically Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 066/126] powerpc/tm: Block signal return setting invalid MSR state Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 067/126] powerpc/tm: Check for already reclaimed tasks Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 068/126] ARC: dw2 unwind: Remove falllback linear search thru FDE entries Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 069/126] fix sysvfs symlinks Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 070/126] vfs: Make sendfile(2) killable even better Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 071/126] vfs: Avoid softlockups with sendfile(2) Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 072/126] nfs4: start callback_ident at idr 1 Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 073/126] ALSA: hda - Fix headphone noise after Dell XPS 13 resume back from S3 Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 074/126] arm64: KVM: Fix AArch32 to AArch64 register mapping Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 075/126] drm/radeon: make rv770_set_sw_state failures non-fatal Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 076/126] ALSA: hda - Fix noise on Gigabyte Z170X mobo Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 077/126] drm/radeon: make some dpm errors debug only Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 078/126] nfs: if we have no valid attrs, then don't declare the attribute cache valid Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 079/126] xen/gntdev: Grant maps should not be subject to NUMA balancing Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 080/126] iscsi-target: Fix rx_login_comp hang after login failure Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 081/126] target: Fix race for SCF_COMPARE_AND_WRITE_POST checking Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 082/126] target: fix COMPARE_AND_WRITE non zero SGL offset data corruption Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 083/126] ARM: dts: Kirkwood: Fix QNAP TS219 power-off Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 084/126] netfilter: ipt_rpfilter: remove the nh_scope test in rpfilter_lookup_reverse Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 085/126] netfilter: nf_tables: fix bogus warning in nft_data_uninit() Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 086/126] netfilter: ip6t_SYNPROXY: fix NULL pointer dereference Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 087/126] RDS: fix race condition when sending a message on unbound socket Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 088/126] gre6: allow to update all parameters via rtnl Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 089/126] atl1c: Improve driver not to do order 4 GFP_ATOMIC allocation Luis Henriques
2016-01-06 10:36 ` [PATCH 3.16.y-ckt 090/126] sctp: use the same clock as if sock source timestamps were on Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 091/126] sctp: update the netstamp_needed counter when copying sockets Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 092/126] ipv6: sctp: clone options to avoid use after free Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 093/126] net: add validation for the socket syscall protocol argument Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 094/126] sh_eth: fix kernel oops in skb_put() Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 095/126] vlan: Fix untag operations of stacked vlans with REORDER_HEADER off Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 096/126] skbuff: Fix offset error in skb_reorder_vlan_header Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 097/126] pptp: verify sockaddr_len in pptp_bind() and pptp_connect() Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 098/126] bluetooth: Validate socket address length in sco_sock_bind() Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 099/126] af_unix: Revert 'lock_interruptible' in stream receive code Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 100/126] ip6mr: call del_timer_sync() in ip6mr_free_table() Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 101/126] drm/i915: Disable PSMI sleep messages on all rings around context switches Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 102/126] crypto: nx - Fix timing leak in GCM and CCM decryption Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 103/126] crypto: talitos - Fix timing leak in ESP ICV verification Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 104/126] ASoC: wm8962: correct addresses for HPF_C_0/1 Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 105/126] mac80211: mesh: fix call_rcu() usage Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 106/126] mac80211: ensure we don't update tx power on a non-running sdata Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 107/126] can: sja1000: clear interrupts on start Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 108/126] ring-buffer: Update read stamp with first real commit on page Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 109/126] block: Always check queue limits for cloned requests Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 110/126] Fix a memory leak in scsi_host_dev_release() Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 111/126] wan/x25: Fix use-after-free in x25_asy_open_tty() Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 112/126] mac80211: do not actively scan DFS channels Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 113/126] locking: Add WARN_ON_ONCE lock assertion Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 114/126] drm: Fix an unwanted master inheritance v2 Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 115/126] sched/core: Clear the root_domain cpumasks in init_rootdomain() Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 116/126] x86/signal: Fix restart_syscall number for x32 tasks Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 117/126] isdn: Partially revert debug format string usage clean up Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 118/126] remoteproc: avoid stack overflow in debugfs file Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 119/126] net: mvneta: add configuration for MBUS windows access protection Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 120/126] net: mvneta: fix bit assignment in MVNETA_RXQ_CONFIG_REG Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 121/126] net: mvneta: fix bit assignment for RX packet irq enable Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 122/126] ipv4: igmp: Allow removing groups from a removed interface Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 123/126] sched/core: Remove false-positive warning from wake_up_process() Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 124/126] btrfs: fix signed overflows in btrfs_sync_file Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 125/126] KEYS: Fix race between read and revoke Luis Henriques
2016-01-06 10:37 ` [PATCH 3.16.y-ckt 126/126] KVM: x86: Reload pit counters for all channels when restoring state Luis Henriques

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1452076655-12851-52-git-send-email-luis.henriques@canonical.com \
    --to=luis.henriques@canonical.com \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=kernel-team@lists.ubuntu.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.