Commit 7341e9a5 authored by Ryusuke Konishi's avatar Ryusuke Konishi Committed by Long Li
Browse files

nilfs2: fix potential oob read in nilfs_btree_check_delete()

stable inclusion
from stable-v6.6.53
commit 257f9e5185eb6de83377caea686c306e22e871f2
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IAYQRO
CVE: CVE-2024-47757

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=tags/v6.6.54&id=257f9e5185eb6de83377caea686c306e22e871f2

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

[ Upstream commit f9c96351aa6718b42a9f42eaf7adce0356bdb5e8 ]

The function nilfs_btree_check_delete(), which checks whether degeneration
to direct mapping occurs before deleting a b-tree entry, causes memory
access outside the block buffer when retrieving the maximum key if the
root node has no entries.

This does not usually happen because b-tree mappings with 0 child nodes
are never created by mkfs.nilfs2 or nilfs2 itself.  However, it can happen
if the b-tree root node read from a device is configured that way, so fix
this potential issue by adding a check for that case.

Link: https://lkml.kernel.org/r/20240904081401.16682-4-konishi.ryusuke@gmail.com


Fixes: 17c76b01 ("nilfs2: B-tree based block mapping")
Signed-off-by: default avatarRyusuke Konishi <konishi.ryusuke@gmail.com>
Cc: Lizhi Xu <lizhi.xu@windriver.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
Signed-off-by: default avatarLong Li <leo.lilong@huawei.com>
parent 5028521f
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -1659,13 +1659,16 @@ static int nilfs_btree_check_delete(struct nilfs_bmap *btree, __u64 key)
	int nchildren, ret;

	root = nilfs_btree_get_root(btree);
	nchildren = nilfs_btree_node_get_nchildren(root);
	if (unlikely(nchildren == 0))
		return 0;

	switch (nilfs_btree_height(btree)) {
	case 2:
		bh = NULL;
		node = root;
		break;
	case 3:
		nchildren = nilfs_btree_node_get_nchildren(root);
		if (nchildren > 1)
			return 0;
		ptr = nilfs_btree_node_get_ptr(root, nchildren - 1,
@@ -1674,12 +1677,12 @@ static int nilfs_btree_check_delete(struct nilfs_bmap *btree, __u64 key)
		if (ret < 0)
			return ret;
		node = (struct nilfs_btree_node *)bh->b_data;
		nchildren = nilfs_btree_node_get_nchildren(node);
		break;
	default:
		return 0;
	}

	nchildren = nilfs_btree_node_get_nchildren(node);
	maxkey = nilfs_btree_node_get_key(node, nchildren - 1);
	nextmaxkey = (nchildren > 1) ?
		nilfs_btree_node_get_key(node, nchildren - 2) : 0;