nilfs2: fix potential oob read in nilfs_btree_check_delete()

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: 17c76b0104 ("nilfs2: B-tree based block mapping")
Signed-off-by: Ryusuke Konishi <konishi.ryusuke@gmail.com>
Cc: Lizhi Xu <lizhi.xu@windriver.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
Ryusuke Konishi 2024-09-04 17:13:09 +09:00 committed by Andrew Morton
parent 111b812d36
commit f9c96351aa

View file

@ -1659,13 +1659,16 @@ static int nilfs_btree_check_delete(struct nilfs_bmap *btree, __u64 key)
int nchildren, ret; int nchildren, ret;
root = nilfs_btree_get_root(btree); root = nilfs_btree_get_root(btree);
nchildren = nilfs_btree_node_get_nchildren(root);
if (unlikely(nchildren == 0))
return 0;
switch (nilfs_btree_height(btree)) { switch (nilfs_btree_height(btree)) {
case 2: case 2:
bh = NULL; bh = NULL;
node = root; node = root;
break; break;
case 3: case 3:
nchildren = nilfs_btree_node_get_nchildren(root);
if (nchildren > 1) if (nchildren > 1)
return 0; return 0;
ptr = nilfs_btree_node_get_ptr(root, nchildren - 1, 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) if (ret < 0)
return ret; return ret;
node = (struct nilfs_btree_node *)bh->b_data; node = (struct nilfs_btree_node *)bh->b_data;
nchildren = nilfs_btree_node_get_nchildren(node);
break; break;
default: default:
return 0; return 0;
} }
nchildren = nilfs_btree_node_get_nchildren(node);
maxkey = nilfs_btree_node_get_key(node, nchildren - 1); maxkey = nilfs_btree_node_get_key(node, nchildren - 1);
nextmaxkey = (nchildren > 1) ? nextmaxkey = (nchildren > 1) ?
nilfs_btree_node_get_key(node, nchildren - 2) : 0; nilfs_btree_node_get_key(node, nchildren - 2) : 0;