Skip to content

Commit 489ec8d

Browse files
fmueller-ionosSasha Levin
authored andcommitted
md/bitmap: Fix bitmap chunk size overflow issues
commit 4555211 upstream. - limit bitmap chunk size internal u64 variable to values not overflowing the u32 bitmap superblock structure variable stored on persistent media - assign bitmap chunk size internal u64 variable from unsigned values to avoid possible sign extension artifacts when assigning from a s32 value The bug has been there since at least kernel 4.0. Steps to reproduce it: 1: mdadm -C /dev/mdx -l 1 --bitmap=internal --bitmap-chunk=256M -e 1.2 -n2 /dev/rnbd1 /dev/rnbd2 2 resize member device rnbd1 and rnbd2 to 8 TB 3 mdadm --grow /dev/mdx --size=max The bitmap_chunksize will overflow without patch. Cc: stable@vger.kernel.org Signed-off-by: Florian-Ewald Mueller <florian-ewald.mueller@ionos.com> Signed-off-by: Jack Wang <jinpu.wang@ionos.com> Signed-off-by: Song Liu <song@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent b771c56 commit 489ec8d

File tree

1 file changed

+12
-8
lines changed

1 file changed

+12
-8
lines changed

drivers/md/md-bitmap.c

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,7 @@ void md_bitmap_print_sb(struct bitmap *bitmap)
486486
sb = kmap_atomic(bitmap->storage.sb_page);
487487
pr_debug("%s: bitmap file superblock:\n", bmname(bitmap));
488488
pr_debug(" magic: %08x\n", le32_to_cpu(sb->magic));
489-
pr_debug(" version: %d\n", le32_to_cpu(sb->version));
489+
pr_debug(" version: %u\n", le32_to_cpu(sb->version));
490490
pr_debug(" uuid: %08x.%08x.%08x.%08x\n",
491491
le32_to_cpu(*(__le32 *)(sb->uuid+0)),
492492
le32_to_cpu(*(__le32 *)(sb->uuid+4)),
@@ -497,11 +497,11 @@ void md_bitmap_print_sb(struct bitmap *bitmap)
497497
pr_debug("events cleared: %llu\n",
498498
(unsigned long long) le64_to_cpu(sb->events_cleared));
499499
pr_debug(" state: %08x\n", le32_to_cpu(sb->state));
500-
pr_debug(" chunksize: %d B\n", le32_to_cpu(sb->chunksize));
501-
pr_debug(" daemon sleep: %ds\n", le32_to_cpu(sb->daemon_sleep));
500+
pr_debug(" chunksize: %u B\n", le32_to_cpu(sb->chunksize));
501+
pr_debug(" daemon sleep: %us\n", le32_to_cpu(sb->daemon_sleep));
502502
pr_debug(" sync size: %llu KB\n",
503503
(unsigned long long)le64_to_cpu(sb->sync_size)/2);
504-
pr_debug("max write behind: %d\n", le32_to_cpu(sb->write_behind));
504+
pr_debug("max write behind: %u\n", le32_to_cpu(sb->write_behind));
505505
kunmap_atomic(sb);
506506
}
507507

@@ -2106,7 +2106,8 @@ int md_bitmap_resize(struct bitmap *bitmap, sector_t blocks,
21062106
bytes = DIV_ROUND_UP(chunks, 8);
21072107
if (!bitmap->mddev->bitmap_info.external)
21082108
bytes += sizeof(bitmap_super_t);
2109-
} while (bytes > (space << 9));
2109+
} while (bytes > (space << 9) && (chunkshift + BITMAP_BLOCK_SHIFT) <
2110+
(BITS_PER_BYTE * sizeof(((bitmap_super_t *)0)->chunksize) - 1));
21102111
} else
21112112
chunkshift = ffz(~chunksize) - BITMAP_BLOCK_SHIFT;
21122113

@@ -2151,7 +2152,7 @@ int md_bitmap_resize(struct bitmap *bitmap, sector_t blocks,
21512152
bitmap->counts.missing_pages = pages;
21522153
bitmap->counts.chunkshift = chunkshift;
21532154
bitmap->counts.chunks = chunks;
2154-
bitmap->mddev->bitmap_info.chunksize = 1 << (chunkshift +
2155+
bitmap->mddev->bitmap_info.chunksize = 1UL << (chunkshift +
21552156
BITMAP_BLOCK_SHIFT);
21562157

21572158
blocks = min(old_counts.chunks << old_counts.chunkshift,
@@ -2177,8 +2178,8 @@ int md_bitmap_resize(struct bitmap *bitmap, sector_t blocks,
21772178
bitmap->counts.missing_pages = old_counts.pages;
21782179
bitmap->counts.chunkshift = old_counts.chunkshift;
21792180
bitmap->counts.chunks = old_counts.chunks;
2180-
bitmap->mddev->bitmap_info.chunksize = 1 << (old_counts.chunkshift +
2181-
BITMAP_BLOCK_SHIFT);
2181+
bitmap->mddev->bitmap_info.chunksize =
2182+
1UL << (old_counts.chunkshift + BITMAP_BLOCK_SHIFT);
21822183
blocks = old_counts.chunks << old_counts.chunkshift;
21832184
pr_warn("Could not pre-allocate in-memory bitmap for cluster raid\n");
21842185
break;
@@ -2519,6 +2520,9 @@ chunksize_store(struct mddev *mddev, const char *buf, size_t len)
25192520
if (csize < 512 ||
25202521
!is_power_of_2(csize))
25212522
return -EINVAL;
2523+
if (BITS_PER_LONG > 32 && csize >= (1ULL << (BITS_PER_BYTE *
2524+
sizeof(((bitmap_super_t *)0)->chunksize))))
2525+
return -EOVERFLOW;
25222526
mddev->bitmap_info.chunksize = csize;
25232527
return len;
25242528
}

0 commit comments

Comments
 (0)