diff options
Diffstat (limited to 'net/ipv4/tcp_input.c')
| -rw-r--r-- | net/ipv4/tcp_input.c | 82 | 
1 files changed, 55 insertions, 27 deletions
| diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 432c36649db3..a13692560e63 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3552,6 +3552,24 @@ static bool tcp_process_frto(struct sock *sk, int flag)  	return false;  } +/* RFC 5961 7 [ACK Throttling] */ +static void tcp_send_challenge_ack(struct sock *sk) +{ +	/* unprotected vars, we dont care of overwrites */ +	static u32 challenge_timestamp; +	static unsigned int challenge_count; +	u32 now = jiffies / HZ; + +	if (now != challenge_timestamp) { +		challenge_timestamp = now; +		challenge_count = 0; +	} +	if (++challenge_count <= sysctl_tcp_challenge_ack_limit) { +		NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPCHALLENGEACK); +		tcp_send_ack(sk); +	} +} +  /* This routine deals with incoming acks, but not outgoing ones. */  static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)  { @@ -3571,8 +3589,14 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)  	/* If the ack is older than previous acks  	 * then we can probably ignore it.  	 */ -	if (before(ack, prior_snd_una)) +	if (before(ack, prior_snd_una)) { +		/* RFC 5961 5.2 [Blind Data Injection Attack].[Mitigation] */ +		if (before(ack, prior_snd_una - tp->max_window)) { +			tcp_send_challenge_ack(sk); +			return -1; +		}  		goto old_ack; +	}  	/* If the ack includes data we haven't sent yet, discard  	 * this segment (RFC793 Section 3.9). @@ -4529,6 +4553,9 @@ int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size)  	struct tcphdr *th;  	bool fragstolen; +	if (size == 0) +		return 0; +  	skb = alloc_skb(size + sizeof(*th), sk->sk_allocation);  	if (!skb)  		goto err; @@ -5241,23 +5268,6 @@ out:  }  #endif /* CONFIG_NET_DMA */ -static void tcp_send_challenge_ack(struct sock *sk) -{ -	/* unprotected vars, we dont care of overwrites */ -	static u32 challenge_timestamp; -	static unsigned int challenge_count; -	u32 now = jiffies / HZ; - -	if (now != challenge_timestamp) { -		challenge_timestamp = now; -		challenge_count = 0; -	} -	if (++challenge_count <= sysctl_tcp_challenge_ack_limit) { -		NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPCHALLENGEACK); -		tcp_send_ack(sk); -	} -} -  /* Does PAWS and seqno based validation of an incoming segment, flags will   * play significant role here.   */ @@ -5310,11 +5320,6 @@ static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb,  		goto discard;  	} -	/* ts_recent update must be made after we are sure that the packet -	 * is in window. -	 */ -	tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq); -  	/* step 3: check security and precedence [ignored] */  	/* step 4: Check for a SYN @@ -5549,6 +5554,11 @@ step5:  	if (th->ack && tcp_ack(sk, skb, FLAG_SLOWPATH) < 0)  		goto discard; +	/* ts_recent update must be made after we are sure that the packet +	 * is in window. +	 */ +	tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq); +  	tcp_rcv_rtt_measure_ts(sk, skb);  	/* Process urgent data. */ @@ -5642,10 +5652,15 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack,  	tcp_fastopen_cache_set(sk, mss, cookie, syn_drop);  	if (data) { /* Retransmit unacked data in SYN */ -		tcp_retransmit_skb(sk, data); +		tcp_for_write_queue_from(data, sk) { +			if (data == tcp_send_head(sk) || +			    __tcp_retransmit_skb(sk, data)) +				break; +		}  		tcp_rearm_rto(sk);  		return true;  	} +	tp->syn_data_acked = tp->syn_data;  	return false;  } @@ -5963,7 +5978,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,  	req = tp->fastopen_rsk;  	if (req != NULL) { -		BUG_ON(sk->sk_state != TCP_SYN_RECV && +		WARN_ON_ONCE(sk->sk_state != TCP_SYN_RECV &&  		    sk->sk_state != TCP_FIN_WAIT1);  		if (tcp_check_req(sk, skb, req, NULL, true) == NULL) @@ -5984,7 +5999,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,  				 */  				if (req) {  					tcp_synack_rtt_meas(sk, req); -					tp->total_retrans = req->retrans; +					tp->total_retrans = req->num_retrans;  					reqsk_fastopen_remove(sk, req, false);  				} else { @@ -6052,7 +6067,15 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,  			 * ACK we have received, this would have acknowledged  			 * our SYNACK so stop the SYNACK timer.  			 */ -			if (acceptable && req != NULL) { +			if (req != NULL) { +				/* Return RST if ack_seq is invalid. +				 * Note that RFC793 only says to generate a +				 * DUPACK for it but for TCP Fast Open it seems +				 * better to treat this case like TCP_SYN_RECV +				 * above. +				 */ +				if (!acceptable) +					return 1;  				/* We no longer need the request sock. */  				reqsk_fastopen_remove(sk, req, false);  				tcp_rearm_rto(sk); @@ -6118,6 +6141,11 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,  	} else  		goto discard; +	/* ts_recent update must be made after we are sure that the packet +	 * is in window. +	 */ +	tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq); +  	/* step 6: check the URG bit */  	tcp_urg(sk, skb, th); |