rxrpc: Allow list of in-use local UDP endpoints to be viewed in /proc

[ Upstream commit 33912c2639ad76660988c8ca97e4d18fca89b668 ]

Allow the list of in-use local UDP endpoints in the current network
namespace to be viewed in /proc.

To aid with this, the endpoint list is converted to an hlist and RCU-safe
manipulation is used so that the list can be read with only the RCU
read lock held.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: linux-afs@lists.infradead.org
Signed-off-by: David S. Miller <davem@davemloft.net>
Stable-dep-of: 3bcd6c7eaa53 ("rxrpc: Fix race between conn bundle lookup and bundle removal [ZDI-CAN-15975]")
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
David Howells
2022-05-21 08:45:15 +01:00
committed by Greg Kroah-Hartman
parent a2d5dba2fc
commit bddde342c6
4 changed files with 94 additions and 22 deletions

View File

@@ -81,7 +81,7 @@ static struct rxrpc_local *rxrpc_alloc_local(struct rxrpc_net *rxnet,
atomic_set(&local->usage, 1);
atomic_set(&local->active_users, 1);
local->rxnet = rxnet;
INIT_LIST_HEAD(&local->link);
INIT_HLIST_NODE(&local->link);
INIT_WORK(&local->processor, rxrpc_local_processor);
init_rwsem(&local->defrag_sem);
skb_queue_head_init(&local->reject_queue);
@@ -199,7 +199,7 @@ struct rxrpc_local *rxrpc_lookup_local(struct net *net,
{
struct rxrpc_local *local;
struct rxrpc_net *rxnet = rxrpc_net(net);
struct list_head *cursor;
struct hlist_node *cursor;
const char *age;
long diff;
int ret;
@@ -209,16 +209,12 @@ struct rxrpc_local *rxrpc_lookup_local(struct net *net,
mutex_lock(&rxnet->local_mutex);
for (cursor = rxnet->local_endpoints.next;
cursor != &rxnet->local_endpoints;
cursor = cursor->next) {
local = list_entry(cursor, struct rxrpc_local, link);
hlist_for_each(cursor, &rxnet->local_endpoints) {
local = hlist_entry(cursor, struct rxrpc_local, link);
diff = rxrpc_local_cmp_key(local, srx);
if (diff < 0)
if (diff != 0)
continue;
if (diff > 0)
break;
/* Services aren't allowed to share transport sockets, so
* reject that here. It is possible that the object is dying -
@@ -230,9 +226,10 @@ struct rxrpc_local *rxrpc_lookup_local(struct net *net,
goto addr_in_use;
}
/* Found a match. We replace a dying object. Attempting to
* bind the transport socket may still fail if we're attempting
* to use a local address that the dying object is still using.
/* Found a match. We want to replace a dying object.
* Attempting to bind the transport socket may still fail if
* we're attempting to use a local address that the dying
* object is still using.
*/
if (!rxrpc_use_local(local))
break;
@@ -249,10 +246,12 @@ struct rxrpc_local *rxrpc_lookup_local(struct net *net,
if (ret < 0)
goto sock_error;
if (cursor != &rxnet->local_endpoints)
list_replace_init(cursor, &local->link);
else
list_add_tail(&local->link, cursor);
if (cursor) {
hlist_replace_rcu(cursor, &local->link);
cursor->pprev = NULL;
} else {
hlist_add_head_rcu(&local->link, &rxnet->local_endpoints);
}
age = "new";
found:
@@ -393,7 +392,7 @@ static void rxrpc_local_destroyer(struct rxrpc_local *local)
local->dead = true;
mutex_lock(&rxnet->local_mutex);
list_del_init(&local->link);
hlist_del_init_rcu(&local->link);
mutex_unlock(&rxnet->local_mutex);
rxrpc_clean_up_local_conns(local);
@@ -480,9 +479,9 @@ void rxrpc_destroy_all_locals(struct rxrpc_net *rxnet)
flush_workqueue(rxrpc_workqueue);
if (!list_empty(&rxnet->local_endpoints)) {
if (!hlist_empty(&rxnet->local_endpoints)) {
mutex_lock(&rxnet->local_mutex);
list_for_each_entry(local, &rxnet->local_endpoints, link) {
hlist_for_each_entry(local, &rxnet->local_endpoints, link) {
pr_err("AF_RXRPC: Leaked local %p {%d}\n",
local, atomic_read(&local->usage));
}