]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
btrfs: tree-checker: validate number of chunk stripes and parity
authorDaniel Xu <dxu@dxuuu.xyz>
Fri, 9 Oct 2020 01:09:10 +0000 (18:09 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 5 Nov 2020 10:43:27 +0000 (11:43 +0100)
commit 85d07fbe09efd1c529ff3e025e2f0d2c6c96a1b7 upstream.

If there's no parity and num_stripes < ncopies, a crafted image can
trigger a division by zero in calc_stripe_length().

The image was generated through fuzzing.

CC: stable@vger.kernel.org # 5.4+
Reviewed-by: Qu Wenruo <wqu@suse.com>
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=209587
Signed-off-by: Daniel Xu <dxu@dxuuu.xyz>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/btrfs/tree-checker.c

index e79f9cb6f691f42e70edba5d64b3d123bbbfd159..48e46323d519cccb78090bcfabe14c3b214c9544 100644 (file)
@@ -577,18 +577,36 @@ int btrfs_check_chunk_valid(struct extent_buffer *leaf,
        u64 type;
        u64 features;
        bool mixed = false;
+       int raid_index;
+       int nparity;
+       int ncopies;
 
        length = btrfs_chunk_length(leaf, chunk);
        stripe_len = btrfs_chunk_stripe_len(leaf, chunk);
        num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
        sub_stripes = btrfs_chunk_sub_stripes(leaf, chunk);
        type = btrfs_chunk_type(leaf, chunk);
+       raid_index = btrfs_bg_flags_to_raid_index(type);
+       ncopies = btrfs_raid_array[raid_index].ncopies;
+       nparity = btrfs_raid_array[raid_index].nparity;
 
        if (!num_stripes) {
                chunk_err(leaf, chunk, logical,
                          "invalid chunk num_stripes, have %u", num_stripes);
                return -EUCLEAN;
        }
+       if (num_stripes < ncopies) {
+               chunk_err(leaf, chunk, logical,
+                         "invalid chunk num_stripes < ncopies, have %u < %d",
+                         num_stripes, ncopies);
+               return -EUCLEAN;
+       }
+       if (nparity && num_stripes == nparity) {
+               chunk_err(leaf, chunk, logical,
+                         "invalid chunk num_stripes == nparity, have %u == %d",
+                         num_stripes, nparity);
+               return -EUCLEAN;
+       }
        if (!IS_ALIGNED(logical, fs_info->sectorsize)) {
                chunk_err(leaf, chunk, logical,
                "invalid chunk logical, have %llu should aligned to %u",