Commit de2ea4b6 authored by Jens Axboe's avatar Jens Axboe
Browse files

net: add __sys_accept4_file() helper



This is identical to __sys_accept4(), except it takes a struct file
instead of an fd, and it also allows passing in extra file->f_flags
flags. The latter is done to support masking in O_NONBLOCK without
manipulating the original file flags.

No functional changes in this patch.

Cc: netdev@vger.kernel.org
Acked-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent fcb323cc
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -392,6 +392,9 @@ extern int __sys_recvfrom(int fd, void __user *ubuf, size_t size,
extern int __sys_sendto(int fd, void __user *buff, size_t len,
extern int __sys_sendto(int fd, void __user *buff, size_t len,
			unsigned int flags, struct sockaddr __user *addr,
			unsigned int flags, struct sockaddr __user *addr,
			int addr_len);
			int addr_len);
extern int __sys_accept4_file(struct file *file, unsigned file_flags,
			struct sockaddr __user *upeer_sockaddr,
			 int __user *upeer_addrlen, int flags);
extern int __sys_accept4(int fd, struct sockaddr __user *upeer_sockaddr,
extern int __sys_accept4(int fd, struct sockaddr __user *upeer_sockaddr,
			 int __user *upeer_addrlen, int flags);
			 int __user *upeer_addrlen, int flags);
extern int __sys_socket(int family, int type, int protocol);
extern int __sys_socket(int family, int type, int protocol);
+41 −24
Original line number Original line Diff line number Diff line
@@ -1690,24 +1690,13 @@ SYSCALL_DEFINE2(listen, int, fd, int, backlog)
	return __sys_listen(fd, backlog);
	return __sys_listen(fd, backlog);
}
}


/*
int __sys_accept4_file(struct file *file, unsigned file_flags,
 *	For accept, we attempt to create a new socket, set up the link
		       struct sockaddr __user *upeer_sockaddr,
 *	with the client, wake up the client, then return the new
 *	connected fd. We collect the address of the connector in kernel
 *	space and move it to user at the very end. This is unclean because
 *	we open the socket then return an error.
 *
 *	1003.1g adds the ability to recvmsg() to query connection pending
 *	status to recvmsg. We need to add that support in a way thats
 *	clean when we restructure accept also.
 */

int __sys_accept4(int fd, struct sockaddr __user *upeer_sockaddr,
		       int __user *upeer_addrlen, int flags)
		       int __user *upeer_addrlen, int flags)
{
{
	struct socket *sock, *newsock;
	struct socket *sock, *newsock;
	struct file *newfile;
	struct file *newfile;
	int err, len, newfd, fput_needed;
	int err, len, newfd;
	struct sockaddr_storage address;
	struct sockaddr_storage address;


	if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
	if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
@@ -1716,14 +1705,14 @@ int __sys_accept4(int fd, struct sockaddr __user *upeer_sockaddr,
	if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))
	if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))
		flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK;
		flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK;


	sock = sockfd_lookup_light(fd, &err, &fput_needed);
	sock = sock_from_file(file, &err);
	if (!sock)
	if (!sock)
		goto out;
		goto out;


	err = -ENFILE;
	err = -ENFILE;
	newsock = sock_alloc();
	newsock = sock_alloc();
	if (!newsock)
	if (!newsock)
		goto out_put;
		goto out;


	newsock->type = sock->type;
	newsock->type = sock->type;
	newsock->ops = sock->ops;
	newsock->ops = sock->ops;
@@ -1738,20 +1727,21 @@ int __sys_accept4(int fd, struct sockaddr __user *upeer_sockaddr,
	if (unlikely(newfd < 0)) {
	if (unlikely(newfd < 0)) {
		err = newfd;
		err = newfd;
		sock_release(newsock);
		sock_release(newsock);
		goto out_put;
		goto out;
	}
	}
	newfile = sock_alloc_file(newsock, flags, sock->sk->sk_prot_creator->name);
	newfile = sock_alloc_file(newsock, flags, sock->sk->sk_prot_creator->name);
	if (IS_ERR(newfile)) {
	if (IS_ERR(newfile)) {
		err = PTR_ERR(newfile);
		err = PTR_ERR(newfile);
		put_unused_fd(newfd);
		put_unused_fd(newfd);
		goto out_put;
		goto out;
	}
	}


	err = security_socket_accept(sock, newsock);
	err = security_socket_accept(sock, newsock);
	if (err)
	if (err)
		goto out_fd;
		goto out_fd;


	err = sock->ops->accept(sock, newsock, sock->file->f_flags, false);
	err = sock->ops->accept(sock, newsock, sock->file->f_flags | file_flags,
					false);
	if (err < 0)
	if (err < 0)
		goto out_fd;
		goto out_fd;


@@ -1772,15 +1762,42 @@ int __sys_accept4(int fd, struct sockaddr __user *upeer_sockaddr,


	fd_install(newfd, newfile);
	fd_install(newfd, newfile);
	err = newfd;
	err = newfd;

out_put:
	fput_light(sock->file, fput_needed);
out:
out:
	return err;
	return err;
out_fd:
out_fd:
	fput(newfile);
	fput(newfile);
	put_unused_fd(newfd);
	put_unused_fd(newfd);
	goto out_put;
	goto out;

}

/*
 *	For accept, we attempt to create a new socket, set up the link
 *	with the client, wake up the client, then return the new
 *	connected fd. We collect the address of the connector in kernel
 *	space and move it to user at the very end. This is unclean because
 *	we open the socket then return an error.
 *
 *	1003.1g adds the ability to recvmsg() to query connection pending
 *	status to recvmsg. We need to add that support in a way thats
 *	clean when we restructure accept also.
 */

int __sys_accept4(int fd, struct sockaddr __user *upeer_sockaddr,
		  int __user *upeer_addrlen, int flags)
{
	int ret = -EBADF;
	struct fd f;

	f = fdget(fd);
	if (f.file) {
		ret = __sys_accept4_file(f.file, 0, upeer_sockaddr,
						upeer_addrlen, flags);
		if (f.flags)
			fput(f.file);
	}

	return ret;
}
}


SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr,
SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr,