@@ -126,4 +126,28 @@ int delete_corrupted_dir_item(struct btrfs_trans_handle *trans,
struct btrfs_key *di_key, char *namebuf,
u32 namelen);
+/*
+ * Check if the inode mode @imode is valid
+ *
+ * This check focuses on S_FTMT bits and unused bits.
+ * Sticky/setuid/setgid and regular owner/group/other bits won't cause
+ * any problem.
+ */
+static inline bool is_valid_imode(u32 imode)
+{
+ if (imode & ~(S_IFMT | 07777))
+ return false;
+
+ /*
+ * S_IFMT is not bitmap, nor pure numbering sequence. Need per valid
+ * number check.
+ */
+ imode &= S_IFMT;
+ if (imode != S_IFDIR && imode != S_IFCHR && imode != S_IFBLK &&
+ imode != S_IFREG && imode != S_IFIFO && imode != S_IFLNK &&
+ imode != S_IFSOCK)
+ return false;
+ return true;
+}
+
#endif
@@ -2452,6 +2452,11 @@ static int check_inode_item(struct btrfs_root *root, struct btrfs_path *path)
nlink = btrfs_inode_nlink(node, ii);
nodatasum = btrfs_inode_flags(node, ii) & BTRFS_INODE_NODATASUM;
+ if (!is_valid_imode(mode)) {
+ error("invalid imode mode bits: 0%o", mode);
+ err |= INODE_MODE_ERROR;
+ }
+
if (S_ISLNK(mode) &&
flags & (BTRFS_INODE_IMMUTABLE | BTRFS_INODE_APPEND)) {
err |= INODE_FLAGS_ERROR;
@@ -46,6 +46,7 @@
#define FATAL_ERROR (1<<22) /* Fatal bit for errno */
#define INODE_FLAGS_ERROR (1<<23) /* Invalid inode flags */
#define DIR_ITEM_HASH_MISMATCH (1<<24) /* Dir item hash mismatch */
+#define INODE_MODE_ERROR (1<<25) /* Bad inode mode */
/*
* Error bit for low memory mode check.
There is one report about invalid free space cache inode mode. Normally free space cache inode should have mode 100600 (regular file, no uid/gid/sticky bit, rw------ bit). But in that report, we have free space cache inode mode as 0. So at least btrfs check should report invalid inode mode. This patch will at least make btrfs check lowmem mode to detect this problem. Please note that, this check only applies to inodes in fs/subvol trees. It doesn't apply to free space cache inodes. Reported-by: Thorsten Hirsch <t.hirsch@web.de> Signed-off-by: Qu Wenruo <wqu@suse.com> --- check/mode-common.h | 24 ++++++++++++++++++++++++ check/mode-lowmem.c | 5 +++++ check/mode-lowmem.h | 1 + 3 files changed, 30 insertions(+)