]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
nilfs2: fix potential oob read in nilfs_btree_check_delete()
authorRyusuke Konishi <konishi.ryusuke@gmail.com>
Wed, 4 Sep 2024 08:13:09 +0000 (17:13 +0900)
committerAndrew Morton <akpm@linux-foundation.org>
Mon, 9 Sep 2024 23:47:42 +0000 (16:47 -0700)
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: 17c76b0104e4 ("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>
fs/nilfs2/btree.c

index dedd3c48084230b51697e1542fbc0362166871dd..ef5061bb56da1ec2a190376efd00dbc8856118ca 100644 (file)
@@ -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;