Skip to content

Commit c926093

Browse files
kdavemasoncl
authored andcommitted
btrfs: add more superblock checks
Populate btrfs_check_super_valid() with checks that try to verify consistency of superblock by additional conditions that may arise from corrupted devices or bitflips. Some of tests are only hints and issue warnings instead of failing the mount, basically when the checks are derived from the data found in the superblock. Tested on a broken image provided by Qu. Reported-by: Qu Wenruo <[email protected]> Signed-off-by: David Sterba <[email protected]> Signed-off-by: Chris Mason <[email protected]>
1 parent 4238302 commit c926093

File tree

1 file changed

+65
-2
lines changed

1 file changed

+65
-2
lines changed

fs/btrfs/disk-io.c

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3817,10 +3817,73 @@ int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid)
38173817
static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info,
38183818
int read_only)
38193819
{
3820+
struct btrfs_super_block *sb = fs_info->super_copy;
3821+
int ret = 0;
3822+
3823+
if (sb->root_level > BTRFS_MAX_LEVEL) {
3824+
printk(KERN_ERR "BTRFS: tree_root level too big: %d > %d\n",
3825+
sb->root_level, BTRFS_MAX_LEVEL);
3826+
ret = -EINVAL;
3827+
}
3828+
if (sb->chunk_root_level > BTRFS_MAX_LEVEL) {
3829+
printk(KERN_ERR "BTRFS: chunk_root level too big: %d > %d\n",
3830+
sb->chunk_root_level, BTRFS_MAX_LEVEL);
3831+
ret = -EINVAL;
3832+
}
3833+
if (sb->log_root_level > BTRFS_MAX_LEVEL) {
3834+
printk(KERN_ERR "BTRFS: log_root level too big: %d > %d\n",
3835+
sb->log_root_level, BTRFS_MAX_LEVEL);
3836+
ret = -EINVAL;
3837+
}
3838+
38203839
/*
3821-
* Placeholder for checks
3840+
* The common minimum, we don't know if we can trust the nodesize/sectorsize
3841+
* items yet, they'll be verified later. Issue just a warning.
38223842
*/
3823-
return 0;
3843+
if (!IS_ALIGNED(sb->root, 4096))
3844+
printk(KERN_WARNING "BTRFS: tree_root block unaligned: %llu\n",
3845+
sb->root);
3846+
if (!IS_ALIGNED(sb->chunk_root, 4096))
3847+
printk(KERN_WARNING "BTRFS: tree_root block unaligned: %llu\n",
3848+
sb->chunk_root);
3849+
if (!IS_ALIGNED(sb->log_root, 4096))
3850+
printk(KERN_WARNING "BTRFS: tree_root block unaligned: %llu\n",
3851+
sb->log_root);
3852+
3853+
if (memcmp(fs_info->fsid, sb->dev_item.fsid, BTRFS_UUID_SIZE) != 0) {
3854+
printk(KERN_ERR "BTRFS: dev_item UUID does not match fsid: %pU != %pU\n",
3855+
fs_info->fsid, sb->dev_item.fsid);
3856+
ret = -EINVAL;
3857+
}
3858+
3859+
/*
3860+
* Hint to catch really bogus numbers, bitflips or so, more exact checks are
3861+
* done later
3862+
*/
3863+
if (sb->num_devices > (1UL << 31))
3864+
printk(KERN_WARNING "BTRFS: suspicious number of devices: %llu\n",
3865+
sb->num_devices);
3866+
3867+
if (sb->bytenr != BTRFS_SUPER_INFO_OFFSET) {
3868+
printk(KERN_ERR "BTRFS: super offset mismatch %llu != %u\n",
3869+
sb->bytenr, BTRFS_SUPER_INFO_OFFSET);
3870+
ret = -EINVAL;
3871+
}
3872+
3873+
/*
3874+
* The generation is a global counter, we'll trust it more than the others
3875+
* but it's still possible that it's the one that's wrong.
3876+
*/
3877+
if (sb->generation < sb->chunk_root_generation)
3878+
printk(KERN_WARNING
3879+
"BTRFS: suspicious: generation < chunk_root_generation: %llu < %llu\n",
3880+
sb->generation, sb->chunk_root_generation);
3881+
if (sb->generation < sb->cache_generation && sb->cache_generation != (u64)-1)
3882+
printk(KERN_WARNING
3883+
"BTRFS: suspicious: generation < cache_generation: %llu < %llu\n",
3884+
sb->generation, sb->cache_generation);
3885+
3886+
return ret;
38243887
}
38253888

38263889
static void btrfs_error_commit_super(struct btrfs_root *root)

0 commit comments

Comments
 (0)