diff options
Diffstat (limited to 'net/ipv6/tcp_ipv6.c')
| -rw-r--r-- | net/ipv6/tcp_ipv6.c | 32 | 
1 files changed, 19 insertions, 13 deletions
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index c5429a636f1a..e7aab561b7b4 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -120,6 +120,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 flowi6 fl6;  	struct dst_entry *dst;  	int addr_type; @@ -235,7 +236,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)); @@ -255,7 +257,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,  	inet->inet_rcv_saddr = LOOPBACK4_IPV6;  	sk->sk_gso_type = SKB_GSO_TCPV6; -	__ip6_dst_store(sk, dst, NULL, NULL); +	ip6_dst_store(sk, dst, NULL, NULL);  	if (tcp_death_row.sysctl_tw_recycle &&  	    !tp->rx_opt.ts_recent_stamp && @@ -263,9 +265,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); @@ -461,7 +463,8 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst,  		if (np->repflow && ireq->pktopts)  			fl6->flowlabel = ip6_flowlabel(ipv6_hdr(ireq->pktopts)); -		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);  	} @@ -972,6 +975,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *  	struct inet_request_sock *ireq;  	struct ipv6_pinfo *newnp;  	const struct ipv6_pinfo *np = inet6_sk(sk); +	struct ipv6_txoptions *opt;  	struct tcp6_sock *newtcp6sk;  	struct inet_sock *newinet;  	struct tcp_sock *newtp; @@ -1056,7 +1060,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *  	 */  	newsk->sk_gso_type = SKB_GSO_TCPV6; -	__ip6_dst_store(newsk, dst, NULL, NULL); +	ip6_dst_store(newsk, dst, NULL, NULL);  	inet6_sk_rx_dst_set(newsk, skb);  	newtcp6sk = (struct tcp6_sock *)newsk; @@ -1098,13 +1102,15 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *  	   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_ca_openreq_child(newsk, dst);  | 
