mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-26 04:16:39 +00:00
btrfs: make thaw time super block check to also verify checksum
commit3d17adea74
upstream. Previous commita05d3c9153
("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:a05d3c9153
("btrfs: check superblock to ensure the fs was not modified at thaw time") Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com> Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
1e7ed525c6
commit
acf85eeda0
3 changed files with 22 additions and 6 deletions
|
@ -167,11 +167,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);
|
||||||
|
|
||||||
|
@ -182,7 +180,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))
|
||||||
|
@ -3471,7 +3469,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(
|
||||||
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);
|
||||||
|
|
|
@ -2553,6 +2553,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. */
|
||||||
|
@ -2567,6 +2568,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)
|
||||||
|
|
Loading…
Reference in a new issue