aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJerry Chu <hkchu@google.com>2012-10-22 07:26:36 -0400
committerDavid S. Miller <davem@davemloft.net>2012-10-23 02:42:56 -0400
commit37561f68bd527ec39076e32effdc7b1dcdfb17ea (patch)
tree3b15ff453617ee5ef52e5f7a9885770b4172bc0a /net
parent0b63bf1fe6f9ed1ec4148e8896f4522e08476b80 (diff)
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: H.K. Jerry Chu <hkchu@google.com> Cc: Neal Cardwell <ncardwell@google.com> Cc: Yuchung Cheng <ycheng@google.com> Acked-by: Yuchung Cheng <ycheng@google.com> Acked-by: Eric Dumazet <edumazet@google.com> Acked-by: Neal Cardwell <ncardwell@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/tcp_input.c12
-rw-r--r--net/ipv4/tcp_timer.c4
2 files changed, 12 insertions, 4 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 036f8573814..1db66398358 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5964,7 +5964,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
5964 5964
5965 req = tp->fastopen_rsk; 5965 req = tp->fastopen_rsk;
5966 if (req != NULL) { 5966 if (req != NULL) {
5967 BUG_ON(sk->sk_state != TCP_SYN_RECV && 5967 WARN_ON_ONCE(sk->sk_state != TCP_SYN_RECV &&
5968 sk->sk_state != TCP_FIN_WAIT1); 5968 sk->sk_state != TCP_FIN_WAIT1);
5969 5969
5970 if (tcp_check_req(sk, skb, req, NULL, true) == NULL) 5970 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,
6053 * ACK we have received, this would have acknowledged 6053 * ACK we have received, this would have acknowledged
6054 * our SYNACK so stop the SYNACK timer. 6054 * our SYNACK so stop the SYNACK timer.
6055 */ 6055 */
6056 if (acceptable && req != NULL) { 6056 if (req != NULL) {
6057 /* Return RST if ack_seq is invalid.
6058 * Note that RFC793 only says to generate a
6059 * DUPACK for it but for TCP Fast Open it seems
6060 * better to treat this case like TCP_SYN_RECV
6061 * above.
6062 */
6063 if (!acceptable)
6064 return 1;
6057 /* We no longer need the request sock. */ 6065 /* We no longer need the request sock. */
6058 reqsk_fastopen_remove(sk, req, false); 6066 reqsk_fastopen_remove(sk, req, false);
6059 tcp_rearm_rto(sk); 6067 tcp_rearm_rto(sk);
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index fc04711e80c..d47c1b4421a 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -347,8 +347,8 @@ void tcp_retransmit_timer(struct sock *sk)
347 return; 347 return;
348 } 348 }
349 if (tp->fastopen_rsk) { 349 if (tp->fastopen_rsk) {
350 BUG_ON(sk->sk_state != TCP_SYN_RECV && 350 WARN_ON_ONCE(sk->sk_state != TCP_SYN_RECV &&
351 sk->sk_state != TCP_FIN_WAIT1); 351 sk->sk_state != TCP_FIN_WAIT1);
352 tcp_fastopen_synack_timer(sk); 352 tcp_fastopen_synack_timer(sk);
353 /* Before we receive ACK to our SYN-ACK don't retransmit 353 /* Before we receive ACK to our SYN-ACK don't retransmit
354 * anything else (e.g., data or FIN segments). 354 * anything else (e.g., data or FIN segments).