From: Li Lingfeng lilingfeng3@huawei.com
hulk inclusion category: bugfix bugzilla: 187387, https://gitee.com/openeuler/kernel/issues/I5KTEM CVE: NA
--------------------------------
When we need to create a private copy of io_identity, we will get the use of current task's private structs, whitch means we should increase their reference counts. If we have grabed some other structs before, we should drop them and clear related flags. Otherwise, leak of old structs and uaf of new structs may occur.
Signed-off-by: Li Lingfeng lilingfeng3@huawei.com Reviewed-by: Zhang Yi yi.zhang@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- fs/io_uring.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+)
diff --git a/fs/io_uring.c b/fs/io_uring.c index faa81d48c812..257e4af176e6 100644 --- a/fs/io_uring.c +++ b/fs/io_uring.c @@ -1364,6 +1364,47 @@ static bool io_identity_cow(struct io_kiocb *req) return true; }
+static void io_drop_identity(struct io_kiocb *req) +{ + struct io_identity *id = req->work.identity; + + if (req->work.flags & IO_WQ_WORK_MM) { + mmdrop(id->mm); + req->work.flags &= ~IO_WQ_WORK_MM; + } +#ifdef CONFIG_BLK_CGROUP + if (req->work.flags & IO_WQ_WORK_BLKCG) { + css_put(id->blkcg_css); + req->work.flags &= ~IO_WQ_WORK_BLKCG; + } +#endif + if (req->work.flags & IO_WQ_WORK_CREDS) { + put_cred(id->creds); + req->work.flags &= ~IO_WQ_WORK_CREDS; + } + if (req->work.flags & IO_WQ_WORK_FILES) { + put_files_struct(req->work.identity->files); + put_nsproxy(req->work.identity->nsproxy); + req->work.flags &= ~IO_WQ_WORK_FILES; + } + if (req->work.flags & IO_WQ_WORK_CANCEL) + req->work.flags &= ~IO_WQ_WORK_CANCEL; + if (req->work.flags & IO_WQ_WORK_FS) { + struct fs_struct *fs = id->fs; + + spin_lock(&id->fs->lock); + if (--fs->users) + fs = NULL; + spin_unlock(&id->fs->lock); + + if (fs) + free_fs_struct(fs); + req->work.flags &= ~IO_WQ_WORK_FS; + } + if (req->work.flags & IO_WQ_WORK_FSIZE) + req->work.flags &= ~IO_WQ_WORK_FSIZE; +} + static bool io_grab_identity(struct io_kiocb *req) { const struct io_op_def *def = &io_op_defs[req->opcode]; @@ -1469,6 +1510,7 @@ static void io_prep_async_work(struct io_kiocb *req) if (io_grab_identity(req)) return;
+ io_drop_identity(req); if (!io_identity_cow(req)) return;