Patch "tcp: do not accept ACK of bytes we never sent" has been added to the 5.10-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    tcp: do not accept ACK of bytes we never sent

to the 5.10-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     tcp-do-not-accept-ack-of-bytes-we-never-sent.patch
and it can be found in the queue-5.10 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit c02ab8ad87ca013e42f5cff7d33dcaa99e472539
Author: Eric Dumazet <edumazet@xxxxxxxxxx>
Date:   Tue Dec 5 16:18:41 2023 +0000

    tcp: do not accept ACK of bytes we never sent
    
    [ Upstream commit 3d501dd326fb1c73f1b8206d4c6e1d7b15c07e27 ]
    
    This patch is based on a detailed report and ideas from Yepeng Pan
    and Christian Rossow.
    
    ACK seq validation is currently following RFC 5961 5.2 guidelines:
    
       The ACK value is considered acceptable only if
       it is in the range of ((SND.UNA - MAX.SND.WND) <= SEG.ACK <=
       SND.NXT).  All incoming segments whose ACK value doesn't satisfy the
       above condition MUST be discarded and an ACK sent back.  It needs to
       be noted that RFC 793 on page 72 (fifth check) says: "If the ACK is a
       duplicate (SEG.ACK < SND.UNA), it can be ignored.  If the ACK
       acknowledges something not yet sent (SEG.ACK > SND.NXT) then send an
       ACK, drop the segment, and return".  The "ignored" above implies that
       the processing of the incoming data segment continues, which means
       the ACK value is treated as acceptable.  This mitigation makes the
       ACK check more stringent since any ACK < SND.UNA wouldn't be
       accepted, instead only ACKs that are in the range ((SND.UNA -
       MAX.SND.WND) <= SEG.ACK <= SND.NXT) get through.
    
    This can be refined for new (and possibly spoofed) flows,
    by not accepting ACK for bytes that were never sent.
    
    This greatly improves TCP security at a little cost.
    
    I added a Fixes: tag to make sure this patch will reach stable trees,
    even if the 'blamed' patch was adhering to the RFC.
    
    tp->bytes_acked was added in linux-4.2
    
    Following packetdrill test (courtesy of Yepeng Pan) shows
    the issue at hand:
    
    0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
    +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
    +0 bind(3, ..., ...) = 0
    +0 listen(3, 1024) = 0
    
    // ---------------- Handshake ------------------- //
    
    // when window scale is set to 14 the window size can be extended to
    // 65535 * (2^14) = 1073725440. Linux would accept an ACK packet
    // with ack number in (Server_ISN+1-1073725440. Server_ISN+1)
    // ,though this ack number acknowledges some data never
    // sent by the server.
    
    +0 < S 0:0(0) win 65535 <mss 1400,nop,wscale 14>
    +0 > S. 0:0(0) ack 1 <...>
    +0 < . 1:1(0) ack 1 win 65535
    +0 accept(3, ..., ...) = 4
    
    // For the established connection, we send an ACK packet,
    // the ack packet uses ack number 1 - 1073725300 + 2^32,
    // where 2^32 is used to wrap around.
    // Note: we used 1073725300 instead of 1073725440 to avoid possible
    // edge cases.
    // 1 - 1073725300 + 2^32 = 3221241997
    
    // Oops, old kernels happily accept this packet.
    +0 < . 1:1001(1000) ack 3221241997 win 65535
    
    // After the kernel fix the following will be replaced by a challenge ACK,
    // and prior malicious frame would be dropped.
    +0 > . 1:1(0) ack 1001
    
    Fixes: 354e4aa391ed ("tcp: RFC 5961 5.2 Blind Data Injection Attack Mitigation")
    Signed-off-by: Eric Dumazet <edumazet@xxxxxxxxxx>
    Reported-by: Yepeng Pan <yepeng.pan@xxxxxxxx>
    Reported-by: Christian Rossow <rossow@xxxxxxxx>
    Acked-by: Neal Cardwell <ncardwell@xxxxxxxxxx>
    Link: https://lore.kernel.org/r/20231205161841.2702925-1-edumazet@xxxxxxxxxx
    Signed-off-by: Jakub Kicinski <kuba@xxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index a8948c76d19b6..0f9fe5edad142 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -3772,8 +3772,12 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
 	 * then we can probably ignore it.
 	 */
 	if (before(ack, prior_snd_una)) {
+		u32 max_window;
+
+		/* do not accept ACK for bytes we never sent. */
+		max_window = min_t(u64, tp->max_window, tp->bytes_acked);
 		/* RFC 5961 5.2 [Blind Data Injection Attack].[Mitigation] */
-		if (before(ack, prior_snd_una - tp->max_window)) {
+		if (before(ack, prior_snd_una - max_window)) {
 			if (!(flag & FLAG_NO_CHALLENGE_ACK))
 				tcp_send_challenge_ack(sk, skb);
 			return -1;




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux