summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Axboe <axboe@kernel.dk>2020-03-04 08:07:32 -0700
committerJens Axboe <axboe@kernel.dk>2020-03-04 13:11:27 -0700
commit6a91ef5209d770ec01c5e9005182e66ff5f333d5 (patch)
tree299df34a94368a36838ade2cec240c501f4435e7
parenta141216cd154aa76752e0bdeb6c590bf641aaae7 (diff)
net: allow specific fd selection for __sys_accept4_file()
Add SOCK_SPECIFIC_FD to mirror O_SPECIFIC_FD, and allow passing in this flag to __sys_accept4_file(), along with the fd to be used. Any other caller of __sys_accept4_file() disallows this flag, as it can't be used outside of io_uring by the existing system calls. Reviewed-by: Josh Triplett <josh@joshtriplett.org> Signed-off-by: Jens Axboe <axboe@kernel.dk>
-rw-r--r--fs/io_uring.c2
-rw-r--r--include/linux/net.h1
-rw-r--r--include/linux/socket.h2
-rw-r--r--net/socket.c12
4 files changed, 11 insertions, 6 deletions
diff --git a/fs/io_uring.c b/fs/io_uring.c
index 2403be5a36c7..14e779f1a292 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -3934,7 +3934,7 @@ static int __io_accept(struct io_kiocb *req, bool force_nonblock)
file_flags = force_nonblock ? O_NONBLOCK : 0;
ret = __sys_accept4_file(req->file, file_flags, accept->addr,
- accept->addr_len, accept->flags);
+ accept->addr_len, accept->flags, -1);
if (ret == -EAGAIN && force_nonblock)
return -EAGAIN;
if (ret == -ERESTARTSYS)
diff --git a/include/linux/net.h b/include/linux/net.h
index 6451425e828f..807360e5f7d8 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -72,6 +72,7 @@ enum sock_type {
#define SOCK_TYPE_MASK 0xf
/* Flags for socket, socketpair, accept4 */
+#define SOCK_SPECIFIC_FD O_SPECIFIC_FD
#define SOCK_CLOEXEC O_CLOEXEC
#ifndef SOCK_NONBLOCK
#define SOCK_NONBLOCK O_NONBLOCK
diff --git a/include/linux/socket.h b/include/linux/socket.h
index fc59ac825561..ce6c97d4a439 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -405,7 +405,7 @@ extern int __sys_sendto(int fd, void __user *buff, size_t 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);
+ int __user *upeer_addrlen, int flags, int open_fd);
extern int __sys_accept4(int fd, struct sockaddr __user *upeer_sockaddr,
int __user *upeer_addrlen, int flags);
extern int __sys_socket(int family, int type, int protocol);
diff --git a/net/socket.c b/net/socket.c
index 70ede74ab24b..405fe8cd700f 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -1707,14 +1707,14 @@ SYSCALL_DEFINE2(listen, int, fd, int, backlog)
int __sys_accept4_file(struct file *file, unsigned file_flags,
struct sockaddr __user *upeer_sockaddr,
- int __user *upeer_addrlen, int flags)
+ int __user *upeer_addrlen, int flags, int open_fd)
{
struct socket *sock, *newsock;
struct file *newfile;
int err, len, newfd;
struct sockaddr_storage address;
- if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
+ if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK | SOCK_SPECIFIC_FD))
return -EINVAL;
if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))
@@ -1738,7 +1738,7 @@ int __sys_accept4_file(struct file *file, unsigned file_flags,
*/
__module_get(newsock->ops->owner);
- newfd = get_unused_fd_flags(flags);
+ newfd = get_specific_unused_fd_flags(open_fd, flags);
if (unlikely(newfd < 0)) {
err = newfd;
sock_release(newsock);
@@ -1804,10 +1804,14 @@ int __sys_accept4(int fd, struct sockaddr __user *upeer_sockaddr,
int ret = -EBADF;
struct fd f;
+ /* only valid through __sys_accept4_file() directly */
+ if (flags & SOCK_SPECIFIC_FD)
+ return -EINVAL;
+
f = fdget(fd);
if (f.file) {
ret = __sys_accept4_file(f.file, 0, upeer_sockaddr,
- upeer_addrlen, flags);
+ upeer_addrlen, flags, -1);
if (f.flags)
fput(f.file);
}