Commit 3d17adea authored by Qu Wenruo's avatar Qu Wenruo Committed by David Sterba

btrfs: make thaw time super block check to also verify checksum

Previous commit a05d3c91 ("btrfs: check superblock to ensure the fs
was not modified at thaw time") only checks the content of the super
block, but it doesn't really check if the on-disk super block has a
matching checksum.

This patch will add the checksum verification to thaw time superblock
verification.

This involves the following extra changes:

- Export btrfs_check_super_csum()
  As we need to call it in super.c.

- Change the argument list of btrfs_check_super_csum()
  Instead of passing a char *, directly pass struct btrfs_super_block *
  pointer.

- Verify that our checksum type didn't change before checking the
  checksum value, like it's done at mount time

Fixes: a05d3c91 ("btrfs: check superblock to ensure the fs was not modified at thaw time")
Reviewed-by: default avatarJohannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: default avatarQu Wenruo <wqu@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 968b7158
...@@ -166,11 +166,9 @@ static bool btrfs_supported_super_csum(u16 csum_type) ...@@ -166,11 +166,9 @@ static bool btrfs_supported_super_csum(u16 csum_type)
* Return 0 if the superblock checksum type matches the checksum value of that * Return 0 if the superblock checksum type matches the checksum value of that
* algorithm. Pass the raw disk superblock data. * algorithm. Pass the raw disk superblock data.
*/ */
static int btrfs_check_super_csum(struct btrfs_fs_info *fs_info, int btrfs_check_super_csum(struct btrfs_fs_info *fs_info,
char *raw_disk_sb) const struct btrfs_super_block *disk_sb)
{ {
struct btrfs_super_block *disk_sb =
(struct btrfs_super_block *)raw_disk_sb;
char result[BTRFS_CSUM_SIZE]; char result[BTRFS_CSUM_SIZE];
SHASH_DESC_ON_STACK(shash, fs_info->csum_shash); SHASH_DESC_ON_STACK(shash, fs_info->csum_shash);
...@@ -181,7 +179,7 @@ static int btrfs_check_super_csum(struct btrfs_fs_info *fs_info, ...@@ -181,7 +179,7 @@ static int btrfs_check_super_csum(struct btrfs_fs_info *fs_info,
* BTRFS_SUPER_INFO_SIZE range, we expect that the unused space is * BTRFS_SUPER_INFO_SIZE range, we expect that the unused space is
* filled with zeros and is included in the checksum. * filled with zeros and is included in the checksum.
*/ */
crypto_shash_digest(shash, raw_disk_sb + BTRFS_CSUM_SIZE, crypto_shash_digest(shash, (const u8 *)disk_sb + BTRFS_CSUM_SIZE,
BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE, result); BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE, result);
if (memcmp(disk_sb->csum, result, fs_info->csum_size)) if (memcmp(disk_sb->csum, result, fs_info->csum_size))
...@@ -3479,7 +3477,7 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device ...@@ -3479,7 +3477,7 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
* We want to check superblock checksum, the type is stored inside. * We want to check superblock checksum, the type is stored inside.
* Pass the whole disk block of size BTRFS_SUPER_INFO_SIZE (4k). * Pass the whole disk block of size BTRFS_SUPER_INFO_SIZE (4k).
*/ */
if (btrfs_check_super_csum(fs_info, (u8 *)disk_super)) { if (btrfs_check_super_csum(fs_info, disk_super)) {
btrfs_err(fs_info, "superblock checksum mismatch"); btrfs_err(fs_info, "superblock checksum mismatch");
err = -EINVAL; err = -EINVAL;
btrfs_release_disk_super(disk_super); btrfs_release_disk_super(disk_super);
......
...@@ -42,6 +42,8 @@ struct extent_buffer *btrfs_find_create_tree_block( ...@@ -42,6 +42,8 @@ struct extent_buffer *btrfs_find_create_tree_block(
void btrfs_clean_tree_block(struct extent_buffer *buf); void btrfs_clean_tree_block(struct extent_buffer *buf);
void btrfs_clear_oneshot_options(struct btrfs_fs_info *fs_info); void btrfs_clear_oneshot_options(struct btrfs_fs_info *fs_info);
int btrfs_start_pre_rw_mount(struct btrfs_fs_info *fs_info); int btrfs_start_pre_rw_mount(struct btrfs_fs_info *fs_info);
int btrfs_check_super_csum(struct btrfs_fs_info *fs_info,
const struct btrfs_super_block *disk_sb);
int __cold open_ctree(struct super_block *sb, int __cold open_ctree(struct super_block *sb,
struct btrfs_fs_devices *fs_devices, struct btrfs_fs_devices *fs_devices,
char *options); char *options);
......
...@@ -2555,6 +2555,7 @@ static int check_dev_super(struct btrfs_device *dev) ...@@ -2555,6 +2555,7 @@ static int check_dev_super(struct btrfs_device *dev)
{ {
struct btrfs_fs_info *fs_info = dev->fs_info; struct btrfs_fs_info *fs_info = dev->fs_info;
struct btrfs_super_block *sb; struct btrfs_super_block *sb;
u16 csum_type;
int ret = 0; int ret = 0;
/* This should be called with fs still frozen. */ /* This should be called with fs still frozen. */
...@@ -2569,6 +2570,21 @@ static int check_dev_super(struct btrfs_device *dev) ...@@ -2569,6 +2570,21 @@ static int check_dev_super(struct btrfs_device *dev)
if (IS_ERR(sb)) if (IS_ERR(sb))
return PTR_ERR(sb); return PTR_ERR(sb);
/* Verify the checksum. */
csum_type = btrfs_super_csum_type(sb);
if (csum_type != btrfs_super_csum_type(fs_info->super_copy)) {
btrfs_err(fs_info, "csum type changed, has %u expect %u",
csum_type, btrfs_super_csum_type(fs_info->super_copy));
ret = -EUCLEAN;
goto out;
}
if (btrfs_check_super_csum(fs_info, sb)) {
btrfs_err(fs_info, "csum for on-disk super block no longer matches");
ret = -EUCLEAN;
goto out;
}
/* Btrfs_validate_super() includes fsid check against super->fsid. */ /* Btrfs_validate_super() includes fsid check against super->fsid. */
ret = btrfs_validate_super(fs_info, sb, 0); ret = btrfs_validate_super(fs_info, sb, 0);
if (ret < 0) if (ret < 0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment