summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2018-03-30 16:05:44 -0400
committerDavid Howells <dhowells@redhat.com>2018-03-30 16:05:44 -0400
commit17226f1240381812c3a4927dc9da2814fb71c8ac (patch)
tree49ef90fafb4ae55ff13e0c373a81bbc509718bd8
parent1159d4b496f57d5b8ee27c8b90b9d01c332e2e11 (diff)
rxrpc: Fix leak of rxrpc_peer objects
When a new client call is requested, an rxrpc_conn_parameters struct object is passed in with a bunch of parameters set, such as the local endpoint to use. A pointer to the target peer record is also placed in there by rxrpc_get_client_conn() - and this is removed if and only if a new connection object is allocated. Thus it leaks if a new connection object isn't allocated. Fix this by putting any peer object attached to the rxrpc_conn_parameters object in the function that allocated it. Fixes: 19ffa01c9c45 ("rxrpc: Use structs to hold connection params and protocol info") Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r--net/rxrpc/af_rxrpc.c2
-rw-r--r--net/rxrpc/ar-internal.h1
-rw-r--r--net/rxrpc/net_ns.c1
-rw-r--r--net/rxrpc/peer_object.c21
-rw-r--r--net/rxrpc/sendmsg.c1
5 files changed, 26 insertions, 0 deletions
diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c
index 0b3026b8fa40..9a2c8e7c000e 100644
--- a/net/rxrpc/af_rxrpc.c
+++ b/net/rxrpc/af_rxrpc.c
@@ -324,6 +324,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
324 mutex_unlock(&call->user_mutex); 324 mutex_unlock(&call->user_mutex);
325 } 325 }
326 326
327 rxrpc_put_peer(cp.peer);
327 _leave(" = %p", call); 328 _leave(" = %p", call);
328 return call; 329 return call;
329} 330}
@@ -447,6 +448,7 @@ int rxrpc_kernel_retry_call(struct socket *sock, struct rxrpc_call *call,
447 ret = rxrpc_retry_client_call(rx, call, &cp, srx, GFP_KERNEL); 448 ret = rxrpc_retry_client_call(rx, call, &cp, srx, GFP_KERNEL);
448 449
449 mutex_unlock(&call->user_mutex); 450 mutex_unlock(&call->user_mutex);
451 rxrpc_put_peer(cp.peer);
450 _leave(" = %d", ret); 452 _leave(" = %d", ret);
451 return ret; 453 return ret;
452} 454}
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
index c46583bc255d..90d7079e0aa9 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -1041,6 +1041,7 @@ struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_local *,
1041struct rxrpc_peer *rxrpc_alloc_peer(struct rxrpc_local *, gfp_t); 1041struct rxrpc_peer *rxrpc_alloc_peer(struct rxrpc_local *, gfp_t);
1042struct rxrpc_peer *rxrpc_lookup_incoming_peer(struct rxrpc_local *, 1042struct rxrpc_peer *rxrpc_lookup_incoming_peer(struct rxrpc_local *,
1043 struct rxrpc_peer *); 1043 struct rxrpc_peer *);
1044void rxrpc_destroy_all_peers(struct rxrpc_net *);
1044struct rxrpc_peer *rxrpc_get_peer(struct rxrpc_peer *); 1045struct rxrpc_peer *rxrpc_get_peer(struct rxrpc_peer *);
1045struct rxrpc_peer *rxrpc_get_peer_maybe(struct rxrpc_peer *); 1046struct rxrpc_peer *rxrpc_get_peer_maybe(struct rxrpc_peer *);
1046void rxrpc_put_peer(struct rxrpc_peer *); 1047void rxrpc_put_peer(struct rxrpc_peer *);
diff --git a/net/rxrpc/net_ns.c b/net/rxrpc/net_ns.c
index fa9ce60e7bfa..c7a023fb22d0 100644
--- a/net/rxrpc/net_ns.c
+++ b/net/rxrpc/net_ns.c
@@ -118,6 +118,7 @@ static __net_exit void rxrpc_exit_net(struct net *net)
118 cancel_work_sync(&rxnet->peer_keepalive_work); 118 cancel_work_sync(&rxnet->peer_keepalive_work);
119 rxrpc_destroy_all_calls(rxnet); 119 rxrpc_destroy_all_calls(rxnet);
120 rxrpc_destroy_all_connections(rxnet); 120 rxrpc_destroy_all_connections(rxnet);
121 rxrpc_destroy_all_peers(rxnet);
121 rxrpc_destroy_all_locals(rxnet); 122 rxrpc_destroy_all_locals(rxnet);
122 proc_remove(rxnet->proc_net); 123 proc_remove(rxnet->proc_net);
123} 124}
diff --git a/net/rxrpc/peer_object.c b/net/rxrpc/peer_object.c
index a4a750aea1e5..1b7e8107b3ae 100644
--- a/net/rxrpc/peer_object.c
+++ b/net/rxrpc/peer_object.c
@@ -463,6 +463,27 @@ void rxrpc_put_peer(struct rxrpc_peer *peer)
463 } 463 }
464} 464}
465 465
466/*
467 * Make sure all peer records have been discarded.
468 */
469void rxrpc_destroy_all_peers(struct rxrpc_net *rxnet)
470{
471 struct rxrpc_peer *peer;
472 int i;
473
474 for (i = 0; i < HASH_SIZE(rxnet->peer_hash); i++) {
475 if (hlist_empty(&rxnet->peer_hash[i]))
476 continue;
477
478 hlist_for_each_entry(peer, &rxnet->peer_hash[i], hash_link) {
479 pr_err("Leaked peer %u {%u} %pISp\n",
480 peer->debug_id,
481 atomic_read(&peer->usage),
482 &peer->srx.transport);
483 }
484 }
485}
486
466/** 487/**
467 * rxrpc_kernel_get_peer - Get the peer address of a call 488 * rxrpc_kernel_get_peer - Get the peer address of a call
468 * @sock: The socket on which the call is in progress. 489 * @sock: The socket on which the call is in progress.
diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c
index a62980a80151..206e802ccbdc 100644
--- a/net/rxrpc/sendmsg.c
+++ b/net/rxrpc/sendmsg.c
@@ -586,6 +586,7 @@ rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg,
586 atomic_inc_return(&rxrpc_debug_id)); 586 atomic_inc_return(&rxrpc_debug_id));
587 /* The socket is now unlocked */ 587 /* The socket is now unlocked */
588 588
589 rxrpc_put_peer(cp.peer);
589 _leave(" = %p\n", call); 590 _leave(" = %p\n", call);
590 return call; 591 return call;
591} 592}