Commit 1ab7ea1f authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'io_uring-5.6-20200320' of git://git.kernel.dk/linux-block

Pull io_uring fixes from Jens Axboe:
 "Two different fixes in here:

   - Fix for a potential NULL pointer deref for links with async or
     drain marked (Pavel)

   - Fix for not properly checking RLIMIT_NOFILE for async punted
     operations.

     This affects openat/openat2, which were added this cycle, and
     accept4. I did a full audit of other cases where we might check
     current->signal->rlim[] and found only RLIMIT_FSIZE for buffered
     writes and fallocate. That one is fixed and queued for 5.7 and
     marked stable"

* tag 'io_uring-5.6-20200320' of git://git.kernel.dk/linux-block:
  io_uring: make sure accept honor rlimit nofile
  io_uring: make sure openat/openat2 honor rlimit nofile
  io_uring: NULL-deref for IOSQE_{ASYNC,DRAIN}
parents 6c1bae74 09952e3e
...@@ -540,9 +540,14 @@ static int alloc_fd(unsigned start, unsigned flags) ...@@ -540,9 +540,14 @@ static int alloc_fd(unsigned start, unsigned flags)
return __alloc_fd(current->files, start, rlimit(RLIMIT_NOFILE), flags); return __alloc_fd(current->files, start, rlimit(RLIMIT_NOFILE), flags);
} }
int __get_unused_fd_flags(unsigned flags, unsigned long nofile)
{
return __alloc_fd(current->files, 0, nofile, flags);
}
int get_unused_fd_flags(unsigned flags) int get_unused_fd_flags(unsigned flags)
{ {
return __alloc_fd(current->files, 0, rlimit(RLIMIT_NOFILE), flags); return __get_unused_fd_flags(flags, rlimit(RLIMIT_NOFILE));
} }
EXPORT_SYMBOL(get_unused_fd_flags); EXPORT_SYMBOL(get_unused_fd_flags);
......
...@@ -343,6 +343,7 @@ struct io_accept { ...@@ -343,6 +343,7 @@ struct io_accept {
struct sockaddr __user *addr; struct sockaddr __user *addr;
int __user *addr_len; int __user *addr_len;
int flags; int flags;
unsigned long nofile;
}; };
struct io_sync { struct io_sync {
...@@ -397,6 +398,7 @@ struct io_open { ...@@ -397,6 +398,7 @@ struct io_open {
struct filename *filename; struct filename *filename;
struct statx __user *buffer; struct statx __user *buffer;
struct open_how how; struct open_how how;
unsigned long nofile;
}; };
struct io_files_update { struct io_files_update {
...@@ -2577,6 +2579,7 @@ static int io_openat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) ...@@ -2577,6 +2579,7 @@ static int io_openat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
return ret; return ret;
} }
req->open.nofile = rlimit(RLIMIT_NOFILE);
req->flags |= REQ_F_NEED_CLEANUP; req->flags |= REQ_F_NEED_CLEANUP;
return 0; return 0;
} }
...@@ -2618,6 +2621,7 @@ static int io_openat2_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) ...@@ -2618,6 +2621,7 @@ static int io_openat2_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
return ret; return ret;
} }
req->open.nofile = rlimit(RLIMIT_NOFILE);
req->flags |= REQ_F_NEED_CLEANUP; req->flags |= REQ_F_NEED_CLEANUP;
return 0; return 0;
} }
...@@ -2636,7 +2640,7 @@ static int io_openat2(struct io_kiocb *req, struct io_kiocb **nxt, ...@@ -2636,7 +2640,7 @@ static int io_openat2(struct io_kiocb *req, struct io_kiocb **nxt,
if (ret) if (ret)
goto err; goto err;
ret = get_unused_fd_flags(req->open.how.flags); ret = __get_unused_fd_flags(req->open.how.flags, req->open.nofile);
if (ret < 0) if (ret < 0)
goto err; goto err;
...@@ -3321,6 +3325,7 @@ static int io_accept_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) ...@@ -3321,6 +3325,7 @@ static int io_accept_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
accept->addr = u64_to_user_ptr(READ_ONCE(sqe->addr)); accept->addr = u64_to_user_ptr(READ_ONCE(sqe->addr));
accept->addr_len = u64_to_user_ptr(READ_ONCE(sqe->addr2)); accept->addr_len = u64_to_user_ptr(READ_ONCE(sqe->addr2));
accept->flags = READ_ONCE(sqe->accept_flags); accept->flags = READ_ONCE(sqe->accept_flags);
accept->nofile = rlimit(RLIMIT_NOFILE);
return 0; return 0;
#else #else
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -3337,7 +3342,8 @@ static int __io_accept(struct io_kiocb *req, struct io_kiocb **nxt, ...@@ -3337,7 +3342,8 @@ static int __io_accept(struct io_kiocb *req, struct io_kiocb **nxt,
file_flags = force_nonblock ? O_NONBLOCK : 0; file_flags = force_nonblock ? O_NONBLOCK : 0;
ret = __sys_accept4_file(req->file, file_flags, accept->addr, ret = __sys_accept4_file(req->file, file_flags, accept->addr,
accept->addr_len, accept->flags); accept->addr_len, accept->flags,
accept->nofile);
if (ret == -EAGAIN && force_nonblock) if (ret == -EAGAIN && force_nonblock)
return -EAGAIN; return -EAGAIN;
if (ret == -ERESTARTSYS) if (ret == -ERESTARTSYS)
...@@ -4131,6 +4137,9 @@ static int io_req_defer_prep(struct io_kiocb *req, ...@@ -4131,6 +4137,9 @@ static int io_req_defer_prep(struct io_kiocb *req,
{ {
ssize_t ret = 0; ssize_t ret = 0;
if (!sqe)
return 0;
if (io_op_defs[req->opcode].file_table) { if (io_op_defs[req->opcode].file_table) {
ret = io_grab_files(req); ret = io_grab_files(req);
if (unlikely(ret)) if (unlikely(ret))
...@@ -4907,6 +4916,11 @@ static bool io_submit_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe, ...@@ -4907,6 +4916,11 @@ static bool io_submit_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
if (sqe_flags & (IOSQE_IO_LINK|IOSQE_IO_HARDLINK)) { if (sqe_flags & (IOSQE_IO_LINK|IOSQE_IO_HARDLINK)) {
req->flags |= REQ_F_LINK; req->flags |= REQ_F_LINK;
INIT_LIST_HEAD(&req->link_list); INIT_LIST_HEAD(&req->link_list);
if (io_alloc_async_ctx(req)) {
ret = -EAGAIN;
goto err_req;
}
ret = io_req_defer_prep(req, sqe); ret = io_req_defer_prep(req, sqe);
if (ret) if (ret)
req->flags |= REQ_F_FAIL_LINK; req->flags |= REQ_F_FAIL_LINK;
......
...@@ -85,6 +85,7 @@ extern int f_dupfd(unsigned int from, struct file *file, unsigned flags); ...@@ -85,6 +85,7 @@ extern int f_dupfd(unsigned int from, struct file *file, unsigned flags);
extern int replace_fd(unsigned fd, struct file *file, unsigned flags); extern int replace_fd(unsigned fd, struct file *file, unsigned flags);
extern void set_close_on_exec(unsigned int fd, int flag); extern void set_close_on_exec(unsigned int fd, int flag);
extern bool get_close_on_exec(unsigned int fd); extern bool get_close_on_exec(unsigned int fd);
extern int __get_unused_fd_flags(unsigned flags, unsigned long nofile);
extern int get_unused_fd_flags(unsigned flags); extern int get_unused_fd_flags(unsigned flags);
extern void put_unused_fd(unsigned int fd); extern void put_unused_fd(unsigned int fd);
......
...@@ -401,7 +401,8 @@ extern int __sys_sendto(int fd, void __user *buff, size_t len, ...@@ -401,7 +401,8 @@ extern int __sys_sendto(int fd, void __user *buff, size_t len,
int addr_len); int addr_len);
extern int __sys_accept4_file(struct file *file, unsigned file_flags, extern int __sys_accept4_file(struct file *file, unsigned file_flags,
struct sockaddr __user *upeer_sockaddr, struct sockaddr __user *upeer_sockaddr,
int __user *upeer_addrlen, int flags); int __user *upeer_addrlen, int flags,
unsigned long nofile);
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);
......
...@@ -1707,7 +1707,8 @@ SYSCALL_DEFINE2(listen, int, fd, int, backlog) ...@@ -1707,7 +1707,8 @@ SYSCALL_DEFINE2(listen, int, fd, int, backlog)
int __sys_accept4_file(struct file *file, unsigned file_flags, int __sys_accept4_file(struct file *file, unsigned file_flags,
struct sockaddr __user *upeer_sockaddr, struct sockaddr __user *upeer_sockaddr,
int __user *upeer_addrlen, int flags) int __user *upeer_addrlen, int flags,
unsigned long nofile)
{ {
struct socket *sock, *newsock; struct socket *sock, *newsock;
struct file *newfile; struct file *newfile;
...@@ -1738,7 +1739,7 @@ int __sys_accept4_file(struct file *file, unsigned file_flags, ...@@ -1738,7 +1739,7 @@ int __sys_accept4_file(struct file *file, unsigned file_flags,
*/ */
__module_get(newsock->ops->owner); __module_get(newsock->ops->owner);
newfd = get_unused_fd_flags(flags); newfd = __get_unused_fd_flags(flags, nofile);
if (unlikely(newfd < 0)) { if (unlikely(newfd < 0)) {
err = newfd; err = newfd;
sock_release(newsock); sock_release(newsock);
...@@ -1807,7 +1808,8 @@ int __sys_accept4(int fd, struct sockaddr __user *upeer_sockaddr, ...@@ -1807,7 +1808,8 @@ int __sys_accept4(int fd, struct sockaddr __user *upeer_sockaddr,
f = fdget(fd); f = fdget(fd);
if (f.file) { if (f.file) {
ret = __sys_accept4_file(f.file, 0, upeer_sockaddr, ret = __sys_accept4_file(f.file, 0, upeer_sockaddr,
upeer_addrlen, flags); upeer_addrlen, flags,
rlimit(RLIMIT_NOFILE));
if (f.flags) if (f.flags)
fput(f.file); fput(f.file);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment