* [PATCH] rxrpc: Serialize client connection IDR updates
@ 2026-10-30 4:21 Kyle Zeng
2026-10-30 4:23 ` netdev-bot+sinfo
2026-10-31 13:43 ` Andrew Lunn
0 siblings, 2 replies; 3+ messages in thread
From: Kyle Zeng @ 2026-10-30 4:21 UTC (permalink / raw)
To: linux-afs
Cc: David Howells, Marc Dionne, netdev, linux-kernel,
outbounddisclosures
The common connection destructor calls rxrpc_kill_client_conn() for
service connections as well as client connections. A service connection
gets its CID from the peer and never owns an entry in local->conn_ids.
Its destruction can therefore remove an unrelated client connection.
The final reference can be dropped by the service reaper or a call
destruction worker, outside the owning local endpoint's I/O thread.
Client connection destruction can also run off-thread, and can remove an
ID already released by rxrpc_unbundle_conn(). These writers can race
idr_alloc_cyclic(), corrupting the radix tree and its RCU callbacks. A
second removal can also delete a new owner after an ID has been reused.
Only run client cleanup for client connections. Restore a per-local IDR
writer lock and the client-ID ownership flag, clearing the flag under the
lock when releasing the ID. Serialize IDR destruction with the same
lock. This covers deferred final puts without changing connection
expiry or the RCU lookup path.
Fixes: 9d35d880e0e4 ("rxrpc: Move client call connection to the I/O thread")
Signed-off-by: Kyle Zeng <kylebot@openai.com>
---
I have a reproducer for this issue and can share via DM
net/rxrpc/ar-internal.h | 2 ++
net/rxrpc/conn_client.c | 17 ++++++++++++++---
net/rxrpc/conn_object.c | 3 ++-
net/rxrpc/local_object.c | 1 +
4 files changed, 19 insertions(+), 4 deletions(-)
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
index 865f05fe37ab..5e49fe0f4a6f 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -377,6 +377,7 @@ struct rxrpc_local {
bool dead;
bool service_closed; /* Service socket closed */
struct idr conn_ids; /* List of connection IDs */
+ spinlock_t conn_ids_lock; /* Lock for conn_ids */
struct list_head new_client_calls; /* Newly created client calls need connection */
spinlock_t client_call_lock; /* Lock for ->new_client_calls */
struct sockaddr_rxrpc srx; /* local address */
@@ -472,6 +473,7 @@ enum rxrpc_call_completion {
* Bits in the connection flags.
*/
enum rxrpc_conn_flag {
+ RXRPC_CONN_HAS_IDR, /* Has a client conn ID assigned */
RXRPC_CONN_IN_SERVICE_CONNS, /* Conn is in peer->service_conns */
RXRPC_CONN_DONT_REUSE, /* Don't reuse this connection */
RXRPC_CONN_PROBING_FOR_UPGRADE, /* Probing for service upgrade */
diff --git a/net/rxrpc/conn_client.c b/net/rxrpc/conn_client.c
index 48519f0de185..4c2db83fceae 100644
--- a/net/rxrpc/conn_client.c
+++ b/net/rxrpc/conn_client.c
@@ -40,12 +40,16 @@ static void rxrpc_activate_bundle(struct rxrpc_bundle *bundle)
}
/*
- * Release a connection ID for a client connection.
+ * Release a client connection ID exactly once. The final reference may be
+ * dropped outside the local endpoint's I/O thread.
*/
static void rxrpc_put_client_connection_id(struct rxrpc_local *local,
struct rxrpc_connection *conn)
{
- idr_remove(&local->conn_ids, conn->proto.cid >> RXRPC_CIDSHIFT);
+ spin_lock(&local->conn_ids_lock);
+ if (test_and_clear_bit(RXRPC_CONN_HAS_IDR, &conn->flags))
+ idr_remove(&local->conn_ids, conn->proto.cid >> RXRPC_CIDSHIFT);
+ spin_unlock(&local->conn_ids_lock);
}
/*
@@ -56,6 +60,7 @@ static void rxrpc_destroy_client_conn_ids(struct rxrpc_local *local)
struct rxrpc_connection *conn;
int id;
+ spin_lock(&local->conn_ids_lock);
if (!idr_is_empty(&local->conn_ids)) {
idr_for_each_entry(&local->conn_ids, conn, id) {
pr_err("AF_RXRPC: Leaked client conn %p {%d}\n",
@@ -65,6 +70,7 @@ static void rxrpc_destroy_client_conn_ids(struct rxrpc_local *local)
}
idr_destroy(&local->conn_ids);
+ spin_unlock(&local->conn_ids_lock);
}
/*
@@ -162,15 +168,20 @@ rxrpc_alloc_client_connection(struct rxrpc_bundle *bundle)
if (!conn)
return ERR_PTR(-ENOMEM);
+ spin_lock(&local->conn_ids_lock);
id = idr_alloc_cyclic(&local->conn_ids, conn, 1, 0x40000000,
GFP_ATOMIC | __GFP_NOWARN);
+ if (id >= 0) {
+ conn->proto.cid = id << RXRPC_CIDSHIFT;
+ set_bit(RXRPC_CONN_HAS_IDR, &conn->flags);
+ }
+ spin_unlock(&local->conn_ids_lock);
if (id < 0) {
kfree(conn);
return ERR_PTR(id);
}
refcount_set(&conn->ref, 1);
- conn->proto.cid = id << RXRPC_CIDSHIFT;
conn->proto.epoch = local->rxnet->epoch;
conn->out_clientflag = RXRPC_CLIENT_INITIATED;
conn->bundle = rxrpc_get_bundle(bundle, rxrpc_bundle_get_client_conn);
diff --git a/net/rxrpc/conn_object.c b/net/rxrpc/conn_object.c
index 0ece717db0f8..bae95cadd72b 100644
--- a/net/rxrpc/conn_object.c
+++ b/net/rxrpc/conn_object.c
@@ -332,7 +332,8 @@ static void rxrpc_clean_up_connection(struct work_struct *work)
rxrpc_purge_queue(&conn->rx_queue);
rxrpc_free_skb(conn->tx_response, rxrpc_skb_put_response);
- rxrpc_kill_client_conn(conn);
+ if (rxrpc_conn_is_client(conn))
+ rxrpc_kill_client_conn(conn);
conn->security->clear(conn);
key_put(conn->key);
diff --git a/net/rxrpc/local_object.c b/net/rxrpc/local_object.c
index 169f9dfdaa77..5a7acd595e11 100644
--- a/net/rxrpc/local_object.c
+++ b/net/rxrpc/local_object.c
@@ -140,6 +140,7 @@ static struct rxrpc_local *rxrpc_alloc_local(struct net *net,
memcpy(&local->srx, srx, sizeof(*srx));
local->srx.srx_service = 0;
idr_init(&local->conn_ids);
+ spin_lock_init(&local->conn_ids_lock);
get_random_bytes(&tmp, sizeof(tmp));
tmp &= 0x3fffffff;
if (tmp == 0)
base-commit: d89e1d186ec9271bf78e62771779e9fc03bf0fc3
--
2.56.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] rxrpc: Serialize client connection IDR updates
2026-10-30 4:21 [PATCH] rxrpc: Serialize client connection IDR updates Kyle Zeng
@ 2026-10-30 4:23 ` netdev-bot+sinfo
2026-10-31 13:43 ` Andrew Lunn
1 sibling, 0 replies; 3+ messages in thread
From: netdev-bot+sinfo @ 2026-10-30 4:23 UTC (permalink / raw)
To: Kyle Zeng
Cc: linux-afs, David Howells, Marc Dionne, netdev, linux-kernel,
outbounddisclosures
Hi!
This is an automated message. This series looks like a fix, but its
commit messages seem to be missing some information:
- How the issue was discovered, e.g. hit in production, hit during
development, syzbot report, manual code inspection, LLM or static
analysis tool scan.
Please do not repost the series just to address the above. Instead,
reply to this email with the missing information, so that reviewers
can take it into account. If the series needs another revision for
other reasons, please include the information in the commit messages
then.
The evaluation is done by an LLM so it may be wrong, if you think
that is the case please reply and explain.
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] rxrpc: Serialize client connection IDR updates
2026-10-30 4:21 [PATCH] rxrpc: Serialize client connection IDR updates Kyle Zeng
2026-10-30 4:23 ` netdev-bot+sinfo
@ 2026-10-31 13:43 ` Andrew Lunn
1 sibling, 0 replies; 3+ messages in thread
From: Andrew Lunn @ 2026-10-31 13:43 UTC (permalink / raw)
To: Kyle Zeng
Cc: linux-afs, David Howells, Marc Dionne, netdev, linux-kernel,
outbounddisclosures
On Thu, Oct 29, 2026 at 09:21:29PM -0700, Kyle Zeng wrote:
> The common connection destructor calls rxrpc_kill_client_conn() for
> service connections as well as client connections. A service connection
> gets its CID from the peer and never owns an entry in local->conn_ids.
> Its destruction can therefore remove an unrelated client connection.
>
> The final reference can be dropped by the service reaper or a call
> destruction worker, outside the owning local endpoint's I/O thread.
> Client connection destruction can also run off-thread, and can remove an
> ID already released by rxrpc_unbundle_conn(). These writers can race
> idr_alloc_cyclic(), corrupting the radix tree and its RCU callbacks. A
> second removal can also delete a new owner after an ID has been reused.
>
> Only run client cleanup for client connections. Restore a per-local IDR
> writer lock and the client-ID ownership flag, clearing the flag under the
> lock when releasing the ID. Serialize IDR destruction with the same
> lock. This covers deferred final puts without changing connection
> expiry or the RCU lookup path.
>
> Fixes: 9d35d880e0e4 ("rxrpc: Move client call connection to the I/O thread")
> Signed-off-by: Kyle Zeng <kylebot@openai.com>
> ---
> I have a reproducer for this issue and can share via DM
Please take a read of
https://www.kernel.org/doc/html/latest/process/maintainer-netdev.html
You need to set the subject line correctly to indicate the three they
are applied to.
All the patches you have posted are very likely to be sent to
/dev/null because of this. It is a good idea to start slow, only one
patch at a time, and figure out the processes.
Andrew
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-10-31 13:43 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-30 4:21 [PATCH] rxrpc: Serialize client connection IDR updates Kyle Zeng
2026-10-30 4:23 ` netdev-bot+sinfo
2026-10-31 13:43 ` Andrew Lunn
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.