diff mbox series

btrfs-progs: convert: Properly work with large ext4 filesystems

Message ID 20220607102421.170419-1-nborisov@suse.com (mailing list archive)
State New, archived
Headers show
Series btrfs-progs: convert: Properly work with large ext4 filesystems | expand

Commit Message

Nikolay Borisov June 7, 2022, 10:24 a.m. UTC
On large (blockcount > 32bit) filesystems reading directly
super_block->s_blocks_count is not sufficient as the block count is held
in 2 separate 32 bit variables. Instead always use the provided
ext2fs_blocks_count to read the value. This can result in assertion
failure, when the block count is only held in the high 32 bits, in this
case s_block_counts would be zero, which would result in
btrfs_convert_context::block_count/total_bytes to also be 0 and hit an
assertion failure:

    convert/main.c:1162: do_convert: Assertion `cctx.total_bytes != 0` failed, value 0
    btrfs-convert(+0xffb0)[0x557defdabfb0]
    btrfs-convert(main+0x6c5)[0x557defdaa125]
    /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xea)[0x7f66e1f8bd0a]
    btrfs-convert(_start+0x2a)[0x557defdab52a]
    Aborted

What's worse it can also result in btrfs-conver mistakenly thinking that
a filesystem is smaller than it actually is (ignoring the top 32 bits).

Link: https://lore.kernel.org/linux-btrfs/023b5ca9-0610-231b-fc4e-a72fe1377a5a@jansson.tech/
Signed-off-by: Nikolay Borisov <nborisov@suse.com>
---
 convert/main.c        | 4 +---
 convert/source-ext2.c | 4 ++--
 2 files changed, 3 insertions(+), 5 deletions(-)

--
2.17.1

Comments

David Sterba July 18, 2022, 3:20 p.m. UTC | #1
On Tue, Jun 07, 2022 at 01:24:21PM +0300, Nikolay Borisov wrote:
> On large (blockcount > 32bit) filesystems reading directly
> super_block->s_blocks_count is not sufficient as the block count is held
> in 2 separate 32 bit variables. Instead always use the provided
> ext2fs_blocks_count to read the value. This can result in assertion
> failure, when the block count is only held in the high 32 bits, in this
> case s_block_counts would be zero, which would result in
> btrfs_convert_context::block_count/total_bytes to also be 0 and hit an
> assertion failure:
> 
>     convert/main.c:1162: do_convert: Assertion `cctx.total_bytes != 0` failed, value 0
>     btrfs-convert(+0xffb0)[0x557defdabfb0]
>     btrfs-convert(main+0x6c5)[0x557defdaa125]
>     /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xea)[0x7f66e1f8bd0a]
>     btrfs-convert(_start+0x2a)[0x557defdab52a]
>     Aborted
> 
> What's worse it can also result in btrfs-conver mistakenly thinking that
> a filesystem is smaller than it actually is (ignoring the top 32 bits).
> 
> Link: https://lore.kernel.org/linux-btrfs/023b5ca9-0610-231b-fc4e-a72fe1377a5a@jansson.tech/
> Signed-off-by: Nikolay Borisov <nborisov@suse.com>

Added to devel, thanks.
diff mbox series

Patch

diff --git a/convert/main.c b/convert/main.c
index 73f919d25255..92ebb1acd181 100644
--- a/convert/main.c
+++ b/convert/main.c
@@ -1134,7 +1134,6 @@  static int do_convert(const char *devname, u32 convert_flags, u32 nodesize,
 	int ret;
 	int fd = -1;
 	u32 blocksize;
-	u64 total_bytes;
 	struct btrfs_root *root;
 	struct btrfs_root *image_root;
 	struct btrfs_convert_context cctx;
@@ -1161,7 +1160,6 @@  static int do_convert(const char *devname, u32 convert_flags, u32 nodesize,

 	ASSERT(cctx.total_bytes != 0);
 	blocksize = cctx.blocksize;
-	total_bytes = (u64)blocksize * (u64)cctx.block_count;
 	if (blocksize < 4096) {
 		error("block size is too small: %u < 4096", blocksize);
 		goto fail;
@@ -1223,7 +1221,7 @@  static int do_convert(const char *devname, u32 convert_flags, u32 nodesize,

 	mkfs_cfg.csum_type = csum_type;
 	mkfs_cfg.label = cctx.label;
-	mkfs_cfg.num_bytes = total_bytes;
+	mkfs_cfg.num_bytes = cctx.total_bytes;
 	mkfs_cfg.nodesize = nodesize;
 	mkfs_cfg.sectorsize = blocksize;
 	mkfs_cfg.stripesize = blocksize;
diff --git a/convert/source-ext2.c b/convert/source-ext2.c
index 9fad4c50e244..610db16b81aa 100644
--- a/convert/source-ext2.c
+++ b/convert/source-ext2.c
@@ -92,8 +92,8 @@  static int ext2_open_fs(struct btrfs_convert_context *cctx, const char *name)

 	cctx->fs_data = ext2_fs;
 	cctx->blocksize = ext2_fs->blocksize;
-	cctx->block_count = ext2_fs->super->s_blocks_count;
-	cctx->total_bytes = (u64)ext2_fs->super->s_blocks_count * ext2_fs->blocksize;
+	cctx->block_count = ext2fs_blocks_count(ext2_fs->super);
+	cctx->total_bytes = cctx->block_count * cctx->blocksize;
 	cctx->label = strndup((char *)ext2_fs->super->s_volume_name, 16);
 	cctx->first_data_block = ext2_fs->super->s_first_data_block;
 	cctx->inodes_count = ext2_fs->super->s_inodes_count;