From 071858de47a29ae8b0bf2239a195df876806e28e Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 23 Apr 2026 05:10:15 -0600 Subject: [PATCH 1/2] io_uring/epoll: switch to using do_epoll_ctl_file() interface No functional changes in this patch. Signed-off-by: Jens Axboe --- io_uring/epoll.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/io_uring/epoll.c b/io_uring/epoll.c index 8d4610246ba0..b9db8bde27ec 100644 --- a/io_uring/epoll.c +++ b/io_uring/epoll.c @@ -51,10 +51,21 @@ int io_epoll_ctl_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) int io_epoll_ctl(struct io_kiocb *req, unsigned int issue_flags) { struct io_epoll *ie = io_kiocb_to_cmd(req, struct io_epoll); - int ret; bool force_nonblock = issue_flags & IO_URING_F_NONBLOCK; + struct epoll_key key; + int ret; - ret = do_epoll_ctl(ie->epfd, ie->op, ie->fd, &ie->event, force_nonblock); + CLASS(fd, f)(ie->epfd); + if (fd_empty(f)) + return -EBADF; + + CLASS(fd, tf)(ie->fd); + if (fd_empty(tf)) + return -EBADF; + + key.file = fd_file(tf); + key.fd = ie->fd; + ret = do_epoll_ctl_file(fd_file(f), ie->op, &key, &ie->event, force_nonblock); if (force_nonblock && ret == -EAGAIN) return -EAGAIN; From cfa1539b24aff18ecb71c6334e7270f810d145bb Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 23 Apr 2026 05:10:45 -0600 Subject: [PATCH 2/2] io_uring/epoll: disallow adding an epoll file to an epoll context One of the nastier things about epoll is how it allows adding epoll files to epoll contexts. This leads to all sorts of loop detection code, and has been a source of issues in the past. Arguably adding IORING_EPOLL_CTL is a historical mistake on the io_uring side, but we're kind of stuck with it now as it does seem to be in use according to code searches. But we can at least minimize the damage a bit and just disallow this part of epoll, where nesting issues can arise. Suggested-by: Linus Torvalds Signed-off-by: Jens Axboe --- io_uring/epoll.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/io_uring/epoll.c b/io_uring/epoll.c index b9db8bde27ec..eecd748cad01 100644 --- a/io_uring/epoll.c +++ b/io_uring/epoll.c @@ -62,6 +62,9 @@ int io_epoll_ctl(struct io_kiocb *req, unsigned int issue_flags) CLASS(fd, tf)(ie->fd); if (fd_empty(tf)) return -EBADF; + /* disallow adding an epoll context to another epoll context */ + if (ie->op == EPOLL_CTL_ADD && is_file_epoll(fd_file(tf))) + return -EINVAL; key.file = fd_file(tf); key.fd = ie->fd;