From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 125AA32A3C9; Tue, 16 Jun 2026 17:48:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781632114; cv=none; b=HCpLMUI8VehO4GohBkbbcP9qrA/kcPA9HDjX84GuCwn+CtGjWiOlsrbodeSuVJVTNsqCFbFv1cG1f8wk2cW9Jl+mBUaWpam56BkrZSQS6Y/X1CMI71W1G5EBEiM7LGctgT0Qhlb0e9pVWiylxaX64+3DVxbbJUI5koQfhock9A4= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781632114; c=relaxed/simple; bh=he7SL5BnZQd5uFRL8AEc8hchEvIW5MtRb5DD+O7pAXE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=F7jsjpe90P/FYd3RKZg5ID2O4n4g74IOK0u4C8ZavkDdIjrmq1zTUuYnuSHPvpnjybVEyeVlrJ3XmopsziVqbn+wSKKpSsq+/EzSuqzM9u/JbHIPUIZ8vzu46wClohOHr0xNksqCmmJCp60ju0UZ3mcwnOIdskSibUpp4DcwMM0= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b=kavjCQM3; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b="kavjCQM3" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 19A541F000E9; Tue, 16 Jun 2026 17:48:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1781632113; bh=fIg3LJWZcwNwg+TIVyLwLjagxsb9r84OqCQkc4O6Fd4=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=kavjCQM3v3OETowFuJWa2e2Cq8Z08ZzOLeCHIsJ5X1/IU64Hvxu5SRHRTN9R7Ei0S NdY+o4Yk5D/OI4dQVSxf6CSqBwJir07j2SoO19GoxC5LvtdmBa3QgDlj+1Bq3UeWko f/oMrZ8us/ELvKXjdJt7yDbv+cXbafpBpPoCXjWA= From: Greg Kroah-Hartman To: stable@vger.kernel.org Cc: Greg Kroah-Hartman , patches@lists.linux.dev, Chris Lew , Vignesh Viswanathan , Simon Horman , "David S. Miller" , Sasha Levin Subject: [PATCH 6.1 350/522] net: qrtr: ns: Change servers radix tree to xarray Date: Tue, 16 Jun 2026 20:28:17 +0530 Message-ID: <20260616145142.173862722@linuxfoundation.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260616145125.307082728@linuxfoundation.org> References: <20260616145125.307082728@linuxfoundation.org> User-Agent: quilt/0.69 X-stable: review X-Patchwork-Hint: ignore Precedence: bulk X-Mailing-List: patches@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 6.1-stable review patch. If anyone has any objections, please let me know. ------------------ From: Vignesh Viswanathan [ Upstream commit 608a147a88728f84bbd2efdde3d4984339f1d872 ] There is a use after free scenario while iterating through the servers radix tree despite the ns being a single threaded process. This can happen when the radix tree APIs are not synchronized with the rcu_read_lock() APIs. Convert the radix tree for servers to xarray to take advantage of the built in rcu lock usage provided by xarray. Signed-off-by: Chris Lew Signed-off-by: Vignesh Viswanathan Reviewed-by: Simon Horman Signed-off-by: David S. Miller Stable-dep-of: 68efba36446a ("net: qrtr: ns: Free the node during ctrl_cmd_bye()") Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/qrtr/ns.c | 133 ++++++++++------------------------------------------------ 1 file changed, 24 insertions(+), 109 deletions(-) --- a/net/qrtr/ns.c +++ b/net/qrtr/ns.c @@ -67,7 +67,7 @@ struct qrtr_server { struct qrtr_node { unsigned int id; - struct radix_tree_root servers; + struct xarray servers; }; /* Max lookup limit is chosen based on the current platform requirements. If the @@ -89,6 +89,7 @@ static struct qrtr_node *node_get(unsign return NULL; node->id = node_id; + xa_init(&node->servers); if (radix_tree_insert(&nodes, node_id, node)) { kfree(node); @@ -199,40 +200,23 @@ static void lookup_notify(struct sockadd static int announce_servers(struct sockaddr_qrtr *sq) { - struct radix_tree_iter iter; struct qrtr_server *srv; struct qrtr_node *node; - void __rcu **slot; + unsigned long index; int ret; node = node_get(qrtr_ns.local_node); if (!node) return 0; - rcu_read_lock(); /* Announce the list of servers registered in this node */ - radix_tree_for_each_slot(slot, &node->servers, &iter, 0) { - srv = radix_tree_deref_slot(slot); - if (!srv) - continue; - if (radix_tree_deref_retry(srv)) { - slot = radix_tree_iter_retry(&iter); - continue; - } - slot = radix_tree_iter_resume(slot, &iter); - rcu_read_unlock(); - + xa_for_each(&node->servers, index, srv) { ret = service_announce_new(sq, srv); if (ret < 0) { pr_err("failed to announce new service\n"); return ret; } - - rcu_read_lock(); } - - rcu_read_unlock(); - return 0; } @@ -262,14 +246,17 @@ static struct qrtr_server *server_add(un goto err; /* Delete the old server on the same port */ - old = radix_tree_lookup(&node->servers, port); + old = xa_store(&node->servers, port, srv, GFP_KERNEL); if (old) { - radix_tree_delete(&node->servers, port); - kfree(old); + if (xa_is_err(old)) { + pr_err("failed to add server [0x%x:0x%x] ret:%d\n", + srv->service, srv->instance, xa_err(old)); + goto err; + } else { + kfree(old); + } } - radix_tree_insert(&node->servers, port, srv); - trace_qrtr_ns_server_add(srv->service, srv->instance, srv->node, srv->port); @@ -286,11 +273,11 @@ static int server_del(struct qrtr_node * struct qrtr_server *srv; struct list_head *li; - srv = radix_tree_lookup(&node->servers, port); + srv = xa_load(&node->servers, port); if (!srv) return -ENOENT; - radix_tree_delete(&node->servers, port); + xa_erase(&node->servers, port); /* Broadcast the removal of local servers */ if (srv->node == qrtr_ns.local_node && bcast) @@ -350,13 +337,12 @@ static int ctrl_cmd_hello(struct sockadd static int ctrl_cmd_bye(struct sockaddr_qrtr *from) { struct qrtr_node *local_node; - struct radix_tree_iter iter; struct qrtr_ctrl_pkt pkt; struct qrtr_server *srv; struct sockaddr_qrtr sq; struct msghdr msg = { }; struct qrtr_node *node; - void __rcu **slot; + unsigned long index; struct kvec iv; int ret; @@ -367,22 +353,9 @@ static int ctrl_cmd_bye(struct sockaddr_ if (!node) return 0; - rcu_read_lock(); /* Advertise removal of this client to all servers of remote node */ - radix_tree_for_each_slot(slot, &node->servers, &iter, 0) { - srv = radix_tree_deref_slot(slot); - if (!srv) - continue; - if (radix_tree_deref_retry(srv)) { - slot = radix_tree_iter_retry(&iter); - continue; - } - slot = radix_tree_iter_resume(slot, &iter); - rcu_read_unlock(); + xa_for_each(&node->servers, index, srv) server_del(node, srv->port, true); - rcu_read_lock(); - } - rcu_read_unlock(); /* Advertise the removal of this client to all local servers */ local_node = node_get(qrtr_ns.local_node); @@ -393,18 +366,7 @@ static int ctrl_cmd_bye(struct sockaddr_ pkt.cmd = cpu_to_le32(QRTR_TYPE_BYE); pkt.client.node = cpu_to_le32(from->sq_node); - rcu_read_lock(); - radix_tree_for_each_slot(slot, &local_node->servers, &iter, 0) { - srv = radix_tree_deref_slot(slot); - if (!srv) - continue; - if (radix_tree_deref_retry(srv)) { - slot = radix_tree_iter_retry(&iter); - continue; - } - slot = radix_tree_iter_resume(slot, &iter); - rcu_read_unlock(); - + xa_for_each(&local_node->servers, index, srv) { sq.sq_family = AF_QIPCRTR; sq.sq_node = srv->node; sq.sq_port = srv->port; @@ -417,11 +379,7 @@ static int ctrl_cmd_bye(struct sockaddr_ pr_err("failed to send bye cmd\n"); return ret; } - rcu_read_lock(); } - - rcu_read_unlock(); - return 0; } @@ -429,7 +387,6 @@ static int ctrl_cmd_del_client(struct so unsigned int node_id, unsigned int port) { struct qrtr_node *local_node; - struct radix_tree_iter iter; struct qrtr_lookup *lookup; struct qrtr_ctrl_pkt pkt; struct msghdr msg = { }; @@ -438,7 +395,7 @@ static int ctrl_cmd_del_client(struct so struct qrtr_node *node; struct list_head *tmp; struct list_head *li; - void __rcu **slot; + unsigned long index; struct kvec iv; int ret; @@ -484,18 +441,7 @@ static int ctrl_cmd_del_client(struct so pkt.client.node = cpu_to_le32(node_id); pkt.client.port = cpu_to_le32(port); - rcu_read_lock(); - radix_tree_for_each_slot(slot, &local_node->servers, &iter, 0) { - srv = radix_tree_deref_slot(slot); - if (!srv) - continue; - if (radix_tree_deref_retry(srv)) { - slot = radix_tree_iter_retry(&iter); - continue; - } - slot = radix_tree_iter_resume(slot, &iter); - rcu_read_unlock(); - + xa_for_each(&local_node->servers, index, srv) { sq.sq_family = AF_QIPCRTR; sq.sq_node = srv->node; sq.sq_port = srv->port; @@ -508,11 +454,7 @@ static int ctrl_cmd_del_client(struct so pr_err("failed to send del client cmd\n"); return ret; } - rcu_read_lock(); } - - rcu_read_unlock(); - return 0; } @@ -585,13 +527,12 @@ static int ctrl_cmd_del_server(struct so static int ctrl_cmd_new_lookup(struct sockaddr_qrtr *from, unsigned int service, unsigned int instance) { - struct radix_tree_iter node_iter; struct qrtr_server_filter filter; - struct radix_tree_iter srv_iter; struct qrtr_lookup *lookup; + struct qrtr_server *srv; struct qrtr_node *node; - void __rcu **node_slot; - void __rcu **srv_slot; + unsigned long node_idx; + unsigned long srv_idx; /* Accept only local observers */ if (from->sq_node != qrtr_ns.local_node) @@ -616,40 +557,14 @@ static int ctrl_cmd_new_lookup(struct so filter.service = service; filter.instance = instance; - rcu_read_lock(); - radix_tree_for_each_slot(node_slot, &nodes, &node_iter, 0) { - node = radix_tree_deref_slot(node_slot); - if (!node) - continue; - if (radix_tree_deref_retry(node)) { - node_slot = radix_tree_iter_retry(&node_iter); - continue; - } - node_slot = radix_tree_iter_resume(node_slot, &node_iter); - - radix_tree_for_each_slot(srv_slot, &node->servers, - &srv_iter, 0) { - struct qrtr_server *srv; - - srv = radix_tree_deref_slot(srv_slot); - if (!srv) - continue; - if (radix_tree_deref_retry(srv)) { - srv_slot = radix_tree_iter_retry(&srv_iter); - continue; - } - + xa_for_each(&nodes, node_idx, node) { + xa_for_each(&node->servers, srv_idx, srv) { if (!server_match(srv, &filter)) continue; - srv_slot = radix_tree_iter_resume(srv_slot, &srv_iter); - - rcu_read_unlock(); lookup_notify(from, srv, true); - rcu_read_lock(); } } - rcu_read_unlock(); /* Empty notification, to indicate end of listing */ lookup_notify(from, NULL, true);