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

Commit 56b31d1c authored by Al Viro's avatar Al Viro
Browse files

unexport sock_map_fd(), switch to sock_alloc_file()



Both modular callers of sock_map_fd() had been buggy; sctp one leaks
descriptor and file if copy_to_user() fails, 9p one shouldn't be
exposing file in the descriptor table at all.

Switch both to sock_alloc_file(), export it, unexport sock_map_fd() and
make it static.

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 28407630
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@ typedef enum {
struct poll_table_struct;
struct pipe_inode_info;
struct inode;
struct file;
struct net;

#define SOCK_ASYNC_NOSPACE	0
@@ -246,7 +247,7 @@ extern int sock_sendmsg(struct socket *sock, struct msghdr *msg,
				  size_t len);
extern int	     sock_recvmsg(struct socket *sock, struct msghdr *msg,
				  size_t size, int flags);
extern int 	     sock_map_fd(struct socket *sock, int flags);
extern struct file  *sock_alloc_file(struct socket *sock, int flags);
extern struct socket *sockfd_lookup(int fd, int *err);
extern struct socket *sock_from_file(struct file *file, int *err);
#define		     sockfd_put(sock) fput(sock->file)
+7 −9
Original line number Diff line number Diff line
@@ -793,30 +793,28 @@ static int p9_fd_open(struct p9_client *client, int rfd, int wfd)
static int p9_socket_open(struct p9_client *client, struct socket *csocket)
{
	struct p9_trans_fd *p;
	int ret, fd;
	struct file *file;
	int ret;

	p = kmalloc(sizeof(struct p9_trans_fd), GFP_KERNEL);
	if (!p)
		return -ENOMEM;

	csocket->sk->sk_allocation = GFP_NOIO;
	fd = sock_map_fd(csocket, 0);
	if (fd < 0) {
	file = sock_alloc_file(csocket, 0);
	if (IS_ERR(file)) {
		pr_err("%s (%d): failed to map fd\n",
		       __func__, task_pid_nr(current));
		sock_release(csocket);
		kfree(p);
		return fd;
		return PTR_ERR(file);
	}

	get_file(csocket->file);
	get_file(csocket->file);
	p->wr = p->rd = csocket->file;
	get_file(file);
	p->wr = p->rd = file;
	client->trans = p;
	client->status = Connected;

	sys_close(fd);	/* still racy */

	p->rd->f_flags |= O_NONBLOCK;

	p->conn = p9_conn_create(client);
+20 −5
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@
#include <linux/init.h>
#include <linux/crypto.h>
#include <linux/slab.h>
#include <linux/file.h>

#include <net/ip.h>
#include <net/icmp.h>
@@ -4276,6 +4277,7 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval
{
	sctp_peeloff_arg_t peeloff;
	struct socket *newsock;
	struct file *newfile;
	int retval = 0;

	if (len < sizeof(sctp_peeloff_arg_t))
@@ -4289,22 +4291,35 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval
		goto out;

	/* Map the socket to an unused fd that can be returned to the user.  */
	retval = sock_map_fd(newsock, 0);
	retval = get_unused_fd();
	if (retval < 0) {
		sock_release(newsock);
		goto out;
	}

	newfile = sock_alloc_file(newsock, 0);
	if (unlikely(IS_ERR(newfile))) {
		put_unused_fd(retval);
		sock_release(newsock);
		return PTR_ERR(newfile);
	}

	SCTP_DEBUG_PRINTK("%s: sk: %p newsk: %p sd: %d\n",
			  __func__, sk, newsock->sk, retval);

	/* Return the fd mapped to the new socket.  */
	if (put_user(len, optlen)) {
		fput(newfile);
		put_unused_fd(retval);
		return -EFAULT;
	}
	peeloff.sd = retval;
	if (put_user(len, optlen))
	if (copy_to_user(optval, &peeloff, len)) {
		fput(newfile);
		put_unused_fd(retval);
		return -EFAULT;
	if (copy_to_user(optval, &peeloff, len))
		retval = -EFAULT;

	}
	fd_install(retval, newfile);
out:
	return retval;
}
+3 −3
Original line number Diff line number Diff line
@@ -346,7 +346,7 @@ static struct file_system_type sock_fs_type = {
 *	but we take care of internal coherence yet.
 */

static struct file *sock_alloc_file(struct socket *sock, int flags)
struct file *sock_alloc_file(struct socket *sock, int flags)
{
	struct qstr name = { .name = "" };
	struct path path;
@@ -375,8 +375,9 @@ static struct file *sock_alloc_file(struct socket *sock, int flags)
	file->private_data = sock;
	return file;
}
EXPORT_SYMBOL(sock_alloc_file);

int sock_map_fd(struct socket *sock, int flags)
static int sock_map_fd(struct socket *sock, int flags)
{
	struct file *newfile;
	int fd = get_unused_fd_flags(flags);
@@ -392,7 +393,6 @@ int sock_map_fd(struct socket *sock, int flags)
	put_unused_fd(fd);
	return PTR_ERR(newfile);
}
EXPORT_SYMBOL(sock_map_fd);

struct socket *sock_from_file(struct file *file, int *err)
{