Patch "rxrpc: Fix race between incoming ACK parser and retransmitter" has been added to the 5.4-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

    rxrpc: Fix race between incoming ACK parser and retransmitter

to the 5.4-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:
     rxrpc-fix-race-between-incoming-ack-parser-and-retra.patch
and it can be found in the queue-5.4 subdirectory.

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



commit ef4e4dc72c18d94fc13b28183ef662edb57d0db3
Author: David Howells <dhowells@xxxxxxxxxx>
Date:   Thu Jun 11 21:57:00 2020 +0100

    rxrpc: Fix race between incoming ACK parser and retransmitter
    
    [ Upstream commit 2ad6691d988c0c611362ddc2aad89e0fb50e3261 ]
    
    There's a race between the retransmission code and the received ACK parser.
    The problem is that the retransmission loop has to drop the lock under
    which it is iterating through the transmission buffer in order to transmit
    a packet, but whilst the lock is dropped, the ACK parser can crank the Tx
    window round and discard the packets from the buffer.
    
    The retransmission code then updated the annotations for the wrong packet
    and a later retransmission thought it had to retransmit a packet that
    wasn't there, leading to a NULL pointer dereference.
    
    Fix this by:
    
     (1) Moving the annotation change to before we drop the lock prior to
         transmission.  This means we can't vary the annotation depending on
         the outcome of the transmission, but that's fine - we'll retransmit
         again later if it failed now.
    
     (2) Skipping the packet if the skb pointer is NULL.
    
    The following oops was seen:
    
            BUG: kernel NULL pointer dereference, address: 000000000000002d
            Workqueue: krxrpcd rxrpc_process_call
            RIP: 0010:rxrpc_get_skb+0x14/0x8a
            ...
            Call Trace:
             rxrpc_resend+0x331/0x41e
             ? get_vtime_delta+0x13/0x20
             rxrpc_process_call+0x3c0/0x4ac
             process_one_work+0x18f/0x27f
             worker_thread+0x1a3/0x247
             ? create_worker+0x17d/0x17d
             kthread+0xe6/0xeb
             ? kthread_delayed_work_timer_fn+0x83/0x83
             ret_from_fork+0x1f/0x30
    
    Fixes: 248f219cb8bc ("rxrpc: Rewrite the data and ack handling code")
    Signed-off-by: David Howells <dhowells@xxxxxxxxxx>
    Signed-off-by: David S. Miller <davem@xxxxxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/net/rxrpc/call_event.c b/net/rxrpc/call_event.c
index 2a65ac41055f5..985fb89202d0c 100644
--- a/net/rxrpc/call_event.c
+++ b/net/rxrpc/call_event.c
@@ -248,7 +248,18 @@ static void rxrpc_resend(struct rxrpc_call *call, unsigned long now_j)
 		if (anno_type != RXRPC_TX_ANNO_RETRANS)
 			continue;
 
+		/* We need to reset the retransmission state, but we need to do
+		 * so before we drop the lock as a new ACK/NAK may come in and
+		 * confuse things
+		 */
+		annotation &= ~RXRPC_TX_ANNO_MASK;
+		annotation |= RXRPC_TX_ANNO_RESENT;
+		call->rxtx_annotations[ix] = annotation;
+
 		skb = call->rxtx_buffer[ix];
+		if (!skb)
+			continue;
+
 		rxrpc_get_skb(skb, rxrpc_skb_got);
 		spin_unlock_bh(&call->lock);
 
@@ -262,24 +273,6 @@ static void rxrpc_resend(struct rxrpc_call *call, unsigned long now_j)
 
 		rxrpc_free_skb(skb, rxrpc_skb_freed);
 		spin_lock_bh(&call->lock);
-
-		/* We need to clear the retransmit state, but there are two
-		 * things we need to be aware of: A new ACK/NAK might have been
-		 * received and the packet might have been hard-ACK'd (in which
-		 * case it will no longer be in the buffer).
-		 */
-		if (after(seq, call->tx_hard_ack)) {
-			annotation = call->rxtx_annotations[ix];
-			anno_type = annotation & RXRPC_TX_ANNO_MASK;
-			if (anno_type == RXRPC_TX_ANNO_RETRANS ||
-			    anno_type == RXRPC_TX_ANNO_NAK) {
-				annotation &= ~RXRPC_TX_ANNO_MASK;
-				annotation |= RXRPC_TX_ANNO_UNACK;
-			}
-			annotation |= RXRPC_TX_ANNO_RESENT;
-			call->rxtx_annotations[ix] = annotation;
-		}
-
 		if (after(call->tx_hard_ack, seq))
 			seq = call->tx_hard_ack;
 	}



[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