Skip to content

Commit 42726ec

Browse files
mrprekuba-moo
authored andcommitted
tcp: send a challenge ACK on SEG.ACK > SND.NXT
RFC 5961 Section 5.2 validates an incoming segment's ACK value against the range [SND.UNA - MAX.SND.WND, SND.NXT] and states: "All incoming segments whose ACK value doesn't satisfy the above condition MUST be discarded and an ACK sent back." Commit 354e4aa ("tcp: RFC 5961 5.2 Blind Data Injection Attack Mitigation") opted Linux into this mitigation and implements the challenge ACK on the lower side (SEG.ACK < SND.UNA - MAX.SND.WND), but the symmetric upper side (SEG.ACK > SND.NXT) still takes the pre-RFC-5961 path and silently returns SKB_DROP_REASON_TCP_ACK_UNSENT_DATA, even though RFC 793 Section 3.9 (now RFC 9293 Section 3.10.7.4) has always required: "If the ACK acknowledges something not yet sent (SEG.ACK > SND.NXT) then send an ACK, drop the segment, and return." Complete the mitigation by sending a challenge ACK on that branch, reusing the existing tcp_send_challenge_ack() path which already enforces the per-socket RFC 5961 Section 7 rate limit via __tcp_oow_rate_limited(). FLAG_NO_CHALLENGE_ACK is honoured for symmetry with the lower-edge case. Update the existing tcp_ts_recent_invalid_ack.pkt selftest, which drives this exact path, to consume the new challenge ACK. Fixes: 354e4aa ("tcp: RFC 5961 5.2 Blind Data Injection Attack Mitigation") Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev> Reviewed-by: Eric Dumazet <edumazet@google.com> Link: https://patch.msgid.link/20260422123605.320000-2-jiayuan.chen@linux.dev Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent 4078c56 commit 42726ec

2 files changed

Lines changed: 10 additions & 4 deletions

File tree

net/ipv4/tcp_input.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4286,11 +4286,15 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
42864286
goto old_ack;
42874287
}
42884288

4289-
/* If the ack includes data we haven't sent yet, discard
4290-
* this segment (RFC793 Section 3.9).
4289+
/* If the ack includes data we haven't sent yet, drop the
4290+
* segment. RFC 793 Section 3.9 and RFC 5961 Section 5.2
4291+
* require us to send an ACK back in that case.
42914292
*/
4292-
if (after(ack, tp->snd_nxt))
4293+
if (after(ack, tp->snd_nxt)) {
4294+
if (!(flag & FLAG_NO_CHALLENGE_ACK))
4295+
tcp_send_challenge_ack(sk, false);
42934296
return -SKB_DROP_REASON_TCP_ACK_UNSENT_DATA;
4297+
}
42944298

42954299
if (after(ack, prior_snd_una)) {
42964300
flag |= FLAG_SND_UNA_ADVANCED;

tools/testing/selftests/net/packetdrill/tcp_ts_recent_invalid_ack.pkt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919

2020
// bad packet with high tsval (its ACK sequence is above our sndnxt)
2121
+0 < F. 1:1(0) ack 9999 win 20000 <nop,nop,TS val 200000 ecr 100>
22-
22+
// Challenge ACK for SEG.ACK > SND.NXT (RFC 5961 5.2 / RFC 793 3.9).
23+
// ecr=200 (not 200000) proves ts_recent was not updated from the bad packet.
24+
+0 > . 1:1(0) ack 1 <nop,nop,TS val 200 ecr 200>
2325

2426
+0 < . 1:1001(1000) ack 1 win 20000 <nop,nop,TS val 201 ecr 100>
2527
+0 > . 1:1(0) ack 1001 <nop,nop,TS val 200 ecr 201>

0 commit comments

Comments
 (0)