Commit fd5d027a authored by Chao Yu's avatar Chao Yu Committed by Baokun Li
Browse files

f2fs: compress: fix to cover {reserve,release}_compress_blocks() w/ cp_rwsem lock

stable inclusion
from stable-v5.10.219
commit a6e1f7744e9b84f86a629a76024bba8468aa153b
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IA7YN0
CVE: CVE-2024-34027

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=a6e1f7744e9b84f86a629a76024bba8468aa153b



--------------------------------

[ Upstream commit 0a4ed2d97cb6d044196cc3e726b6699222b41019 ]

It needs to cover {reserve,release}_compress_blocks() w/ cp_rwsem lock
to avoid racing with checkpoint, otherwise, filesystem metadata including
blkaddr in dnode, inode fields and .total_valid_block_count may be
corrupted after SPO case.

Fixes: ef8d563f ("f2fs: introduce F2FS_IOC_RELEASE_COMPRESS_BLOCKS")
Fixes: c75488fb ("f2fs: introduce F2FS_IOC_RESERVE_COMPRESS_BLOCKS")
Signed-off-by: default avatarChao Yu <chao@kernel.org>
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
Signed-off-by: default avatarBaokun Li <libaokun1@huawei.com>
parent 451734a9
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -3579,9 +3579,12 @@ static int f2fs_release_compress_blocks(struct file *filp, unsigned long arg)
		struct dnode_of_data dn;
		pgoff_t end_offset, count;

		f2fs_lock_op(sbi);

		set_new_dnode(&dn, inode, NULL, NULL, 0);
		ret = f2fs_get_dnode_of_data(&dn, page_idx, LOOKUP_NODE);
		if (ret) {
			f2fs_unlock_op(sbi);
			if (ret == -ENOENT) {
				page_idx = f2fs_get_next_page_offset(&dn,
								page_idx);
@@ -3599,6 +3602,8 @@ static int f2fs_release_compress_blocks(struct file *filp, unsigned long arg)

		f2fs_put_dnode(&dn);

		f2fs_unlock_op(sbi);

		if (ret < 0)
			break;

@@ -3732,9 +3737,12 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg)
		struct dnode_of_data dn;
		pgoff_t end_offset, count;

		f2fs_lock_op(sbi);

		set_new_dnode(&dn, inode, NULL, NULL, 0);
		ret = f2fs_get_dnode_of_data(&dn, page_idx, LOOKUP_NODE);
		if (ret) {
			f2fs_unlock_op(sbi);
			if (ret == -ENOENT) {
				page_idx = f2fs_get_next_page_offset(&dn,
								page_idx);
@@ -3752,6 +3760,8 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg)

		f2fs_put_dnode(&dn);

		f2fs_unlock_op(sbi);

		if (ret < 0)
			break;