Patch "rxrpc: Fix data-race warning and potential load/store tearing" has been added to the 6.12-stable tree

gregkh at linuxfoundation.org gregkh at linuxfoundation.org
Tue Feb 3 06:50:48 PST 2026


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

    rxrpc: Fix data-race warning and potential load/store tearing

to the 6.12-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-data-race-warning-and-potential-load-store-tearing.patch
and it can be found in the queue-6.12 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable at vger.kernel.org> know about it.


>From stable+bounces-212715-greg=kroah.com at vger.kernel.org Thu Jan 29 01:11:05 2026
From: Sasha Levin <sashal at kernel.org>
Date: Wed, 28 Jan 2026 19:10:48 -0500
Subject: rxrpc: Fix data-race warning and potential load/store tearing
To: stable at vger.kernel.org
Cc: David Howells <dhowells at redhat.com>, syzbot+6182afad5045e6703b3d at syzkaller.appspotmail.com, Marc Dionne <marc.dionne at auristor.com>, Simon Horman <horms at kernel.org>, linux-afs at lists.infradead.org, stable at kernel.org, Jakub Kicinski <kuba at kernel.org>, Sasha Levin <sashal at kernel.org>
Message-ID: <20260129001048.2933922-1-sashal at kernel.org>

From: David Howells <dhowells at redhat.com>

[ Upstream commit 5d5fe8bcd331f1e34e0943ec7c18432edfcf0e8b ]

Fix the following:

        BUG: KCSAN: data-race in rxrpc_peer_keepalive_worker / rxrpc_send_data_packet

which is reporting an issue with the reads and writes to ->last_tx_at in:

        conn->peer->last_tx_at = ktime_get_seconds();

and:

        keepalive_at = peer->last_tx_at + RXRPC_KEEPALIVE_TIME;

The lockless accesses to these to values aren't actually a problem as the
read only needs an approximate time of last transmission for the purposes
of deciding whether or not the transmission of a keepalive packet is
warranted yet.

Also, as ->last_tx_at is a 64-bit value, tearing can occur on a 32-bit
arch.

Fix both of these by switching to an unsigned int for ->last_tx_at and only
storing the LSW of the time64_t.  It can then be reconstructed at need
provided no more than 68 years has elapsed since the last transmission.

Fixes: ace45bec6d77 ("rxrpc: Fix firewall route keepalive")
Reported-by: syzbot+6182afad5045e6703b3d at syzkaller.appspotmail.com
Closes: https://lore.kernel.org/r/695e7cfb.050a0220.1c677c.036b.GAE@google.com/
Signed-off-by: David Howells <dhowells at redhat.com>
cc: Marc Dionne <marc.dionne at auristor.com>
cc: Simon Horman <horms at kernel.org>
cc: linux-afs at lists.infradead.org
cc: stable at kernel.org
Link: https://patch.msgid.link/1107124.1768903985@warthog.procyon.org.uk
Signed-off-by: Jakub Kicinski <kuba at kernel.org>
[ different struct fields (peer->mtu, peer->srtt_us, peer->rto_us) and different output.c code structure ]
Signed-off-by: Sasha Levin <sashal at kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
---
 net/rxrpc/ar-internal.h |    9 ++++++++-
 net/rxrpc/conn_event.c  |    2 +-
 net/rxrpc/output.c      |   10 +++++-----
 net/rxrpc/peer_event.c  |   17 ++++++++++++++++-
 net/rxrpc/proc.c        |    4 ++--
 net/rxrpc/rxkad.c       |    4 ++--
 6 files changed, 34 insertions(+), 12 deletions(-)

--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -335,7 +335,7 @@ struct rxrpc_peer {
 	struct hlist_head	error_targets;	/* targets for net error distribution */
 	struct rb_root		service_conns;	/* Service connections */
 	struct list_head	keepalive_link;	/* Link in net->peer_keepalive[] */
-	time64_t		last_tx_at;	/* Last time packet sent here */
+	unsigned int		last_tx_at;	/* Last time packet sent here (time64_t LSW) */
 	seqlock_t		service_conn_lock;
 	spinlock_t		lock;		/* access lock */
 	unsigned int		if_mtu;		/* interface MTU for this peer */
@@ -1161,6 +1161,13 @@ void rxrpc_transmit_one(struct rxrpc_cal
 void rxrpc_input_error(struct rxrpc_local *, struct sk_buff *);
 void rxrpc_peer_keepalive_worker(struct work_struct *);
 
+/* Update the last transmission time on a peer for keepalive purposes. */
+static inline void rxrpc_peer_mark_tx(struct rxrpc_peer *peer)
+{
+	/* To avoid tearing on 32-bit systems, we only keep the LSW. */
+	WRITE_ONCE(peer->last_tx_at, ktime_get_seconds());
+}
+
 /*
  * peer_object.c
  */
--- a/net/rxrpc/conn_event.c
+++ b/net/rxrpc/conn_event.c
@@ -180,7 +180,7 @@ void rxrpc_conn_retransmit_call(struct r
 	}
 
 	ret = kernel_sendmsg(conn->local->socket, &msg, iov, ioc, len);
-	conn->peer->last_tx_at = ktime_get_seconds();
+	rxrpc_peer_mark_tx(conn->peer);
 	if (ret < 0)
 		trace_rxrpc_tx_fail(chan->call_debug_id, serial, ret,
 				    rxrpc_tx_point_call_final_resend);
--- a/net/rxrpc/output.c
+++ b/net/rxrpc/output.c
@@ -209,7 +209,7 @@ static void rxrpc_send_ack_packet(struct
 	iov_iter_kvec(&msg.msg_iter, WRITE, txb->kvec, txb->nr_kvec, txb->len);
 	rxrpc_local_dont_fragment(conn->local, false);
 	ret = do_udp_sendmsg(conn->local->socket, &msg, txb->len);
-	call->peer->last_tx_at = ktime_get_seconds();
+	rxrpc_peer_mark_tx(call->peer);
 	if (ret < 0) {
 		trace_rxrpc_tx_fail(call->debug_id, txb->serial, ret,
 				    rxrpc_tx_point_call_ack);
@@ -310,7 +310,7 @@ int rxrpc_send_abort_packet(struct rxrpc
 
 	iov_iter_kvec(&msg.msg_iter, WRITE, iov, 1, sizeof(pkt));
 	ret = do_udp_sendmsg(conn->local->socket, &msg, sizeof(pkt));
-	conn->peer->last_tx_at = ktime_get_seconds();
+	rxrpc_peer_mark_tx(conn->peer);
 	if (ret < 0)
 		trace_rxrpc_tx_fail(call->debug_id, serial, ret,
 				    rxrpc_tx_point_call_abort);
@@ -486,7 +486,7 @@ retry:
 	 */
 	rxrpc_inc_stat(call->rxnet, stat_tx_data_send);
 	ret = do_udp_sendmsg(conn->local->socket, &msg, len);
-	conn->peer->last_tx_at = ktime_get_seconds();
+	rxrpc_peer_mark_tx(conn->peer);
 
 	if (ret < 0) {
 		rxrpc_inc_stat(call->rxnet, stat_tx_data_send_fail);
@@ -573,7 +573,7 @@ void rxrpc_send_conn_abort(struct rxrpc_
 
 	trace_rxrpc_tx_packet(conn->debug_id, &whdr, rxrpc_tx_point_conn_abort);
 
-	conn->peer->last_tx_at = ktime_get_seconds();
+	rxrpc_peer_mark_tx(conn->peer);
 }
 
 /*
@@ -692,7 +692,7 @@ void rxrpc_send_keepalive(struct rxrpc_p
 		trace_rxrpc_tx_packet(peer->debug_id, &whdr,
 				      rxrpc_tx_point_version_keepalive);
 
-	peer->last_tx_at = ktime_get_seconds();
+	rxrpc_peer_mark_tx(peer);
 	_leave("");
 }
 
--- a/net/rxrpc/peer_event.c
+++ b/net/rxrpc/peer_event.c
@@ -225,6 +225,21 @@ static void rxrpc_distribute_error(struc
 }
 
 /*
+ * Reconstruct the last transmission time.  The difference calculated should be
+ * valid provided no more than ~68 years elapsed since the last transmission.
+ */
+static time64_t rxrpc_peer_get_tx_mark(const struct rxrpc_peer *peer, time64_t base)
+{
+	s32 last_tx_at = READ_ONCE(peer->last_tx_at);
+	s32 base_lsw = base;
+	s32 diff = last_tx_at - base_lsw;
+
+	diff = clamp(diff, -RXRPC_KEEPALIVE_TIME, RXRPC_KEEPALIVE_TIME);
+
+	return diff + base;
+}
+
+/*
  * Perform keep-alive pings.
  */
 static void rxrpc_peer_keepalive_dispatch(struct rxrpc_net *rxnet,
@@ -252,7 +267,7 @@ static void rxrpc_peer_keepalive_dispatc
 		spin_unlock_bh(&rxnet->peer_hash_lock);
 
 		if (use) {
-			keepalive_at = peer->last_tx_at + RXRPC_KEEPALIVE_TIME;
+			keepalive_at = rxrpc_peer_get_tx_mark(peer, base) + RXRPC_KEEPALIVE_TIME;
 			slot = keepalive_at - base;
 			_debug("%02x peer %u t=%d {%pISp}",
 			       cursor, peer->debug_id, slot, &peer->srx.transport);
--- a/net/rxrpc/proc.c
+++ b/net/rxrpc/proc.c
@@ -299,13 +299,13 @@ static int rxrpc_peer_seq_show(struct se
 	now = ktime_get_seconds();
 	seq_printf(seq,
 		   "UDP   %-47.47s %-47.47s %3u"
-		   " %3u %5u %6llus %8u %8u\n",
+		   " %3u %5u %6ds %8u %8u\n",
 		   lbuff,
 		   rbuff,
 		   refcount_read(&peer->ref),
 		   peer->cong_ssthresh,
 		   peer->mtu,
-		   now - peer->last_tx_at,
+		   (s32)now - (s32)READ_ONCE(peer->last_tx_at),
 		   peer->srtt_us >> 3,
 		   peer->rto_us);
 
--- a/net/rxrpc/rxkad.c
+++ b/net/rxrpc/rxkad.c
@@ -676,7 +676,7 @@ static int rxkad_issue_challenge(struct
 		return -EAGAIN;
 	}
 
-	conn->peer->last_tx_at = ktime_get_seconds();
+	rxrpc_peer_mark_tx(conn->peer);
 	trace_rxrpc_tx_packet(conn->debug_id, &whdr,
 			      rxrpc_tx_point_rxkad_challenge);
 	_leave(" = 0");
@@ -734,7 +734,7 @@ static int rxkad_send_response(struct rx
 		return -EAGAIN;
 	}
 
-	conn->peer->last_tx_at = ktime_get_seconds();
+	rxrpc_peer_mark_tx(conn->peer);
 	_leave(" = 0");
 	return 0;
 }


Patches currently in stable-queue which might be from sashal at kernel.org are

queue-6.12/dma-pool-distinguish-between-missing-and-exhausted-a.patch
queue-6.12/nfc-nci-fix-race-between-rfkill-and-nci_unregister_d.patch
queue-6.12/bcache-fix-i-o-accounting-leak-in-detached_dev_do_re.patch
queue-6.12/can-gs_usb-gs_usb_receive_bulk_callback-fix-error-me.patch
queue-6.12/ipv6-use-the-right-ifindex-when-replying-to-icmpv6-f.patch
queue-6.12/bluetooth-hci_uart-fix-null-ptr-deref-in-hci_uart_wr.patch
queue-6.12/ice-stop-counting-udp-csum-mismatch-as-rx_errors.patch
queue-6.12/net-phy-micrel-fix-clk-warning-when-removing-the-dri.patch
queue-6.12/scsi-firewire-sbp-target-fix-overflow-in-sbp_make_tp.patch
queue-6.12/net-wwan-t7xx-fix-potential-skb-frags-overflow-in-rx.patch
queue-6.12/gpio-virtuser-fix-uaf-in-configfs-release-path.patch
queue-6.12/asoc-intel-sof_es8336-fix-headphone-gpio-logic-inver.patch
queue-6.12/net-mlx5-initialize-events-outside-devlink-lock.patch
queue-6.12/ice-fix-null-pointer-dereference-in-ice_vsi_set_napi.patch
queue-6.12/sched-deadline-fix-stuck-dl_server.patch
queue-6.12/nfc-llcp-fix-memleak-in-nfc_llcp_send_ui_frame.patch
queue-6.12/sched-deadline-document-dl_server.patch
queue-6.12/net-mlx5e-tc-delete-flows-only-for-existing-peers.patch
queue-6.12/net-mlx5e-skip-esn-replay-window-setup-for-ipsec-cry.patch
queue-6.12/rocker-fix-memory-leak-in-rocker_world_port_post_fin.patch
queue-6.12/net-mvpp2-cls-fix-memory-leak-in-mvpp2_ethtool_cls_r.patch
queue-6.12/net-bridge-fix-static-key-check.patch
queue-6.12/bonding-annotate-data-races-around-slave-last_rx.patch
queue-6.12/net-mlx5-fix-memory-leak-in-esw_acl_ingress_lgcy_set.patch
queue-6.12/bcache-use-bio-cloning-for-detached-device-requests.patch
queue-6.12/bcache-fix-improper-use-of-bi_end_io.patch
queue-6.12/net-mlx5-fs-fix-inverted-cap-check-in-tx-flow-table-.patch
queue-6.12/net-bcmasp-fix-early-exit-leak-with-fixed-phy.patch
queue-6.12/gpiolib-acpi-use-bit_ull-for-u64-mask-in-address-spa.patch
queue-6.12/rxrpc-fix-data-race-warning-and-potential-load-store-tearing.patch
queue-6.12/can-at91_can-fix-memory-leak-in-at91_can_probe.patch
queue-6.12/ksmbd-smbd-fix-dma_unmap_sg-nents.patch
queue-6.12/octeon_ep-fix-memory-leak-in-octep_device_setup.patch
queue-6.12/net-mlx5-fix-vhca_id-access-call-trace-use-before-al.patch
queue-6.12/bluetooth-mgmt-fix-memory-leak-in-set_ssp_complete.patch



More information about the linux-afs mailing list