tcp: should drop incoming frames without ACK flag set

In commit 96e0bf4b51 (tcp: Discard segments that ack data not yet
sent) John Dykstra enforced a check against ack sequences.

In commit 354e4aa391 (tcp: RFC 5961 5.2 Blind Data Injection Attack
Mitigation) I added more safety tests.

But we missed fact that these tests are not performed if ACK bit is
not set.

RFC 793 3.9 mandates TCP should drop a frame without ACK flag set.

" fifth check the ACK field,
      if the ACK bit is off drop the segment and return"

Not doing so permits an attacker to only guess an acceptable sequence
number, evading stronger checks.

Many thanks to Zhiyun Qian for bringing this issue to our attention.

See :
http://web.eecs.umich.edu/~zhiyunq/pub/ccs12_TCP_sequence_number_inference.pdf

Reported-by: Zhiyun Qian <zhiyunq@umich.edu>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Nandita Dukkipati <nanditad@google.com>
Cc: Neal Cardwell <ncardwell@google.com>
Cc: John Dykstra <john.dykstra1@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Eric Dumazet 2012-12-26 12:44:34 +00:00 committed by David S. Miller
parent 3d0dcfbd8f
commit c3ae62af8e

View File

@ -5543,6 +5543,9 @@ slow_path:
if (len < (th->doff << 2) || tcp_checksum_complete_user(sk, skb)) if (len < (th->doff << 2) || tcp_checksum_complete_user(sk, skb))
goto csum_error; goto csum_error;
if (!th->ack)
goto discard;
/* /*
* Standard slow path. * Standard slow path.
*/ */
@ -5551,7 +5554,7 @@ slow_path:
return 0; return 0;
step5: step5:
if (th->ack && tcp_ack(sk, skb, FLAG_SLOWPATH) < 0) if (tcp_ack(sk, skb, FLAG_SLOWPATH) < 0)
goto discard; goto discard;
/* ts_recent update must be made after we are sure that the packet /* ts_recent update must be made after we are sure that the packet
@ -5984,11 +5987,15 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
if (tcp_check_req(sk, skb, req, NULL, true) == NULL) if (tcp_check_req(sk, skb, req, NULL, true) == NULL)
goto discard; goto discard;
} }
if (!th->ack)
goto discard;
if (!tcp_validate_incoming(sk, skb, th, 0)) if (!tcp_validate_incoming(sk, skb, th, 0))
return 0; return 0;
/* step 5: check the ACK field */ /* step 5: check the ACK field */
if (th->ack) { if (true) {
int acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH) > 0; int acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH) > 0;
switch (sk->sk_state) { switch (sk->sk_state) {
@ -6138,8 +6145,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
} }
break; break;
} }
} else }
goto discard;
/* ts_recent update must be made after we are sure that the packet /* ts_recent update must be made after we are sure that the packet
* is in window. * is in window.