All of lore.kernel.org
 help / color / mirror / Atom feed
From: Chao Yu <chao@kernel.org>
To: jaegeuk@kernel.org
Cc: linux-kernel@vger.kernel.org, linux-f2fs-devel@lists.sourceforge.net
Subject: [f2fs-dev] [PATCH] f2fs: fix potential .flags overflow on 32bit architecture
Date: Sun, 22 Mar 2020 18:13:27 +0800	[thread overview]
Message-ID: <20200322101327.5979-1-chao@kernel.org> (raw)

From: Chao Yu <yuchao0@huawei.com>

f2fs_inode_info.flags is unsigned long variable, it has 32 bits
in 32bit architecture, since we introduced FI_MMAP_FILE flag
when we support data compression, we may access memory cross
the border of .flags field, corrupting .i_sem field, result in
below deadlock.

To fix this issue, let's introduce .extra_flags to grab extra
space to store those new flags.

Call Trace:
 __schedule+0x8d0/0x13fc
 ? mark_held_locks+0xac/0x100
 schedule+0xcc/0x260
 rwsem_down_write_slowpath+0x3ab/0x65d
 down_write+0xc7/0xe0
 f2fs_drop_nlink+0x3d/0x600 [f2fs]
 f2fs_delete_inline_entry+0x300/0x440 [f2fs]
 f2fs_delete_entry+0x3a1/0x7f0 [f2fs]
 f2fs_unlink+0x500/0x790 [f2fs]
 vfs_unlink+0x211/0x490
 do_unlinkat+0x483/0x520
 sys_unlink+0x4a/0x70
 do_fast_syscall_32+0x12b/0x683
 entry_SYSENTER_32+0xaa/0x102

Fixes: 4c8ff7095bef ("f2fs: support data compression")
Signed-off-by: Chao Yu <yuchao0@huawei.com>
---
 fs/f2fs/f2fs.h  | 26 ++++++++++++++++++++------
 fs/f2fs/inode.c |  1 +
 2 files changed, 21 insertions(+), 6 deletions(-)

diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index fcafa68212eb..fcd22df2e9ca 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -695,6 +695,7 @@ struct f2fs_inode_info {
 
 	/* Use below internally in f2fs*/
 	unsigned long flags;		/* use to pass per-file flags */
+	unsigned long extra_flags;	/* extra flags */
 	struct rw_semaphore i_sem;	/* protect fi info */
 	atomic_t dirty_pages;		/* # of dirty pages */
 	f2fs_hash_t chash;		/* hash value of given file name */
@@ -2569,7 +2570,7 @@ enum {
 };
 
 static inline void __mark_inode_dirty_flag(struct inode *inode,
-						int flag, bool set)
+					unsigned long long flag, bool set)
 {
 	switch (flag) {
 	case FI_INLINE_XATTR:
@@ -2588,20 +2589,33 @@ static inline void __mark_inode_dirty_flag(struct inode *inode,
 
 static inline void set_inode_flag(struct inode *inode, int flag)
 {
-	if (!test_bit(flag, &F2FS_I(inode)->flags))
-		set_bit(flag, &F2FS_I(inode)->flags);
+	if ((1 << flag) <= sizeof(unsigned long)) {
+		if (!test_bit(flag, &F2FS_I(inode)->flags))
+			set_bit(flag, &F2FS_I(inode)->flags);
+	} else {
+		if (!test_bit(flag - 32, &F2FS_I(inode)->extra_flags))
+			set_bit(flag - 32, &F2FS_I(inode)->extra_flags);
+	}
 	__mark_inode_dirty_flag(inode, flag, true);
 }
 
 static inline int is_inode_flag_set(struct inode *inode, int flag)
 {
-	return test_bit(flag, &F2FS_I(inode)->flags);
+	if ((1 << flag) <= sizeof(unsigned long))
+		return test_bit(flag, &F2FS_I(inode)->flags);
+	else
+		return test_bit(flag - 32, &F2FS_I(inode)->extra_flags);
 }
 
 static inline void clear_inode_flag(struct inode *inode, int flag)
 {
-	if (test_bit(flag, &F2FS_I(inode)->flags))
-		clear_bit(flag, &F2FS_I(inode)->flags);
+	if ((1 << flag) <= sizeof(unsigned long)) {
+		if (test_bit(flag, &F2FS_I(inode)->flags))
+			clear_bit(flag, &F2FS_I(inode)->flags);
+	} else {
+		if (test_bit(flag - 32, &F2FS_I(inode)->extra_flags))
+			clear_bit(flag - 32, &F2FS_I(inode)->extra_flags);
+	}
 	__mark_inode_dirty_flag(inode, flag, false);
 }
 
diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
index 44e08bf2e2b4..ca924d7e0e30 100644
--- a/fs/f2fs/inode.c
+++ b/fs/f2fs/inode.c
@@ -363,6 +363,7 @@ static int do_read_inode(struct inode *inode)
 	if (S_ISREG(inode->i_mode))
 		fi->i_flags &= ~F2FS_PROJINHERIT_FL;
 	fi->flags = 0;
+	fi->extra_flags = 0;
 	fi->i_advise = ri->i_advise;
 	fi->i_pino = le32_to_cpu(ri->i_pino);
 	fi->i_dir_level = ri->i_dir_level;
-- 
2.22.0



_______________________________________________
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 <yuchao0@huawei.com>
Subject: [PATCH] f2fs: fix potential .flags overflow on 32bit architecture
Date: Sun, 22 Mar 2020 18:13:27 +0800	[thread overview]
Message-ID: <20200322101327.5979-1-chao@kernel.org> (raw)

From: Chao Yu <yuchao0@huawei.com>

f2fs_inode_info.flags is unsigned long variable, it has 32 bits
in 32bit architecture, since we introduced FI_MMAP_FILE flag
when we support data compression, we may access memory cross
the border of .flags field, corrupting .i_sem field, result in
below deadlock.

To fix this issue, let's introduce .extra_flags to grab extra
space to store those new flags.

Call Trace:
 __schedule+0x8d0/0x13fc
 ? mark_held_locks+0xac/0x100
 schedule+0xcc/0x260
 rwsem_down_write_slowpath+0x3ab/0x65d
 down_write+0xc7/0xe0
 f2fs_drop_nlink+0x3d/0x600 [f2fs]
 f2fs_delete_inline_entry+0x300/0x440 [f2fs]
 f2fs_delete_entry+0x3a1/0x7f0 [f2fs]
 f2fs_unlink+0x500/0x790 [f2fs]
 vfs_unlink+0x211/0x490
 do_unlinkat+0x483/0x520
 sys_unlink+0x4a/0x70
 do_fast_syscall_32+0x12b/0x683
 entry_SYSENTER_32+0xaa/0x102

Fixes: 4c8ff7095bef ("f2fs: support data compression")
Signed-off-by: Chao Yu <yuchao0@huawei.com>
---
 fs/f2fs/f2fs.h  | 26 ++++++++++++++++++++------
 fs/f2fs/inode.c |  1 +
 2 files changed, 21 insertions(+), 6 deletions(-)

diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index fcafa68212eb..fcd22df2e9ca 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -695,6 +695,7 @@ struct f2fs_inode_info {
 
 	/* Use below internally in f2fs*/
 	unsigned long flags;		/* use to pass per-file flags */
+	unsigned long extra_flags;	/* extra flags */
 	struct rw_semaphore i_sem;	/* protect fi info */
 	atomic_t dirty_pages;		/* # of dirty pages */
 	f2fs_hash_t chash;		/* hash value of given file name */
@@ -2569,7 +2570,7 @@ enum {
 };
 
 static inline void __mark_inode_dirty_flag(struct inode *inode,
-						int flag, bool set)
+					unsigned long long flag, bool set)
 {
 	switch (flag) {
 	case FI_INLINE_XATTR:
@@ -2588,20 +2589,33 @@ static inline void __mark_inode_dirty_flag(struct inode *inode,
 
 static inline void set_inode_flag(struct inode *inode, int flag)
 {
-	if (!test_bit(flag, &F2FS_I(inode)->flags))
-		set_bit(flag, &F2FS_I(inode)->flags);
+	if ((1 << flag) <= sizeof(unsigned long)) {
+		if (!test_bit(flag, &F2FS_I(inode)->flags))
+			set_bit(flag, &F2FS_I(inode)->flags);
+	} else {
+		if (!test_bit(flag - 32, &F2FS_I(inode)->extra_flags))
+			set_bit(flag - 32, &F2FS_I(inode)->extra_flags);
+	}
 	__mark_inode_dirty_flag(inode, flag, true);
 }
 
 static inline int is_inode_flag_set(struct inode *inode, int flag)
 {
-	return test_bit(flag, &F2FS_I(inode)->flags);
+	if ((1 << flag) <= sizeof(unsigned long))
+		return test_bit(flag, &F2FS_I(inode)->flags);
+	else
+		return test_bit(flag - 32, &F2FS_I(inode)->extra_flags);
 }
 
 static inline void clear_inode_flag(struct inode *inode, int flag)
 {
-	if (test_bit(flag, &F2FS_I(inode)->flags))
-		clear_bit(flag, &F2FS_I(inode)->flags);
+	if ((1 << flag) <= sizeof(unsigned long)) {
+		if (test_bit(flag, &F2FS_I(inode)->flags))
+			clear_bit(flag, &F2FS_I(inode)->flags);
+	} else {
+		if (test_bit(flag - 32, &F2FS_I(inode)->extra_flags))
+			clear_bit(flag - 32, &F2FS_I(inode)->extra_flags);
+	}
 	__mark_inode_dirty_flag(inode, flag, false);
 }
 
diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
index 44e08bf2e2b4..ca924d7e0e30 100644
--- a/fs/f2fs/inode.c
+++ b/fs/f2fs/inode.c
@@ -363,6 +363,7 @@ static int do_read_inode(struct inode *inode)
 	if (S_ISREG(inode->i_mode))
 		fi->i_flags &= ~F2FS_PROJINHERIT_FL;
 	fi->flags = 0;
+	fi->extra_flags = 0;
 	fi->i_advise = ri->i_advise;
 	fi->i_pino = le32_to_cpu(ri->i_pino);
 	fi->i_dir_level = ri->i_dir_level;
-- 
2.22.0


             reply	other threads:[~2020-03-22 10:14 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-03-22 10:13 Chao Yu [this message]
2020-03-22 10:13 ` [PATCH] f2fs: fix potential .flags overflow on 32bit architecture Chao Yu
2020-03-22 12:14 ` [f2fs-dev] " Ondřej Jirman
2020-03-22 12:14   ` Ondřej Jirman
2020-03-22 13:18   ` [f2fs-dev] " Chao Yu
2020-03-22 13:18     ` Chao Yu
2020-03-22 15:30     ` [f2fs-dev] " Ondřej Jirman
2020-03-22 15:30       ` Ondřej Jirman
2020-03-23  1:15       ` [f2fs-dev] " Chao Yu
2020-03-23  1:15         ` 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=20200322101327.5979-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 \
    /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.