Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 37561f68 authored by Jerry Chu's avatar Jerry Chu Committed by David S. Miller
Browse files

tcp: Reject invalid ack_seq to Fast Open sockets



A packet with an invalid ack_seq may cause a TCP Fast Open socket to switch
to the unexpected TCP_CLOSING state, triggering a BUG_ON kernel panic.

When a FIN packet with an invalid ack_seq# arrives at a socket in
the TCP_FIN_WAIT1 state, rather than discarding the packet, the current
code will accept the FIN, causing state transition to TCP_CLOSING.

This may be a small deviation from RFC793, which seems to say that the
packet should be dropped. Unfortunately I did not expect this case for
Fast Open hence it will trigger a BUG_ON panic.

It turns out there is really nothing bad about a TFO socket going into
TCP_CLOSING state so I could just remove the BUG_ON statements. But after
some thought I think it's better to treat this case like TCP_SYN_RECV
and return a RST to the confused peer who caused the unacceptable ack_seq
to be generated in the first place.

Signed-off-by: default avatarH.K. Jerry Chu <hkchu@google.com>
Cc: Neal Cardwell <ncardwell@google.com>
Cc: Yuchung Cheng <ycheng@google.com>
Acked-by: default avatarYuchung Cheng <ycheng@google.com>
Acked-by: default avatarEric Dumazet <edumazet@google.com>
Acked-by: default avatarNeal Cardwell <ncardwell@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0b63bf1f
Loading
Loading
Loading
Loading
+10 −2
Original line number Diff line number Diff line
@@ -5964,7 +5964,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)
@@ -6053,7 +6053,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);
+2 −2
Original line number Diff line number Diff line
@@ -347,7 +347,7 @@ void tcp_retransmit_timer(struct sock *sk)
		return;
	}
	if (tp->fastopen_rsk) {
		BUG_ON(sk->sk_state != TCP_SYN_RECV &&
		WARN_ON_ONCE(sk->sk_state != TCP_SYN_RECV &&
			     sk->sk_state != TCP_FIN_WAIT1);
		tcp_fastopen_synack_timer(sk);
		/* Before we receive ACK to our SYN-ACK don't retransmit