From: Amir Goldstein <amir73il@gmail.com> mainline inclusion from mainline-v6.7-rc1 commit 83bc1d294130cc471a89ce10770daa281a93fcb0 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/15316 CVE: CVE-2026-46054 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- A writeable mapped backing file can perform writes to the real inode. Therefore, the real path mount must be kept writable so long as the writable map exists. This may not be strictly needed for ovelrayfs private upper mount, but it is correct to take the mnt_writers count in the vfs helper. Signed-off-by: Amir Goldstein <amir73il@gmail.com> Link: https://lore.kernel.org/r/20231009153712.1566422-2-amir73il@gmail.com Signed-off-by: Christian Brauner <brauner@kernel.org> Conflicts: fs/internal.h fs/open.c [fs/internal.h: 5.10 use __mnt_drop_write instead of mnt_put_write_access. fs/open.c: 5.10 use __mnt_want_write instead of mnt_get_write_access.] Signed-off-by: Cai Xinchen <caixinchen1@huawei.com> --- fs/internal.h | 11 +++++++++-- fs/open.c | 31 +++++++++++++++++++++++++------ 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/fs/internal.h b/fs/internal.h index 1ba9a0a3e4a5..c143ffd1a174 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -111,13 +111,20 @@ struct file *alloc_empty_file(int flags, const struct cred *cred); struct file *alloc_empty_file_noaccount(int flags, const struct cred *cred); struct file *alloc_empty_backing_file(int flags, const struct cred *cred); +static inline void file_put_write_access(struct file *file) +{ + put_write_access(file->f_inode); + __mnt_drop_write(file->f_path.mnt); + if (unlikely(file->f_mode & FMODE_BACKING)) + __mnt_drop_write(backing_file_real_path(file)->mnt); +} + static inline void put_file_access(struct file *file) { if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { i_readcount_dec(file->f_inode); } else if (file->f_mode & FMODE_WRITER) { - put_write_access(file->f_inode); - __mnt_drop_write(file->f_path.mnt); + file_put_write_access(file); } } diff --git a/fs/open.c b/fs/open.c index 585ab626f802..16a11f8d6116 100644 --- a/fs/open.c +++ b/fs/open.c @@ -760,6 +760,30 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group) return ksys_fchown(fd, user, group); } +static inline int file_get_write_access(struct file *f) +{ + int error; + + error = get_write_access(f->f_inode); + if (unlikely(error)) + return error; + error = __mnt_want_write(f->f_path.mnt); + if (unlikely(error)) + goto cleanup_inode; + if (unlikely(f->f_mode & FMODE_BACKING)) { + error = __mnt_want_write(backing_file_real_path(f)->mnt); + if (unlikely(error)) + goto cleanup_mnt; + } + return 0; + +cleanup_mnt: + __mnt_drop_write(f->f_path.mnt); +cleanup_inode: + put_write_access(f->f_inode); + return error; +} + static int do_dentry_open(struct file *f, struct inode *inode, int (*open)(struct inode *, struct file *)) @@ -782,14 +806,9 @@ static int do_dentry_open(struct file *f, if ((f->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { i_readcount_inc(inode); } else if (f->f_mode & FMODE_WRITE && !special_file(inode->i_mode)) { - error = get_write_access(inode); + error = file_get_write_access(f); if (unlikely(error)) goto cleanup_file; - error = __mnt_want_write(f->f_path.mnt); - if (unlikely(error)) { - put_write_access(inode); - goto cleanup_file; - } f->f_mode |= FMODE_WRITER; } -- 2.18.0.huawei.25