Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 266675ab authored by Ka-Cheong Poon's avatar Ka-Cheong Poon Committed by Greg Kroah-Hartman
Browse files

rds: Incorrect reference counting in TCP socket creation



[ Upstream commit 84eef2b2187ed73c0e4520cbfeb874e964a0b56a ]

Commit 0933a578 ("rds: tcp: use sock_create_lite() to create the
accept socket") has a reference counting issue in TCP socket creation
when accepting a new connection.  The code uses sock_create_lite() to
create a kernel socket.  But it does not do __module_get() on the
socket owner.  When the connection is shutdown and sock_release() is
called to free the socket, the owner's reference count is decremented
and becomes incorrect.  Note that this bug only shows up when the socket
owner is configured as a kernel module.

v2: Update comments

Fixes: 0933a578 ("rds: tcp: use sock_create_lite() to create the accept socket")
Signed-off-by: default avatarKa-Cheong Poon <ka-cheong.poon@oracle.com>
Acked-by: default avatarSantosh Shilimkar <santosh.shilimkar@oracle.com>
Acked-by: default avatarSowmini Varadhan <sowmini.varadhan@oracle.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarSasha Levin <alexander.levin@microsoft.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 2b6e7f2f
Loading
Loading
Loading
Loading
+11 −3
Original line number Diff line number Diff line
/*
 * Copyright (c) 2006 Oracle.  All rights reserved.
 * Copyright (c) 2006, 2018 Oracle.  All rights reserved.
 *
 * This software is available to you under a choice of one of two
 * licenses.  You may choose to be licensed under the terms of the GNU
@@ -142,12 +142,20 @@ int rds_tcp_accept_one(struct socket *sock)
	if (ret)
		goto out;

	new_sock->type = sock->type;
	new_sock->ops = sock->ops;
	ret = sock->ops->accept(sock, new_sock, O_NONBLOCK, true);
	if (ret < 0)
		goto out;

	/* sock_create_lite() does not get a hold on the owner module so we
	 * need to do it here.  Note that sock_release() uses sock->ops to
	 * determine if it needs to decrement the reference count.  So set
	 * sock->ops after calling accept() in case that fails.  And there's
	 * no need to do try_module_get() as the listener should have a hold
	 * already.
	 */
	new_sock->ops = sock->ops;
	__module_get(new_sock->ops->owner);

	ret = rds_tcp_keepalive(new_sock);
	if (ret < 0)
		goto out;