FAILED: patch "[PATCH] rxrpc: Fix data-race warning and potential load/store tearing" failed to apply to 5.10-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 5.10-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.10.y
git checkout FETCH_HEAD
git cherry-pick -x 5d5fe8bcd331f1e34e0943ec7c18432edfcf0e8b
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026012758-thrift-exploit-8d08@gregkh' --subject-prefix 'PATCH 5.10.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 5d5fe8bcd331f1e34e0943ec7c18432edfcf0e8b Mon Sep 17 00:00:00 2001
From: David Howells <[email protected]>
Date: Tue, 20 Jan 2026 10:13:05 +0000
Subject: [PATCH] rxrpc: Fix data-race warning and potential load/store tearing
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.
net/rxrpc/ar-internal.h +8 -1
@@ -387,7 +387,7 @@ struct rxrpc_peer {struct rb_root service_conns;/* Service connections */ struct list_head keepalive_link;/* Link in net->peer_keepalive[] */ unsigned long app_data;/* Application data (e.g. afs_server) */ -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 */ int debug_id;/* debug ID for printks */
@@ -1379,6 +1379,13 @@ void rxrpc_peer_keepalive_worker(struct work_struct *);void rxrpc_input_probe_for_pmtud (struct rxrpc_connection *conn,rxrpc_serial_t acked_serial,bool sendmsg_fail); +/* 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 */
net/rxrpc/conn_event.c +1 -1
@@ -194,7 +194,7 @@ void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn, } 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);
net/rxrpc/output.c +7 -7
@@ -275,7 +275,7 @@ static void rxrpc_send_ack_packet(struct rxrpc_call *call, int nr_kv, size_t lenrxrpc_local_dont_fragment (conn->local, why == rxrpc_propose_ack_ping_for_mtu_probe); ret =do_udp_sendmsg (conn->local->socket, &msg, 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, serial, ret, rxrpc_tx_point_call_ack);
@@ -411,7 +411,7 @@ int rxrpc_send_abort_packet(struct rxrpc_call *call)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);
@@ -698,7 +698,7 @@ void rxrpc_send_data_packet(struct rxrpc_call *call, struct rxrpc_send_data_req ret =0 ;trace_rxrpc_tx_data (call, txb->seq, txb->serial, txb->flags, rxrpc_txdata_inject_loss); - conn->peer->last_tx_at =ktime_get_seconds (); +rxrpc_peer_mark_tx (conn->peer); goto done; } }
@@ -711,7 +711,7 @@ void rxrpc_send_data_packet(struct rxrpc_call *call, struct rxrpc_send_data_req*/ 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 == -EMSGSIZE ) {rxrpc_inc_stat (call->rxnet, stat_tx_data_send_msgsize);
@@ -797,7 +797,7 @@ void rxrpc_send_conn_abort(struct rxrpc_connection *conn)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); }/*
@@ -917,7 +917,7 @@ void rxrpc_send_keepalive(struct rxrpc_peer *peer)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 ("" ); }
@@ -973,7 +973,7 @@ void rxrpc_send_response(struct rxrpc_connection *conn, struct sk_buff *responseif (ret <0 ) goto fail; - conn->peer->last_tx_at =ktime_get_seconds (); +rxrpc_peer_mark_tx (conn->peer);return ; fail:
net/rxrpc/peer_event.c +16 -1
@@ -237,6 +237,21 @@ static void rxrpc_distribute_error(struct rxrpc_peer *peer, struct sk_buff *skb,spin_unlock_irq (&peer->lock); } +/* +* 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. */
@@ -265,7 +280,7 @@ static void rxrpc_peer_keepalive_dispatch(struct rxrpc_net *rxnet,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);
net/rxrpc/proc.c +2 -2
@@ -296,13 +296,13 @@ static int rxrpc_peer_seq_show(struct seq_file *seq, void *v) now =ktime_get_seconds ();seq_printf (seq, -"UDP %-47.47s %-47.47s %3u %4u %5u %6llus %8d %8d\n" , +"UDP %-47.47s %-47.47s %3u %4u %5u %6ds %8d %8d\n" , lbuff, rbuff,refcount_read (&peer->ref), peer->cong_ssthresh, peer->max_data, - now - peer->last_tx_at, + (s32 )now - (s32 )READ_ONCE (peer->last_tx_at),READ_ONCE (peer->recent_srtt_us),READ_ONCE (peer->recent_rto_us));
net/rxrpc/rxgk.c +1 -1
@@ -678,7 +678,7 @@ static int rxgk_issue_challenge(struct rxrpc_connection *conn) ret =do_udp_sendmsg (conn->local->socket, &msg, len);if (ret >0 ) - conn->peer->last_tx_at =ktime_get_seconds (); +rxrpc_peer_mark_tx (conn->peer);__free_page (page);if (ret <0 ) {
net/rxrpc/rxkad.c +1 -1
@@ -694,7 +694,7 @@ static int rxkad_issue_challenge(struct rxrpc_connection *conn)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" );