2023-05-04 17:44:49

by Chuck Lever

[permalink] [raw]
Subject: [PATCH v1] SUNRPC: Fix error handling in svc_setup_socket()

From: Chuck Lever <[email protected]>

Dan points out that sock_alloc_file() releases @sock on error, but
so do all of svc_setup_socket's callers, resulting in a double-
release if sock_alloc_file() returns an error.

Rather than allocating a struct file for all new sockets, allocate
one only for sockets created during a TCP accept. For the moment,
those are the only ones that will ever be used with RPC-with-TLS.

Reported-by: Dan Carpenter <[email protected]>
Fixes: ae0d77708aae ("SUNRPC: Ensure server-side sockets have a sock->file")
Signed-off-by: Chuck Lever <[email protected]>
---
net/sunrpc/svcsock.c | 16 ++++------------
1 file changed, 4 insertions(+), 12 deletions(-)

diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index a51c9b989d58..9989194446a5 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -895,6 +895,9 @@ static struct svc_xprt *svc_tcp_accept(struct svc_xprt *xprt)
trace_svcsock_accept_err(xprt, serv->sv_name, err);
return NULL;
}
+ if (IS_ERR(sock_alloc_file(newsock, O_NONBLOCK, NULL)))
+ return NULL;
+
set_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags);

err = kernel_getpeername(newsock, sin);
@@ -935,7 +938,7 @@ static struct svc_xprt *svc_tcp_accept(struct svc_xprt *xprt)
return &newsvsk->sk_xprt;

failed:
- sock_release(newsock);
+ sockfd_put(newsock);
return NULL;
}

@@ -1430,7 +1433,6 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
struct socket *sock,
int flags)
{
- struct file *filp = NULL;
struct svc_sock *svsk;
struct sock *inet;
int pmap_register = !(flags & SVC_SOCK_ANONYMOUS);
@@ -1439,14 +1441,6 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
if (!svsk)
return ERR_PTR(-ENOMEM);

- if (!sock->file) {
- filp = sock_alloc_file(sock, O_NONBLOCK, NULL);
- if (IS_ERR(filp)) {
- kfree(svsk);
- return ERR_CAST(filp);
- }
- }
-
inet = sock->sk;

if (pmap_register) {
@@ -1456,8 +1450,6 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
inet->sk_protocol,
ntohs(inet_sk(inet)->inet_sport));
if (err < 0) {
- if (filp)
- fput(filp);
kfree(svsk);
return ERR_PTR(err);
}