Amir Goldstein (3): io_uring: rename kiocb_end_write() local helper fs: create kiocb_{start,end}_write() helpers io_uring: use kiocb_{start,end}_write() helpers
Jens Axboe (1): io_uring/rw: fix missing NOWAIT check for O_DIRECT start write
include/linux/fs.h | 35 +++++++++++++++++++++++++++++++ io_uring/io_uring.c | 50 ++++++++++++++++++++++++--------------------- 2 files changed, 62 insertions(+), 23 deletions(-)
From: Amir Goldstein amir73il@gmail.com
stable inclusion from stable-v5.10.230 commit 955089c2403c5c75755629517d235ad99650a03c category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/IB5KQC CVE: CVE-2024-53052
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
Commit a370167fe526123637965f60859a9f1f3e1a58b7 upstream.
This helper does not take a kiocb as input and we want to create a common helper by that name that takes a kiocb as input.
Signed-off-by: Amir Goldstein amir73il@gmail.com Reviewed-by: Jan Kara jack@suse.cz Reviewed-by: Jens Axboe axboe@kernel.dk Message-Id: 20230817141337.1025891-2-amir73il@gmail.com Signed-off-by: Christian Brauner brauner@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org
Conflicts: io_uring/io_uring.c [Context differences.] Signed-off-by: Baokun Li libaokun1@huawei.com --- io_uring/io_uring.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c index efcaf9e74c83..b5808fe51271 100644 --- a/io_uring/io_uring.c +++ b/io_uring/io_uring.c @@ -2650,7 +2650,7 @@ static int io_iopoll_check(struct io_ring_ctx *ctx, long min) return ret; }
-static void kiocb_end_write(struct io_kiocb *req) +static void io_req_end_write(struct io_kiocb *req) { /* * Tell lockdep we inherited freeze protection from submission @@ -2714,7 +2714,7 @@ static bool io_rw_should_reissue(struct io_kiocb *req) static bool __io_complete_rw_common(struct io_kiocb *req, long res) { if (req->rw.kiocb.ki_flags & IOCB_WRITE) { - kiocb_end_write(req); + io_req_end_write(req); fsnotify_modify(req->file); } else { fsnotify_access(req->file); @@ -2787,7 +2787,7 @@ static void io_complete_rw_iopoll(struct kiocb *kiocb, long res, long res2) struct io_kiocb *req = container_of(kiocb, struct io_kiocb, rw.kiocb);
if (kiocb->ki_flags & IOCB_WRITE) - kiocb_end_write(req); + io_req_end_write(req); if (unlikely(res != req->result)) { if (res == -EAGAIN && io_rw_should_reissue(req)) { req->flags |= REQ_F_REISSUE; @@ -3756,7 +3756,7 @@ static int io_write(struct io_kiocb *req, unsigned int issue_flags) ret = io_setup_async_rw(req, iovec, inline_vecs, iter, false); if (!ret) { if (kiocb->ki_flags & IOCB_WRITE) - kiocb_end_write(req); + io_req_end_write(req); return -EAGAIN; } return ret;
From: Amir Goldstein amir73il@gmail.com
stable inclusion from stable-v5.10.230 commit f83a32351efd6c6676fdabd5ab0e680500bc48e0 category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/IB5KQC CVE: CVE-2024-53052
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
Commit ed0360bbab72b829437b67ebb2f9cfac19f59dfe upstream.
aio, io_uring, cachefiles and overlayfs, all open code an ugly variant of file_{start,end}_write() to silence lockdep warnings.
Create helpers for this lockdep dance so we can use the helpers in all the callers.
Suggested-by: Jan Kara jack@suse.cz Signed-off-by: Amir Goldstein amir73il@gmail.com Reviewed-by: Jan Kara jack@suse.cz Reviewed-by: Jens Axboe axboe@kernel.dk Message-Id: 20230817141337.1025891-4-amir73il@gmail.com Signed-off-by: Christian Brauner brauner@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org Signed-off-by: Baokun Li libaokun1@huawei.com --- include/linux/fs.h | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+)
diff --git a/include/linux/fs.h b/include/linux/fs.h index afbd97e44f0b..4ce9c03d40cd 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1762,6 +1762,41 @@ static inline bool sb_start_intwrite_trylock(struct super_block *sb) return __sb_start_write_trylock(sb, SB_FREEZE_FS); }
+/** + * kiocb_start_write - get write access to a superblock for async file io + * @iocb: the io context we want to submit the write with + * + * This is a variant of sb_start_write() for async io submission. + * Should be matched with a call to kiocb_end_write(). + */ +static inline void kiocb_start_write(struct kiocb *iocb) +{ + struct inode *inode = file_inode(iocb->ki_filp); + + sb_start_write(inode->i_sb); + /* + * Fool lockdep by telling it the lock got released so that it + * doesn't complain about the held lock when we return to userspace. + */ + __sb_writers_release(inode->i_sb, SB_FREEZE_WRITE); +} + +/** + * kiocb_end_write - drop write access to a superblock after async file io + * @iocb: the io context we sumbitted the write with + * + * Should be matched with a call to kiocb_start_write(). + */ +static inline void kiocb_end_write(struct kiocb *iocb) +{ + struct inode *inode = file_inode(iocb->ki_filp); + + /* + * Tell lockdep we inherited freeze protection from submission thread. + */ + __sb_writers_acquired(inode->i_sb, SB_FREEZE_WRITE); + sb_end_write(inode->i_sb); +}
extern bool inode_owner_or_capable(const struct inode *inode);
From: Amir Goldstein amir73il@gmail.com
stable inclusion from stable-v5.10.230 commit f336622838e595868da703c4de4f892a3320de57 category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/IB5KQC CVE: CVE-2024-53052
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
Commit e484fd73f4bdcb00c2188100c2d84e9f3f5c9f7d upstream.
Use helpers instead of the open coded dance to silence lockdep warnings.
Suggested-by: Jan Kara jack@suse.cz Signed-off-by: Amir Goldstein amir73il@gmail.com Reviewed-by: Jan Kara jack@suse.cz Reviewed-by: Jens Axboe axboe@kernel.dk Message-Id: 20230817141337.1025891-5-amir73il@gmail.com Signed-off-by: Christian Brauner brauner@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org Signed-off-by: Baokun Li libaokun1@huawei.com --- io_uring/io_uring.c | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-)
diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c index b5808fe51271..e5ff11af63ea 100644 --- a/io_uring/io_uring.c +++ b/io_uring/io_uring.c @@ -2652,15 +2652,10 @@ static int io_iopoll_check(struct io_ring_ctx *ctx, long min)
static void io_req_end_write(struct io_kiocb *req) { - /* - * Tell lockdep we inherited freeze protection from submission - * thread. - */ if (req->flags & REQ_F_ISREG) { - struct super_block *sb = file_inode(req->file)->i_sb; + struct io_rw *rw = &req->rw;
- __sb_writers_acquired(sb, SB_FREEZE_WRITE); - sb_end_write(sb); + kiocb_end_write(&rw->kiocb); } }
@@ -3709,18 +3704,8 @@ static int io_write(struct io_kiocb *req, unsigned int issue_flags) if (unlikely(ret)) goto out_free;
- /* - * Open-code file_start_write here to grab freeze protection, - * which will be released by another thread in - * io_complete_rw(). Fool lockdep by telling it the lock got - * released so that it doesn't complain about the held lock when - * we return to userspace. - */ - if (req->flags & REQ_F_ISREG) { - sb_start_write(file_inode(req->file)->i_sb); - __sb_writers_release(file_inode(req->file)->i_sb, - SB_FREEZE_WRITE); - } + if (req->flags & REQ_F_ISREG) + kiocb_start_write(kiocb); kiocb->ki_flags |= IOCB_WRITE;
if (req->file->f_op->write_iter)
From: Jens Axboe axboe@kernel.dk
stable inclusion from stable-v5.10.230 commit 485d9232112b17f389b29497ff41b97b3189546b category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/IB5KQC CVE: CVE-2024-53052
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
Commit 1d60d74e852647255bd8e76f5a22dc42531e4389 upstream.
When io_uring starts a write, it'll call kiocb_start_write() to bump the super block rwsem, preventing any freezes from happening while that write is in-flight. The freeze side will grab that rwsem for writing, excluding any new writers from happening and waiting for existing writes to finish. But io_uring unconditionally uses kiocb_start_write(), which will block if someone is currently attempting to freeze the mount point. This causes a deadlock where freeze is waiting for previous writes to complete, but the previous writes cannot complete, as the task that is supposed to complete them is blocked waiting on starting a new write. This results in the following stuck trace showing that dependency with the write blocked starting a new write:
task:fio state:D stack:0 pid:886 tgid:886 ppid:876 Call trace: __switch_to+0x1d8/0x348 __schedule+0x8e8/0x2248 schedule+0x110/0x3f0 percpu_rwsem_wait+0x1e8/0x3f8 __percpu_down_read+0xe8/0x500 io_write+0xbb8/0xff8 io_issue_sqe+0x10c/0x1020 io_submit_sqes+0x614/0x2110 __arm64_sys_io_uring_enter+0x524/0x1038 invoke_syscall+0x74/0x268 el0_svc_common.constprop.0+0x160/0x238 do_el0_svc+0x44/0x60 el0_svc+0x44/0xb0 el0t_64_sync_handler+0x118/0x128 el0t_64_sync+0x168/0x170 INFO: task fsfreeze:7364 blocked for more than 15 seconds. Not tainted 6.12.0-rc5-00063-g76aaf945701c #7963
with the attempting freezer stuck trying to grab the rwsem:
task:fsfreeze state:D stack:0 pid:7364 tgid:7364 ppid:995 Call trace: __switch_to+0x1d8/0x348 __schedule+0x8e8/0x2248 schedule+0x110/0x3f0 percpu_down_write+0x2b0/0x680 freeze_super+0x248/0x8a8 do_vfs_ioctl+0x149c/0x1b18 __arm64_sys_ioctl+0xd0/0x1a0 invoke_syscall+0x74/0x268 el0_svc_common.constprop.0+0x160/0x238 do_el0_svc+0x44/0x60 el0_svc+0x44/0xb0 el0t_64_sync_handler+0x118/0x128 el0t_64_sync+0x168/0x170
Fix this by having the io_uring side honor IOCB_NOWAIT, and only attempt a blocking grab of the super block rwsem if it isn't set. For normal issue where IOCB_NOWAIT would always be set, this returns -EAGAIN which will have io_uring core issue a blocking attempt of the write. That will in turn also get completions run, ensuring forward progress.
Since freezing requires CAP_SYS_ADMIN in the first place, this isn't something that can be triggered by a regular user.
Cc: stable@vger.kernel.org # 5.10+ Reported-by: Peter Mann peter.mann@sh.cz Link: https://lore.kernel.org/io-uring/38c94aec-81c9-4f62-b44e-1d87f5597644@sh.cz Signed-off-by: Jens Axboe axboe@kernel.dk Signed-off-by: Sasha Levin sashal@kernel.org Signed-off-by: Baokun Li libaokun1@huawei.com --- io_uring/io_uring.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-)
diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c index e5ff11af63ea..4d69fb4cf803 100644 --- a/io_uring/io_uring.c +++ b/io_uring/io_uring.c @@ -3661,6 +3661,25 @@ static int io_write_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) return io_prep_rw(req, sqe, WRITE); }
+static bool io_kiocb_start_write(struct io_kiocb *req, struct kiocb *kiocb) +{ + struct inode *inode; + bool ret; + + if (!(req->flags & REQ_F_ISREG)) + return true; + if (!(kiocb->ki_flags & IOCB_NOWAIT)) { + kiocb_start_write(kiocb); + return true; + } + + inode = file_inode(kiocb->ki_filp); + ret = sb_start_write_trylock(inode->i_sb); + if (ret) + __sb_writers_release(inode->i_sb, SB_FREEZE_WRITE); + return ret; +} + static int io_write(struct io_kiocb *req, unsigned int issue_flags) { struct iovec inline_vecs[UIO_FASTIOV], *iovec = inline_vecs; @@ -3704,8 +3723,8 @@ static int io_write(struct io_kiocb *req, unsigned int issue_flags) if (unlikely(ret)) goto out_free;
- if (req->flags & REQ_F_ISREG) - kiocb_start_write(kiocb); + if (unlikely(!io_kiocb_start_write(req, kiocb))) + goto copy_iov; kiocb->ki_flags |= IOCB_WRITE;
if (req->file->f_op->write_iter)
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://gitee.com/openeuler/kernel/pulls/13457 邮件列表地址:https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/X...
FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://gitee.com/openeuler/kernel/pulls/13457 Mailing list address: https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/X...