From 07ba053021c154ce6af046b0bb9bfad68c393c2a Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Mon, 1 Jun 2020 16:04:13 -0700 Subject: [PATCH] scoutfs: check super blkno fields We had a bug where mkfs would set a free data blkno allocator bit past the end of the device. (Just at it, in fact. Those fenceposts.) Add some checks at mount to make sure that the allocator blkno ranges in the super don't have obvious mistakes. Signed-off-by: Zach Brown --- kmod/src/super.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/kmod/src/super.c b/kmod/src/super.c index dc3ff01b..efc7f1f7 100644 --- a/kmod/src/super.c +++ b/kmod/src/super.c @@ -242,6 +242,7 @@ int scoutfs_read_super(struct super_block *sb, { struct scoutfs_super_block *super; __le32 calc; + u64 blkno; int ret; super = kmalloc(sizeof(struct scoutfs_super_block), GFP_NOFS); @@ -294,6 +295,51 @@ int scoutfs_read_super(struct super_block *sb, goto out; } + blkno = (SCOUTFS_QUORUM_BLKNO + SCOUTFS_QUORUM_BLOCKS) >> + SCOUTFS_BLOCK_SM_LG_SHIFT; + if (le64_to_cpu(super->first_meta_blkno) < blkno) { + scoutfs_err(sb, "super block first meta blkno %llu is within quorum blocks", + le64_to_cpu(super->first_meta_blkno)); + ret = -EINVAL; + goto out; + } + + if (le64_to_cpu(super->first_meta_blkno) > + le64_to_cpu(super->last_meta_blkno)) { + scoutfs_err(sb, "super block first meta blkno %llu is greater than last meta blkno %llu", + le64_to_cpu(super->first_meta_blkno), + le64_to_cpu(super->last_meta_blkno)); + ret = -EINVAL; + goto out; + } + + blkno = (le64_to_cpu(super->last_meta_blkno) + 1) << + SCOUTFS_BLOCK_SM_LG_SHIFT; + if (le64_to_cpu(super->first_data_blkno) < blkno) { + scoutfs_err(sb, "super block first data blkno %llu is within last meta blkno %llu", + le64_to_cpu(super->first_data_blkno), blkno); + ret = -EINVAL; + goto out; + } + + if (le64_to_cpu(super->first_data_blkno) > + le64_to_cpu(super->last_data_blkno)) { + scoutfs_err(sb, "super block first data blkno %llu is greater than last data blkno %llu", + le64_to_cpu(super->first_data_blkno), + le64_to_cpu(super->last_data_blkno)); + ret = -EINVAL; + goto out; + } + + blkno = (i_size_read(sb->s_bdev->bd_inode) >> + SCOUTFS_BLOCK_SM_SHIFT) - 1; + if (le64_to_cpu(super->last_data_blkno) > blkno) { + scoutfs_err(sb, "super block last data blkno %llu is outsite device size last blkno %llu", + le64_to_cpu(super->last_data_blkno), blkno); + ret = -EINVAL; + goto out; + } + *super_res = *super; ret = 0; out: