Skip to content

Commit 76100a8

Browse files
ying-xuedavem330
authored andcommitted
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: a62fbcc ("tipc: make subscriber server support net namespace") Signed-off-by: Ying Xue <[email protected]> Reviewed-by: Jon Maloy <[email protected]> Reviewed-by: Erik Hugne <[email protected]> Reported-by: Cong Wang <[email protected]> Tested-by: Erik Hugne <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 5284143 commit 76100a8

File tree

3 files changed

+39
-92
lines changed

3 files changed

+39
-92
lines changed

net/tipc/server.c

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,13 @@
3737
#include "core.h"
3838
#include "socket.h"
3939
#include <net/sock.h>
40+
#include <linux/module.h>
4041

4142
/* Number of messages to send before rescheduling */
4243
#define MAX_SEND_MSG_COUNT 25
4344
#define MAX_RECV_MSG_COUNT 25
4445
#define CF_CONNECTED 1
46+
#define CF_SERVER 2
4547

4648
#define sock2con(x) ((struct tipc_conn *)(x)->sk_user_data)
4749

@@ -88,9 +90,16 @@ static void tipc_clean_outqueues(struct tipc_conn *con);
8890
static void tipc_conn_kref_release(struct kref *kref)
8991
{
9092
struct tipc_conn *con = container_of(kref, struct tipc_conn, kref);
93+
struct socket *sock = con->sock;
94+
struct sock *sk;
9195

92-
if (con->sock) {
93-
tipc_sock_release_local(con->sock);
96+
if (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);
94103
con->sock = NULL;
95104
}
96105

@@ -281,7 +290,7 @@ static int tipc_accept_from_sock(struct tipc_conn *con)
281290
struct tipc_conn *newcon;
282291
int ret;
283292

284-
ret = tipc_sock_accept_local(sock, &newsock, O_NONBLOCK);
293+
ret = kernel_accept(sock, &newsock, O_NONBLOCK);
285294
if (ret < 0)
286295
return ret;
287296

@@ -309,9 +318,12 @@ static struct socket *tipc_create_listen_sock(struct tipc_conn *con)
309318
struct socket *sock = NULL;
310319
int ret;
311320

312-
ret = tipc_sock_create_local(s->net, s->type, &sock);
321+
ret = sock_create_kern(AF_TIPC, SOCK_SEQPACKET, 0, &sock);
313322
if (ret < 0)
314323
return NULL;
324+
325+
sk_change_net(sock->sk, s->net);
326+
315327
ret = kernel_setsockopt(sock, SOL_TIPC, TIPC_IMPORTANCE,
316328
(char *)&s->imp, sizeof(s->imp));
317329
if (ret < 0)
@@ -337,11 +349,31 @@ static struct socket *tipc_create_listen_sock(struct tipc_conn *con)
337349
pr_err("Unknown socket type %d\n", s->type);
338350
goto create_err;
339351
}
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+
340372
return sock;
341373

342374
create_err:
343-
sock_release(sock);
344-
con->sock = NULL;
375+
kernel_sock_shutdown(sock, SHUT_RDWR);
376+
sk_release_kernel(sock->sk);
345377
return NULL;
346378
}
347379

net/tipc/socket.c

Lines changed: 1 addition & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,7 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dsz);
121121
static const struct proto_ops packet_ops;
122122
static const struct proto_ops stream_ops;
123123
static const struct proto_ops msg_ops;
124-
125124
static struct proto tipc_proto;
126-
static struct proto tipc_proto_kern;
127125

128126
static const struct nla_policy tipc_nl_sock_policy[TIPC_NLA_SOCK_MAX + 1] = {
129127
[TIPC_NLA_SOCK_UNSPEC] = { .type = NLA_UNSPEC },
@@ -341,11 +339,7 @@ static int tipc_sk_create(struct net *net, struct socket *sock,
341339
}
342340

343341
/* Allocate socket's protocol area */
344-
if (!kern)
345-
sk = sk_alloc(net, AF_TIPC, GFP_KERNEL, &tipc_proto);
346-
else
347-
sk = sk_alloc(net, AF_TIPC, GFP_KERNEL, &tipc_proto_kern);
348-
342+
sk = sk_alloc(net, AF_TIPC, GFP_KERNEL, &tipc_proto);
349343
if (sk == NULL)
350344
return -ENOMEM;
351345

@@ -383,75 +377,6 @@ static int tipc_sk_create(struct net *net, struct socket *sock,
383377
return 0;
384378
}
385379

386-
/**
387-
* tipc_sock_create_local - create TIPC socket from inside TIPC module
388-
* @type: socket type - SOCK_RDM or SOCK_SEQPACKET
389-
*
390-
* We cannot use sock_creat_kern here because it bumps module user count.
391-
* Since socket owner and creator is the same module we must make sure
392-
* that module count remains zero for module local sockets, otherwise
393-
* we cannot do rmmod.
394-
*
395-
* Returns 0 on success, errno otherwise
396-
*/
397-
int tipc_sock_create_local(struct net *net, int type, struct socket **res)
398-
{
399-
int rc;
400-
401-
rc = sock_create_lite(AF_TIPC, type, 0, res);
402-
if (rc < 0) {
403-
pr_err("Failed to create kernel socket\n");
404-
return rc;
405-
}
406-
tipc_sk_create(net, *res, 0, 1);
407-
408-
return 0;
409-
}
410-
411-
/**
412-
* tipc_sock_release_local - release socket created by tipc_sock_create_local
413-
* @sock: the socket to be released.
414-
*
415-
* Module reference count is not incremented when such sockets are created,
416-
* so we must keep it from being decremented when they are released.
417-
*/
418-
void tipc_sock_release_local(struct socket *sock)
419-
{
420-
tipc_release(sock);
421-
sock->ops = NULL;
422-
sock_release(sock);
423-
}
424-
425-
/**
426-
* tipc_sock_accept_local - accept a connection on a socket created
427-
* with tipc_sock_create_local. Use this function to avoid that
428-
* module reference count is inadvertently incremented.
429-
*
430-
* @sock: the accepting socket
431-
* @newsock: reference to the new socket to be created
432-
* @flags: socket flags
433-
*/
434-
435-
int tipc_sock_accept_local(struct socket *sock, struct socket **newsock,
436-
int flags)
437-
{
438-
struct sock *sk = sock->sk;
439-
int ret;
440-
441-
ret = sock_create_lite(sk->sk_family, sk->sk_type,
442-
sk->sk_protocol, newsock);
443-
if (ret < 0)
444-
return ret;
445-
446-
ret = tipc_accept(sock, *newsock, flags);
447-
if (ret < 0) {
448-
sock_release(*newsock);
449-
return ret;
450-
}
451-
(*newsock)->ops = sock->ops;
452-
return ret;
453-
}
454-
455380
static void tipc_sk_callback(struct rcu_head *head)
456381
{
457382
struct tipc_sock *tsk = container_of(head, struct tipc_sock, rcu);
@@ -2608,12 +2533,6 @@ static struct proto tipc_proto = {
26082533
.sysctl_rmem = sysctl_tipc_rmem
26092534
};
26102535

2611-
static struct proto tipc_proto_kern = {
2612-
.name = "TIPC",
2613-
.obj_size = sizeof(struct tipc_sock),
2614-
.sysctl_rmem = sysctl_tipc_rmem
2615-
};
2616-
26172536
/**
26182537
* tipc_socket_init - initialize TIPC socket interface
26192538
*

net/tipc/socket.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,6 @@
4444
SKB_TRUESIZE(TIPC_MAX_USER_MSG_SIZE))
4545
int tipc_socket_init(void);
4646
void tipc_socket_stop(void);
47-
int tipc_sock_create_local(struct net *net, int type, struct socket **res);
48-
void tipc_sock_release_local(struct socket *sock);
49-
int tipc_sock_accept_local(struct socket *sock, struct socket **newsock,
50-
int flags);
5147
int tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq);
5248
void tipc_sk_mcast_rcv(struct net *net, struct sk_buff_head *arrvq,
5349
struct sk_buff_head *inputq);

0 commit comments

Comments
 (0)