aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc/server.c
diff options
context:
space:
mode:
authorYing Xue <ying.xue@windriver.com>2015-03-17 21:32:57 -0400
committerDavid S. Miller <davem@davemloft.net>2015-03-17 22:11:26 -0400
commit76100a8a64bc2ae898bc49d51dd28c1f4f5ed37b (patch)
treec868f57ef59ff263a8ed7d4ec17bf7620bb8554a /net/tipc/server.c
parent5284143057708af297eea10812a67d18e42e9abe (diff)
tipc: fix netns refcnt leak
When the TIPC module is loaded, we launch a topology server in kernel space, which in its turn is creating TIPC sockets for communication with topology server users. Because both the socket's creator and provider reside in the same module, it is necessary that the TIPC module's reference count remains zero after the server is started and the socket created; otherwise it becomes impossible to perform "rmmod" even on an idle module. Currently, we achieve this by defining a separate "tipc_proto_kern" protocol struct, that is used only for kernel space socket allocations. This structure has the "owner" field set to NULL, which restricts the module reference count from being be bumped when sk_alloc() for local sockets is called. Furthermore, we have defined three kernel-specific functions, tipc_sock_create_local(), tipc_sock_release_local() and tipc_sock_accept_local(), to avoid the module counter being modified when module local sockets are created or deleted. This has worked well until we introduced name space support. However, after name space support was introduced, we have observed that a reference count leak occurs, because the netns counter is not decremented in tipc_sock_delete_local(). This commit remedies this problem. But instead of just modifying tipc_sock_delete_local(), we eliminate the whole parallel socket handling infrastructure, and start using the regular sk_create_kern(), kernel_accept() and sk_release_kernel() calls. Since those functions manipulate the module counter, we must now compensate for that by explicitly decrementing the counter after module local sockets are created, and increment it just before calling sk_release_kernel(). Fixes: a62fbccecd62 ("tipc: make subscriber server support net namespace") Signed-off-by: Ying Xue <ying.xue@windriver.com> Reviewed-by: Jon Maloy <jon.maloy@ericson.com> Reviewed-by: Erik Hugne <erik.hugne@ericsson.com> Reported-by: Cong Wang <cwang@twopensource.com> Tested-by: Erik Hugne <erik.hugne@ericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tipc/server.c')
-rw-r--r--net/tipc/server.c44
1 files changed, 38 insertions, 6 deletions
diff --git a/net/tipc/server.c b/net/tipc/server.c
index eadd4ed45905..a57c8407cbf3 100644
--- a/net/tipc/server.c
+++ b/net/tipc/server.c
@@ -37,11 +37,13 @@
37#include "core.h" 37#include "core.h"
38#include "socket.h" 38#include "socket.h"
39#include <net/sock.h> 39#include <net/sock.h>
40#include <linux/module.h>
40 41
41/* Number of messages to send before rescheduling */ 42/* Number of messages to send before rescheduling */
42#define MAX_SEND_MSG_COUNT 25 43#define MAX_SEND_MSG_COUNT 25
43#define MAX_RECV_MSG_COUNT 25 44#define MAX_RECV_MSG_COUNT 25
44#define CF_CONNECTED 1 45#define CF_CONNECTED 1
46#define CF_SERVER 2
45 47
46#define sock2con(x) ((struct tipc_conn *)(x)->sk_user_data) 48#define sock2con(x) ((struct tipc_conn *)(x)->sk_user_data)
47 49
@@ -88,9 +90,16 @@ static void tipc_clean_outqueues(struct tipc_conn *con);
88static void tipc_conn_kref_release(struct kref *kref) 90static void tipc_conn_kref_release(struct kref *kref)
89{ 91{
90 struct tipc_conn *con = container_of(kref, struct tipc_conn, kref); 92 struct tipc_conn *con = container_of(kref, struct tipc_conn, kref);
93 struct socket *sock = con->sock;
94 struct sock *sk;
91 95
92 if (con->sock) { 96 if (sock) {
93 tipc_sock_release_local(con->sock); 97 sk = sock->sk;
98 if (test_bit(CF_SERVER, &con->flags)) {
99 __module_get(sock->ops->owner);
100 __module_get(sk->sk_prot_creator->owner);
101 }
102 sk_release_kernel(sk);
94 con->sock = NULL; 103 con->sock = NULL;
95 } 104 }
96 105
@@ -281,7 +290,7 @@ static int tipc_accept_from_sock(struct tipc_conn *con)
281 struct tipc_conn *newcon; 290 struct tipc_conn *newcon;
282 int ret; 291 int ret;
283 292
284 ret = tipc_sock_accept_local(sock, &newsock, O_NONBLOCK); 293 ret = kernel_accept(sock, &newsock, O_NONBLOCK);
285 if (ret < 0) 294 if (ret < 0)
286 return ret; 295 return ret;
287 296
@@ -309,9 +318,12 @@ static struct socket *tipc_create_listen_sock(struct tipc_conn *con)
309 struct socket *sock = NULL; 318 struct socket *sock = NULL;
310 int ret; 319 int ret;
311 320
312 ret = tipc_sock_create_local(s->net, s->type, &sock); 321 ret = sock_create_kern(AF_TIPC, SOCK_SEQPACKET, 0, &sock);
313 if (ret < 0) 322 if (ret < 0)
314 return NULL; 323 return NULL;
324
325 sk_change_net(sock->sk, s->net);
326
315 ret = kernel_setsockopt(sock, SOL_TIPC, TIPC_IMPORTANCE, 327 ret = kernel_setsockopt(sock, SOL_TIPC, TIPC_IMPORTANCE,
316 (char *)&s->imp, sizeof(s->imp)); 328 (char *)&s->imp, sizeof(s->imp));
317 if (ret < 0) 329 if (ret < 0)
@@ -337,11 +349,31 @@ static struct socket *tipc_create_listen_sock(struct tipc_conn *con)
337 pr_err("Unknown socket type %d\n", s->type); 349 pr_err("Unknown socket type %d\n", s->type);
338 goto create_err; 350 goto create_err;
339 } 351 }
352
353 /* As server's listening socket owner and creator is the same module,
354 * we have to decrease TIPC module reference count to guarantee that
355 * it remains zero after the server socket is created, otherwise,
356 * executing "rmmod" command is unable to make TIPC module deleted
357 * after TIPC module is inserted successfully.
358 *
359 * However, the reference count is ever increased twice in
360 * sock_create_kern(): one is to increase the reference count of owner
361 * of TIPC socket's proto_ops struct; another is to increment the
362 * reference count of owner of TIPC proto struct. Therefore, we must
363 * decrement the module reference count twice to ensure that it keeps
364 * zero after server's listening socket is created. Of course, we
365 * must bump the module reference count twice as well before the socket
366 * is closed.
367 */
368 module_put(sock->ops->owner);
369 module_put(sock->sk->sk_prot_creator->owner);
370 set_bit(CF_SERVER, &con->flags);
371
340 return sock; 372 return sock;
341 373
342create_err: 374create_err:
343 sock_release(sock); 375 kernel_sock_shutdown(sock, SHUT_RDWR);
344 con->sock = NULL; 376 sk_release_kernel(sock->sk);
345 return NULL; 377 return NULL;
346} 378}
347 379