[RH7,3/4] ms/make sock_alloc_file() do sock_release() on failures

Submitted by Vasily Averin on Dec. 2, 2020, 9:56 a.m.

Details

Message ID 2bde357e-dd40-ddad-391c-5c883bf350b1@virtuozzo.com
State New
Series "Series without cover letter"
Headers show

Commit Message

Vasily Averin Dec. 2, 2020, 9:56 a.m.
From: Al Viro <viro@ZenIV.linux.org.uk>

This changes calling conventions (and simplifies the hell out
or by sock_release() done by sock_alloc_file().  Either way
the caller should not do sock_release() after that point.

Reviewed-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>

(cherry-picked from commit 8e1611e2357927b22892ecc062d65c99d0d89066)
Backport changes: removed hooks in non-existing files
	drivers/staging/lustre/lnet/lnet/lib-socket.c
	net/kcm/kcmsock.c

https://syzkaller.appspot.com/bug?id=23d0799f98b7c8c4bc3f5ecff7c28a87c64e40e8
https://jira.sw.ru/browse/PSBM-123046
Signed-off-by: Vasily Averin <vvs@virtuozzo.com>
---
 net/9p/trans_fd.c |  1 -
 net/sctp/socket.c |  1 -
 net/socket.c      | 27 +++++++++------------------
 3 files changed, 9 insertions(+), 20 deletions(-)

Patch hide | download patch | download mbox

diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c
index 02efb25..01cb566 100644
--- a/net/9p/trans_fd.c
+++ b/net/9p/trans_fd.c
@@ -807,7 +807,6 @@  static int p9_socket_open(struct p9_client *client, struct socket *csocket)
 	if (IS_ERR(file)) {
 		pr_err("%s (%d): failed to map fd\n",
 		       __func__, task_pid_nr(current));
-		sock_release(csocket);
 		kfree(p);
 		return PTR_ERR(file);
 	}
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 409fd92..67f0838 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -4888,7 +4888,6 @@  static int sctp_getsockopt_peeloff_common(struct sock *sk, sctp_peeloff_arg_t *p
 	*newfile = sock_alloc_file(newsock, 0, NULL);
 	if (IS_ERR(*newfile)) {
 		put_unused_fd(retval);
-		sock_release(newsock);
 		retval = PTR_ERR(*newfile);
 		*newfile = NULL;
 		return retval;
diff --git a/net/socket.c b/net/socket.c
index 6ea6b18..e720aa8 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -373,8 +373,10 @@  struct file *sock_alloc_file(struct socket *sock, int flags, const char *dname)
 		name.len = strlen(name.name);
 	}
 	path.dentry = d_alloc_pseudo(sock_mnt->mnt_sb, &name);
-	if (unlikely(!path.dentry))
+	if (unlikely(!path.dentry)) {
+		sock_release(sock);
 		return ERR_PTR(-ENOMEM);
+	}
 	path.mnt = mntget(sock_mnt);
 
 	d_instantiate(path.dentry, SOCK_INODE(sock));
@@ -382,9 +384,11 @@  struct file *sock_alloc_file(struct socket *sock, int flags, const char *dname)
 	file = alloc_file(&path, FMODE_READ | FMODE_WRITE,
 		  &socket_file_ops);
 	if (IS_ERR(file)) {
-		/* drop dentry, keep inode */
-		ihold(path.dentry->d_inode);
+		/* drop dentry, keep inode for a bit */
+		ihold(d_inode(path.dentry));
 		path_put(&path);
+		/* ... and now kill it properly */
+		sock_release(sock);
 		return file;
 	}
 
@@ -1476,19 +1480,9 @@  SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)
 
 	retval = sock_create(family, type, protocol, &sock);
 	if (retval < 0)
-		goto out;
+		return retval;
 
-	retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK));
-	if (retval < 0)
-		goto out_release;
-
-out:
-	/* It may be already another descriptor 8) Not kernel problem. */
-	return retval;
-
-out_release:
-	sock_release(sock);
-	return retval;
+	return sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK));
 }
 
 /*
@@ -1558,7 +1552,6 @@  SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol,
 	newfile1 = sock_alloc_file(sock1, flags, NULL);
 	if (IS_ERR(newfile1)) {
 		err = PTR_ERR(newfile1);
-		sock_release(sock1);
 		sock_release(sock2);
 		goto out;
 	}
@@ -1566,7 +1559,6 @@  SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol,
 	newfile2 = sock_alloc_file(sock2, flags, NULL);
 	if (IS_ERR(newfile2)) {
 		err = PTR_ERR(newfile2);
-		sock_release(sock2);
 		fput(newfile1);
 		goto out;
 	}
@@ -1695,7 +1687,6 @@  SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr,
 	if (IS_ERR(newfile)) {
 		err = PTR_ERR(newfile);
 		put_unused_fd(newfd);
-		sock_release(newsock);
 		goto out_put;
 	}