From ae59a6c5e0b8496b87bfd0cf5b20c8bc2e7efa6a Mon Sep 17 00:00:00 2001 From: Edward Adam Davis Date: Wed, 18 Jun 2025 15:31:57 +0800 Subject: [PATCH] fs/ntfs3: cancle set bad inode after removing name fails mainline inclusion from mainline-v6.17-rc1 commit d99208b91933fd2a58ed9ed321af07dacd06ddc3 category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/ICU6DM CVE: CVE-2025-38615 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=d99208b91933fd2a58ed9ed321af07dacd06ddc3 -------------------------------- The reproducer uses a file0 on a ntfs3 file system with a corrupted i_link. When renaming, the file0's inode is marked as a bad inode because the file name cannot be deleted. The underlying bug is that make_bad_inode() is called on a live inode. In some cases it's "icache lookup finds a normal inode, d_splice_alias() is called to attach it to dentry, while another thread decides to call make_bad_inode() on it - that would evict it from icache, but we'd already found it there earlier". In some it's outright "we have an inode attached to dentry - that's how we got it in the first place; let's call make_bad_inode() on it just for shits and giggles". Fixes: 78ab59fee07f ("fs/ntfs3: Rework file operations") Reported-by: syzbot+1aa90f0eb1fc3e77d969@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=1aa90f0eb1fc3e77d969 Signed-off-by: Edward Adam Davis Signed-off-by: Konstantin Komarov Conflicts: fs/ntfs3/namei.c [The code 'simple_rename_timestamp(dir, dentry, new_dir, new_dentry);' does not exist in the mainline version, causing conflicts] Signed-off-by: lijuzhang --- fs/ntfs3/frecord.c | 7 +++---- fs/ntfs3/namei.c | 12 +++--------- fs/ntfs3/ntfs_fs.h | 3 +-- 3 files changed, 7 insertions(+), 15 deletions(-) diff --git a/fs/ntfs3/frecord.c b/fs/ntfs3/frecord.c index 43e7e9ce7d61..f7559f788570 100644 --- a/fs/ntfs3/frecord.c +++ b/fs/ntfs3/frecord.c @@ -2990,8 +2990,7 @@ int ni_add_name(struct ntfs_inode *dir_ni, struct ntfs_inode *ni, * ni_rename - Remove one name and insert new name. */ int ni_rename(struct ntfs_inode *dir_ni, struct ntfs_inode *new_dir_ni, - struct ntfs_inode *ni, struct NTFS_DE *de, struct NTFS_DE *new_de, - bool *is_bad) + struct ntfs_inode *ni, struct NTFS_DE *de, struct NTFS_DE *new_de) { int err; struct NTFS_DE *de2 = NULL; @@ -3014,8 +3013,8 @@ int ni_rename(struct ntfs_inode *dir_ni, struct ntfs_inode *new_dir_ni, err = ni_add_name(new_dir_ni, ni, new_de); if (!err) { err = ni_remove_name(dir_ni, ni, de, &de2, &undo); - if (err && ni_remove_name(new_dir_ni, ni, new_de, &de2, &undo)) - *is_bad = true; + WARN_ON(err && ni_remove_name(new_dir_ni, ni, new_de, &de2, + &undo)); } /* diff --git a/fs/ntfs3/namei.c b/fs/ntfs3/namei.c index 50d6d9fbcf67..18330d982b07 100644 --- a/fs/ntfs3/namei.c +++ b/fs/ntfs3/namei.c @@ -240,7 +240,7 @@ static int ntfs_rename(struct inode *dir, struct ntfs_inode *ni = ntfs_i(inode); struct inode *new_inode = d_inode(new_dentry); struct NTFS_DE *de, *new_de; - bool is_same, is_bad; + bool is_same; /* * de - memory of PATH_MAX bytes: * [0-1024) - original name (dentry->d_name) @@ -304,14 +304,8 @@ static int ntfs_rename(struct inode *dir, ni_lock_dir(dir_ni); ni_lock(ni); - is_bad = false; - err = ni_rename(dir_ni, new_dir_ni, ni, de, new_de, &is_bad); - if (is_bad) { - /* Restore after failed rename failed too. */ - make_bad_inode(inode); - ntfs_inode_err(inode, "failed to undo rename"); - ntfs_set_state(sbi, NTFS_DIRTY_ERROR); - } else if (!err) { + err = ni_rename(dir_ni, new_dir_ni, ni, de, new_de); + if (!err) { inode->i_ctime = dir->i_ctime = dir->i_mtime = current_time(dir); mark_inode_dirty(inode); diff --git a/fs/ntfs3/ntfs_fs.h b/fs/ntfs3/ntfs_fs.h index 5d13c47a257c..2ff7719d4bd4 100644 --- a/fs/ntfs3/ntfs_fs.h +++ b/fs/ntfs3/ntfs_fs.h @@ -569,8 +569,7 @@ int ni_add_name(struct ntfs_inode *dir_ni, struct ntfs_inode *ni, struct NTFS_DE *de); int ni_rename(struct ntfs_inode *dir_ni, struct ntfs_inode *new_dir_ni, - struct ntfs_inode *ni, struct NTFS_DE *de, struct NTFS_DE *new_de, - bool *is_bad); + struct ntfs_inode *ni, struct NTFS_DE *de, struct NTFS_DE *new_de); bool ni_is_dirty(struct inode *inode); -- Gitee