diff options
Diffstat (limited to 'net/ipv6/tcp_ipv6.c')
| -rw-r--r-- | net/ipv6/tcp_ipv6.c | 82 | 
1 files changed, 52 insertions, 30 deletions
| diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 8e42e8f54b70..2521690d62d6 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -101,12 +101,18 @@ static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)  	}  } -static u32 tcp_v6_init_seq_and_tsoff(const struct sk_buff *skb, u32 *tsoff) +static u32 tcp_v6_init_seq(const struct sk_buff *skb)  { -	return secure_tcpv6_seq_and_tsoff(ipv6_hdr(skb)->daddr.s6_addr32, -					  ipv6_hdr(skb)->saddr.s6_addr32, -					  tcp_hdr(skb)->dest, -					  tcp_hdr(skb)->source, tsoff); +	return secure_tcpv6_seq(ipv6_hdr(skb)->daddr.s6_addr32, +				ipv6_hdr(skb)->saddr.s6_addr32, +				tcp_hdr(skb)->dest, +				tcp_hdr(skb)->source); +} + +static u32 tcp_v6_init_ts_off(const struct net *net, const struct sk_buff *skb) +{ +	return secure_tcpv6_ts_off(net, ipv6_hdr(skb)->daddr.s6_addr32, +				   ipv6_hdr(skb)->saddr.s6_addr32);  }  static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, @@ -122,7 +128,6 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,  	struct flowi6 fl6;  	struct dst_entry *dst;  	int addr_type; -	u32 seq;  	int err;  	struct inet_timewait_death_row *tcp_death_row = &sock_net(sk)->ipv4.tcp_death_row; @@ -282,13 +287,14 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,  	sk_set_txhash(sk);  	if (likely(!tp->repair)) { -		seq = secure_tcpv6_seq_and_tsoff(np->saddr.s6_addr32, -						 sk->sk_v6_daddr.s6_addr32, -						 inet->inet_sport, -						 inet->inet_dport, -						 &tp->tsoffset);  		if (!tp->write_seq) -			tp->write_seq = seq; +			tp->write_seq = secure_tcpv6_seq(np->saddr.s6_addr32, +							 sk->sk_v6_daddr.s6_addr32, +							 inet->inet_sport, +							 inet->inet_dport); +		tp->tsoffset = secure_tcpv6_ts_off(sock_net(sk), +						   np->saddr.s6_addr32, +						   sk->sk_v6_daddr.s6_addr32);  	}  	if (tcp_fastopen_defer_connect(sk, &err)) @@ -509,11 +515,12 @@ static struct tcp_md5sig_key *tcp_v6_md5_lookup(const struct sock *sk,  	return tcp_v6_md5_do_lookup(sk, &addr_sk->sk_v6_daddr);  } -static int tcp_v6_parse_md5_keys(struct sock *sk, char __user *optval, -				 int optlen) +static int tcp_v6_parse_md5_keys(struct sock *sk, int optname, +				 char __user *optval, int optlen)  {  	struct tcp_md5sig cmd;  	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&cmd.tcpm_addr; +	u8 prefixlen;  	if (optlen < sizeof(cmd))  		return -EINVAL; @@ -524,12 +531,22 @@ static int tcp_v6_parse_md5_keys(struct sock *sk, char __user *optval,  	if (sin6->sin6_family != AF_INET6)  		return -EINVAL; +	if (optname == TCP_MD5SIG_EXT && +	    cmd.tcpm_flags & TCP_MD5SIG_FLAG_PREFIX) { +		prefixlen = cmd.tcpm_prefixlen; +		if (prefixlen > 128 || (ipv6_addr_v4mapped(&sin6->sin6_addr) && +					prefixlen > 32)) +			return -EINVAL; +	} else { +		prefixlen = ipv6_addr_v4mapped(&sin6->sin6_addr) ? 32 : 128; +	} +  	if (!cmd.tcpm_keylen) {  		if (ipv6_addr_v4mapped(&sin6->sin6_addr))  			return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3], -					      AF_INET); +					      AF_INET, prefixlen);  		return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr, -				      AF_INET6); +				      AF_INET6, prefixlen);  	}  	if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN) @@ -537,10 +554,12 @@ static int tcp_v6_parse_md5_keys(struct sock *sk, char __user *optval,  	if (ipv6_addr_v4mapped(&sin6->sin6_addr))  		return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3], -				      AF_INET, cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL); +				      AF_INET, prefixlen, cmd.tcpm_key, +				      cmd.tcpm_keylen, GFP_KERNEL);  	return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin6->sin6_addr, -			      AF_INET6, cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL); +			      AF_INET6, prefixlen, cmd.tcpm_key, +			      cmd.tcpm_keylen, GFP_KERNEL);  }  static int tcp_v6_md5_hash_headers(struct tcp_md5sig_pool *hp, @@ -715,7 +734,7 @@ static void tcp_v6_init_req(struct request_sock *req,  	     np->rxopt.bits.rxinfo ||  	     np->rxopt.bits.rxoinfo || np->rxopt.bits.rxhlim ||  	     np->rxopt.bits.rxohlim || np->repflow)) { -		atomic_inc(&skb->users); +		refcount_inc(&skb->users);  		ireq->pktopts = skb;  	}  } @@ -749,7 +768,8 @@ static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = {  	.cookie_init_seq =	cookie_v6_init_sequence,  #endif  	.route_req	=	tcp_v6_route_req, -	.init_seq_tsoff	=	tcp_v6_init_seq_and_tsoff, +	.init_seq	=	tcp_v6_init_seq, +	.init_ts_off	=	tcp_v6_init_ts_off,  	.send_synack	=	tcp_v6_send_synack,  }; @@ -782,7 +802,7 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32  	skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len); -	t1 = (struct tcphdr *) skb_push(buff, tot_len); +	t1 = skb_push(buff, tot_len);  	skb_reset_transport_header(buff);  	/* Swap the send and the receive. */ @@ -943,7 +963,7 @@ static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)  	tcp_v6_send_ack(sk, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,  			tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, -			tcp_time_stamp + tcptw->tw_ts_offset, +			tcp_time_stamp_raw() + tcptw->tw_ts_offset,  			tcptw->tw_ts_recent, tw->tw_bound_dev_if, tcp_twsk_md5_key(tcptw),  			tw->tw_tclass, cpu_to_be32(tw->tw_flowlabel)); @@ -965,7 +985,7 @@ static void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb,  			tcp_rsk(req)->snt_isn + 1 : tcp_sk(sk)->snd_nxt,  			tcp_rsk(req)->rcv_nxt,  			req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale, -			tcp_time_stamp + tcp_rsk(req)->ts_off, +			tcp_time_stamp_raw() + tcp_rsk(req)->ts_off,  			req->ts_recent, sk->sk_bound_dev_if,  			tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr),  			0, 0); @@ -1056,6 +1076,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *  		newtp->af_specific = &tcp_sock_ipv6_mapped_specific;  #endif +		newnp->ipv6_mc_list = NULL;  		newnp->ipv6_ac_list = NULL;  		newnp->ipv6_fl_list = NULL;  		newnp->pktoptions  = NULL; @@ -1125,6 +1146,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *  	   First: no IPv4 options.  	 */  	newinet->inet_opt = NULL; +	newnp->ipv6_mc_list = NULL;  	newnp->ipv6_ac_list = NULL;  	newnp->ipv6_fl_list = NULL; @@ -1177,7 +1199,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *  		 * across. Shucks.  		 */  		tcp_md5_do_add(newsk, (union tcp_md5_addr *)&newsk->sk_v6_daddr, -			       AF_INET6, key->key, key->keylen, +			       AF_INET6, 128, key->key, key->keylen,  			       sk_gfp_mask(sk, GFP_ATOMIC));  	}  #endif @@ -1240,9 +1262,6 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)  	if (skb->protocol == htons(ETH_P_IP))  		return tcp_v4_do_rcv(sk, skb); -	if (tcp_filter(sk, skb)) -		goto discard; -  	/*  	 *	socket locking is here for SMP purposes as backlog rcv  	 *	is currently called with bh processing disabled. @@ -1445,6 +1464,8 @@ process:  		if (nsk == sk) {  			reqsk_put(req);  			tcp_v6_restore_cb(skb); +		} else if (tcp_filter(sk, skb)) { +			goto discard_and_relse;  		} else if (tcp_child_process(sk, nsk, skb)) {  			tcp_v6_send_reset(nsk, skb);  			goto discard_and_relse; @@ -1788,7 +1809,7 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)  		   from_kuid_munged(seq_user_ns(seq), sock_i_uid(sp)),  		   icsk->icsk_probes_out,  		   sock_i_ino(sp), -		   atomic_read(&sp->sk_refcnt), sp, +		   refcount_read(&sp->sk_refcnt), sp,  		   jiffies_to_clock_t(icsk->icsk_rto),  		   jiffies_to_clock_t(icsk->icsk_ack.ato),  		   (icsk->icsk_ack.quick << 1) | icsk->icsk_ack.pingpong, @@ -1821,7 +1842,7 @@ static void get_timewait6_sock(struct seq_file *seq,  		   dest->s6_addr32[2], dest->s6_addr32[3], destp,  		   tw->tw_substate, 0, 0,  		   3, jiffies_delta_to_clock_t(delta), 0, 0, 0, 0, -		   atomic_read(&tw->tw_refcnt), tw); +		   refcount_read(&tw->tw_refcnt), tw);  }  static int tcp6_seq_show(struct seq_file *seq, void *v) @@ -1901,6 +1922,7 @@ struct proto tcpv6_prot = {  	.unhash			= inet_unhash,  	.get_port		= inet_csk_get_port,  	.enter_memory_pressure	= tcp_enter_memory_pressure, +	.leave_memory_pressure	= tcp_leave_memory_pressure,  	.stream_memory_free	= tcp_stream_memory_free,  	.sockets_allocated	= &tcp_sockets_allocated,  	.memory_allocated	= &tcp_memory_allocated, @@ -1911,7 +1933,7 @@ struct proto tcpv6_prot = {  	.sysctl_rmem		= sysctl_tcp_rmem,  	.max_header		= MAX_TCP_HEADER,  	.obj_size		= sizeof(struct tcp6_sock), -	.slab_flags		= SLAB_DESTROY_BY_RCU, +	.slab_flags		= SLAB_TYPESAFE_BY_RCU,  	.twsk_prot		= &tcp6_timewait_sock_ops,  	.rsk_prot		= &tcp6_request_sock_ops,  	.h.hashinfo		= &tcp_hashinfo, |