From: Chao Yu <chao@kernel.org>
To: jaegeuk@kernel.org
Cc: linux-kernel@vger.kernel.org, stable@vger.kernel.org,
linux-f2fs-devel@lists.sourceforge.net,
Ming Yan <yanming@tju.edu.cn>
Subject: [f2fs-dev] [PATCH v4] f2fs: fix to do sanity check for inline inode
Date: Tue, 17 May 2022 11:31:20 +0800 [thread overview]
Message-ID: <20220517033120.3564912-1-chao@kernel.org> (raw)
Yanming reported a kernel bug in Bugzilla kernel [1], which can be
reproduced. The bug message is:
The kernel message is shown below:
kernel BUG at fs/inode.c:611!
Call Trace:
evict+0x282/0x4e0
__dentry_kill+0x2b2/0x4d0
dput+0x2dd/0x720
do_renameat2+0x596/0x970
__x64_sys_rename+0x78/0x90
do_syscall_64+0x3b/0x90
[1] https://bugzilla.kernel.org/show_bug.cgi?id=215895
The bug is due to fuzzed inode has both inline_data and encrypted flags.
During f2fs_evict_inode(), as the inode was deleted by rename(), it
will cause inline data conversion due to conflicting flags. The page
cache will be polluted and the panic will be triggered in clear_inode().
Try fixing the bug by doing more sanity checks for inline data inode in
sanity_check_inode().
Cc: stable@vger.kernel.org
Reported-by: Ming Yan <yanming@tju.edu.cn>
Signed-off-by: Chao Yu <chao.yu@oppo.com>
---
v4:
- introduce and use f2fs_post_read_required_ondisk() only for
sanity_check_inode().
fs/f2fs/f2fs.h | 15 ++++++++++++++-
fs/f2fs/file.c | 2 +-
fs/f2fs/inline.c | 11 ++++++++---
fs/f2fs/inode.c | 3 +--
fs/f2fs/namei.c | 2 +-
5 files changed, 25 insertions(+), 8 deletions(-)
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 7faf230f101f..65442ab03d32 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -4039,7 +4039,7 @@ extern struct kmem_cache *f2fs_inode_entry_slab;
/*
* inline.c
*/
-bool f2fs_may_inline_data(struct inode *inode);
+bool f2fs_may_inline_data(struct inode *inode, bool sanity_check);
bool f2fs_may_inline_dentry(struct inode *inode);
void f2fs_do_read_inline_data(struct page *page, struct page *ipage);
void f2fs_truncate_inline_inode(struct inode *inode,
@@ -4141,6 +4141,19 @@ static inline void f2fs_set_encrypted_inode(struct inode *inode)
#endif
}
+static inline bool f2fs_post_read_required_ondisk(struct inode *inode)
+{
+ /*
+ * used by sanity_check_inode(), when disk layout fields has not
+ * been synchronized to inmem fields.
+ */
+ if (S_ISREG(inode->i_mode) && (file_is_encrypt(inode) ||
+ F2FS_I(inode)->i_flags & F2FS_COMPR_FL ||
+ file_is_verity(inode)))
+ return true;
+
+ return false;
+}
/*
* Returns true if the reads of the inode's data need to undergo some
* postprocessing step, like decryption or authenticity verification.
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 0a554730d2c4..73ba1c6dceaa 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -796,7 +796,7 @@ int f2fs_truncate(struct inode *inode)
return err;
/* we should check inline_data size */
- if (!f2fs_may_inline_data(inode)) {
+ if (!f2fs_may_inline_data(inode, false)) {
err = f2fs_convert_inline_inode(inode);
if (err)
return err;
diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c
index a578bf83b803..331ecd8af80c 100644
--- a/fs/f2fs/inline.c
+++ b/fs/f2fs/inline.c
@@ -14,7 +14,7 @@
#include "node.h"
#include <trace/events/f2fs.h>
-bool f2fs_may_inline_data(struct inode *inode)
+bool f2fs_may_inline_data(struct inode *inode, bool sanity_check)
{
if (f2fs_is_atomic_file(inode))
return false;
@@ -25,8 +25,13 @@ bool f2fs_may_inline_data(struct inode *inode)
if (i_size_read(inode) > MAX_INLINE_DATA(inode))
return false;
- if (f2fs_post_read_required(inode))
- return false;
+ if (sanity_check) {
+ if (f2fs_post_read_required_ondisk(inode))
+ return false;
+ } else {
+ if (f2fs_post_read_required(inode))
+ return false;
+ }
return true;
}
diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
index 2fce8fa0dac8..3384100dde0b 100644
--- a/fs/f2fs/inode.c
+++ b/fs/f2fs/inode.c
@@ -276,8 +276,7 @@ static bool sanity_check_inode(struct inode *inode, struct page *node_page)
}
}
- if (f2fs_has_inline_data(inode) &&
- (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode))) {
+ if (f2fs_has_inline_data(inode) && !f2fs_may_inline_data(inode, true)) {
set_sbi_flag(sbi, SBI_NEED_FSCK);
f2fs_warn(sbi, "%s: inode (ino=%lx, mode=%u) should not have inline_data, run fsck to fix",
__func__, inode->i_ino, inode->i_mode);
diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
index c549acb52ac4..514088f707ed 100644
--- a/fs/f2fs/namei.c
+++ b/fs/f2fs/namei.c
@@ -89,7 +89,7 @@ static struct inode *f2fs_new_inode(struct user_namespace *mnt_userns,
if (test_opt(sbi, INLINE_XATTR))
set_inode_flag(inode, FI_INLINE_XATTR);
- if (test_opt(sbi, INLINE_DATA) && f2fs_may_inline_data(inode))
+ if (test_opt(sbi, INLINE_DATA) && f2fs_may_inline_data(inode, false))
set_inode_flag(inode, FI_INLINE_DATA);
if (f2fs_may_inline_dentry(inode))
set_inode_flag(inode, FI_INLINE_DENTRY);
--
2.25.1
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
WARNING: multiple messages have this Message-ID (diff)
From: Chao Yu <chao@kernel.org>
To: jaegeuk@kernel.org
Cc: linux-f2fs-devel@lists.sourceforge.net,
linux-kernel@vger.kernel.org, Chao Yu <chao@kernel.org>,
stable@vger.kernel.org, Ming Yan <yanming@tju.edu.cn>,
Chao Yu <chao.yu@oppo.com>
Subject: [PATCH v4] f2fs: fix to do sanity check for inline inode
Date: Tue, 17 May 2022 11:31:20 +0800 [thread overview]
Message-ID: <20220517033120.3564912-1-chao@kernel.org> (raw)
Yanming reported a kernel bug in Bugzilla kernel [1], which can be
reproduced. The bug message is:
The kernel message is shown below:
kernel BUG at fs/inode.c:611!
Call Trace:
evict+0x282/0x4e0
__dentry_kill+0x2b2/0x4d0
dput+0x2dd/0x720
do_renameat2+0x596/0x970
__x64_sys_rename+0x78/0x90
do_syscall_64+0x3b/0x90
[1] https://bugzilla.kernel.org/show_bug.cgi?id=215895
The bug is due to fuzzed inode has both inline_data and encrypted flags.
During f2fs_evict_inode(), as the inode was deleted by rename(), it
will cause inline data conversion due to conflicting flags. The page
cache will be polluted and the panic will be triggered in clear_inode().
Try fixing the bug by doing more sanity checks for inline data inode in
sanity_check_inode().
Cc: stable@vger.kernel.org
Reported-by: Ming Yan <yanming@tju.edu.cn>
Signed-off-by: Chao Yu <chao.yu@oppo.com>
---
v4:
- introduce and use f2fs_post_read_required_ondisk() only for
sanity_check_inode().
fs/f2fs/f2fs.h | 15 ++++++++++++++-
fs/f2fs/file.c | 2 +-
fs/f2fs/inline.c | 11 ++++++++---
fs/f2fs/inode.c | 3 +--
fs/f2fs/namei.c | 2 +-
5 files changed, 25 insertions(+), 8 deletions(-)
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 7faf230f101f..65442ab03d32 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -4039,7 +4039,7 @@ extern struct kmem_cache *f2fs_inode_entry_slab;
/*
* inline.c
*/
-bool f2fs_may_inline_data(struct inode *inode);
+bool f2fs_may_inline_data(struct inode *inode, bool sanity_check);
bool f2fs_may_inline_dentry(struct inode *inode);
void f2fs_do_read_inline_data(struct page *page, struct page *ipage);
void f2fs_truncate_inline_inode(struct inode *inode,
@@ -4141,6 +4141,19 @@ static inline void f2fs_set_encrypted_inode(struct inode *inode)
#endif
}
+static inline bool f2fs_post_read_required_ondisk(struct inode *inode)
+{
+ /*
+ * used by sanity_check_inode(), when disk layout fields has not
+ * been synchronized to inmem fields.
+ */
+ if (S_ISREG(inode->i_mode) && (file_is_encrypt(inode) ||
+ F2FS_I(inode)->i_flags & F2FS_COMPR_FL ||
+ file_is_verity(inode)))
+ return true;
+
+ return false;
+}
/*
* Returns true if the reads of the inode's data need to undergo some
* postprocessing step, like decryption or authenticity verification.
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 0a554730d2c4..73ba1c6dceaa 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -796,7 +796,7 @@ int f2fs_truncate(struct inode *inode)
return err;
/* we should check inline_data size */
- if (!f2fs_may_inline_data(inode)) {
+ if (!f2fs_may_inline_data(inode, false)) {
err = f2fs_convert_inline_inode(inode);
if (err)
return err;
diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c
index a578bf83b803..331ecd8af80c 100644
--- a/fs/f2fs/inline.c
+++ b/fs/f2fs/inline.c
@@ -14,7 +14,7 @@
#include "node.h"
#include <trace/events/f2fs.h>
-bool f2fs_may_inline_data(struct inode *inode)
+bool f2fs_may_inline_data(struct inode *inode, bool sanity_check)
{
if (f2fs_is_atomic_file(inode))
return false;
@@ -25,8 +25,13 @@ bool f2fs_may_inline_data(struct inode *inode)
if (i_size_read(inode) > MAX_INLINE_DATA(inode))
return false;
- if (f2fs_post_read_required(inode))
- return false;
+ if (sanity_check) {
+ if (f2fs_post_read_required_ondisk(inode))
+ return false;
+ } else {
+ if (f2fs_post_read_required(inode))
+ return false;
+ }
return true;
}
diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
index 2fce8fa0dac8..3384100dde0b 100644
--- a/fs/f2fs/inode.c
+++ b/fs/f2fs/inode.c
@@ -276,8 +276,7 @@ static bool sanity_check_inode(struct inode *inode, struct page *node_page)
}
}
- if (f2fs_has_inline_data(inode) &&
- (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode))) {
+ if (f2fs_has_inline_data(inode) && !f2fs_may_inline_data(inode, true)) {
set_sbi_flag(sbi, SBI_NEED_FSCK);
f2fs_warn(sbi, "%s: inode (ino=%lx, mode=%u) should not have inline_data, run fsck to fix",
__func__, inode->i_ino, inode->i_mode);
diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
index c549acb52ac4..514088f707ed 100644
--- a/fs/f2fs/namei.c
+++ b/fs/f2fs/namei.c
@@ -89,7 +89,7 @@ static struct inode *f2fs_new_inode(struct user_namespace *mnt_userns,
if (test_opt(sbi, INLINE_XATTR))
set_inode_flag(inode, FI_INLINE_XATTR);
- if (test_opt(sbi, INLINE_DATA) && f2fs_may_inline_data(inode))
+ if (test_opt(sbi, INLINE_DATA) && f2fs_may_inline_data(inode, false))
set_inode_flag(inode, FI_INLINE_DATA);
if (f2fs_may_inline_dentry(inode))
set_inode_flag(inode, FI_INLINE_DENTRY);
--
2.25.1
next reply other threads:[~2022-05-17 3:31 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-05-17 3:31 Chao Yu [this message]
2022-05-17 3:31 ` [PATCH v4] f2fs: fix to do sanity check for inline inode Chao Yu
2022-05-17 18:18 ` [f2fs-dev] " Jaegeuk Kim
2022-05-17 18:18 ` Jaegeuk Kim
2022-05-18 12:29 ` [f2fs-dev] " Chao Yu
2022-05-18 12:29 ` Chao Yu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220517033120.3564912-1-chao@kernel.org \
--to=chao@kernel.org \
--cc=jaegeuk@kernel.org \
--cc=linux-f2fs-devel@lists.sourceforge.net \
--cc=linux-kernel@vger.kernel.org \
--cc=stable@vger.kernel.org \
--cc=yanming@tju.edu.cn \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.