[PATCH 2/3] rxrpc: wait for deferred conn destruction before conn_proc_list check

Henry Martin <[email protected]>
Newsgroups org.kernel.vger.netdev,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
rxrpc_destroy_all_connections() flushes rxrpc_workqueue and then
immediately asserts that rxnet->conn_proc_list is empty. However,
connection destruction is normally deferred to system_wq: the
final-ACK timer is still pending when the last ref is dropped, so
rxrpc_put_connection() schedules conn->destructor instead of running
it inline. conn->proc_link is only removed by the deferred
destructor (rxrpc_clean_up_connection()), which the
flush_workqueue(rxrpc_workqueue) call does not cover - so the
assertion can fire on a perfectly healthy intermediate state:

	rxrpc: Assertion failed
	kernel BUG at net/rxrpc/conn_object.c:488!
	Workqueue: netns cleanup_net

The BUG kills the cleanup_net kworker mid-teardown, leaving the
netns half-destroyed and potentially wedging later netns operations.
This is easily reachable from an unprivileged userns+netns running
loopback AF_RXRPC traffic.

The existing wait_var_event() on nr_conns is exactly the right
synchronization: nr_conns only reaches zero after every destructor
and RCU free has completed, which implies proc_link has been removed
from every connection. It is, however, placed *after* the assertion
it is meant to make reliable. Move it between the service_conns
leak check (whose outcome is already final once the reaper has been
flushed) and the conn_proc_list assertion.

This also silences the spurious "AF_RXRPC: Leaked peer" messages
seen during netns teardown, which share the same root cause: peer
references are dropped by the same deferred destructors.

Found by the autokbug dynamic kernel fuzzer at Tencent Yunding Lab.

Signed-off-by: Henry Martin <[email protected]>
---
 net/rxrpc/conn_object.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/net/rxrpc/conn_object.c b/net/rxrpc/conn_object.c
index 0ece717db0f85..df3f92b1a42e9 100644
--- a/net/rxrpc/conn_object.c
+++ b/net/rxrpc/conn_object.c
@@ -485,11 +485,13 @@ void rxrpc_destroy_all_connections(struct rxrpc_net *rxnet)
 	write_unlock(&rxnet->conn_lock);
 	BUG_ON(leak);
 
-	ASSERT(list_empty(&rxnet->conn_proc_list));
-
-	/* We need to wait for the connections to be destroyed by RCU as they
-	 * pin things that we still need to get rid of.
+	/* Connection destruction is normally deferred to system_wq because
+	 * the final-ACK timer is still pending when the last ref is dropped.
+	 * Wait for the deferred destructors (and the RCU frees) to complete
+	 * before checking conn_proc_list; they remove conns from it.
 	 */
 	wait_var_event(&rxnet->nr_conns, !atomic_read(&rxnet->nr_conns));
+
+	ASSERT(list_empty(&rxnet->conn_proc_list));
 	_leave("");
 }
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.