aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorQu Wenruo <quwenruo@cn.fujitsu.com>2015-12-14 20:14:36 -0500
committerChris Mason <clm@fb.com>2016-01-19 21:21:41 -0500
commit319e4d0661e5323c9f9945f0f8fb5905e5fe74c3 (patch)
tree8930cb9cd248db15d0443bc93e046be23633921c /fs
parentc2d6cb1636d235257086f939a8194ef0bf93af6e (diff)
btrfs: Enhance super validation check
Enhance btrfs_check_super_valid() function by the following points: 1) Restrict sector/node size check Not the old max/min valid check, but also check if it's a power of 2. So some bogus number like 12K node size won't pass now. 2) Super flag check For now, there is still some inconsistency between kernel and btrfs-progs super flags. And considering btrfs-progs may add new flags for super block, this check will only output warning. 3) Better root alignment check Now root bytenr is checked against sector size. 4) Move some check into btrfs_check_super_valid(). Like node size vs leaf size check, and PAGESIZE vs sectorsize check. And magic number check. Reported-by: Vegard Nossum <vegard.nossum@oracle.com> Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/disk-io.c97
1 files changed, 48 insertions, 49 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index be03f93ca257..26ef14152093 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -55,6 +55,12 @@
55#include <asm/cpufeature.h> 55#include <asm/cpufeature.h>
56#endif 56#endif
57 57
58#define BTRFS_SUPER_FLAG_SUPP (BTRFS_HEADER_FLAG_WRITTEN |\
59 BTRFS_HEADER_FLAG_RELOC |\
60 BTRFS_SUPER_FLAG_ERROR |\
61 BTRFS_SUPER_FLAG_SEEDING |\
62 BTRFS_SUPER_FLAG_METADUMP)
63
58static const struct extent_io_ops btree_extent_io_ops; 64static const struct extent_io_ops btree_extent_io_ops;
59static void end_workqueue_fn(struct btrfs_work *work); 65static void end_workqueue_fn(struct btrfs_work *work);
60static void free_fs_root(struct btrfs_root *root); 66static void free_fs_root(struct btrfs_root *root);
@@ -2760,26 +2766,6 @@ int open_ctree(struct super_block *sb,
2760 goto fail_alloc; 2766 goto fail_alloc;
2761 } 2767 }
2762 2768
2763 /*
2764 * Leafsize and nodesize were always equal, this is only a sanity check.
2765 */
2766 if (le32_to_cpu(disk_super->__unused_leafsize) !=
2767 btrfs_super_nodesize(disk_super)) {
2768 printk(KERN_ERR "BTRFS: couldn't mount because metadata "
2769 "blocksizes don't match. node %d leaf %d\n",
2770 btrfs_super_nodesize(disk_super),
2771 le32_to_cpu(disk_super->__unused_leafsize));
2772 err = -EINVAL;
2773 goto fail_alloc;
2774 }
2775 if (btrfs_super_nodesize(disk_super) > BTRFS_MAX_METADATA_BLOCKSIZE) {
2776 printk(KERN_ERR "BTRFS: couldn't mount because metadata "
2777 "blocksize (%d) was too large\n",
2778 btrfs_super_nodesize(disk_super));
2779 err = -EINVAL;
2780 goto fail_alloc;
2781 }
2782
2783 features = btrfs_super_incompat_flags(disk_super); 2769 features = btrfs_super_incompat_flags(disk_super);
2784 features |= BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF; 2770 features |= BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF;
2785 if (tree_root->fs_info->compress_type == BTRFS_COMPRESS_LZO) 2771 if (tree_root->fs_info->compress_type == BTRFS_COMPRESS_LZO)
@@ -2851,17 +2837,6 @@ int open_ctree(struct super_block *sb,
2851 sb->s_blocksize = sectorsize; 2837 sb->s_blocksize = sectorsize;
2852 sb->s_blocksize_bits = blksize_bits(sectorsize); 2838 sb->s_blocksize_bits = blksize_bits(sectorsize);
2853 2839
2854 if (btrfs_super_magic(disk_super) != BTRFS_MAGIC) {
2855 printk(KERN_ERR "BTRFS: valid FS not found on %s\n", sb->s_id);
2856 goto fail_sb_buffer;
2857 }
2858
2859 if (sectorsize != PAGE_SIZE) {
2860 printk(KERN_ERR "BTRFS: incompatible sector size (%lu) "
2861 "found on %s\n", (unsigned long)sectorsize, sb->s_id);
2862 goto fail_sb_buffer;
2863 }
2864
2865 mutex_lock(&fs_info->chunk_mutex); 2840 mutex_lock(&fs_info->chunk_mutex);
2866 ret = btrfs_read_sys_array(tree_root); 2841 ret = btrfs_read_sys_array(tree_root);
2867 mutex_unlock(&fs_info->chunk_mutex); 2842 mutex_unlock(&fs_info->chunk_mutex);
@@ -4048,8 +4023,17 @@ static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info,
4048 int read_only) 4023 int read_only)
4049{ 4024{
4050 struct btrfs_super_block *sb = fs_info->super_copy; 4025 struct btrfs_super_block *sb = fs_info->super_copy;
4026 u64 nodesize = btrfs_super_nodesize(sb);
4027 u64 sectorsize = btrfs_super_sectorsize(sb);
4051 int ret = 0; 4028 int ret = 0;
4052 4029
4030 if (btrfs_super_magic(sb) != BTRFS_MAGIC) {
4031 printk(KERN_ERR "BTRFS: no valid FS found\n");
4032 ret = -EINVAL;
4033 }
4034 if (btrfs_super_flags(sb) & ~BTRFS_SUPER_FLAG_SUPP)
4035 printk(KERN_WARNING "BTRFS: unrecognized super flag: %llu\n",
4036 btrfs_super_flags(sb) & ~BTRFS_SUPER_FLAG_SUPP);
4053 if (btrfs_super_root_level(sb) >= BTRFS_MAX_LEVEL) { 4037 if (btrfs_super_root_level(sb) >= BTRFS_MAX_LEVEL) {
4054 printk(KERN_ERR "BTRFS: tree_root level too big: %d >= %d\n", 4038 printk(KERN_ERR "BTRFS: tree_root level too big: %d >= %d\n",
4055 btrfs_super_root_level(sb), BTRFS_MAX_LEVEL); 4039 btrfs_super_root_level(sb), BTRFS_MAX_LEVEL);
@@ -4067,31 +4051,46 @@ static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info,
4067 } 4051 }
4068 4052
4069 /* 4053 /*
4070 * The common minimum, we don't know if we can trust the nodesize/sectorsize 4054 * Check sectorsize and nodesize first, other check will need it.
4071 * items yet, they'll be verified later. Issue just a warning. 4055 * Check all possible sectorsize(4K, 8K, 16K, 32K, 64K) here.
4072 */ 4056 */
4073 if (!IS_ALIGNED(btrfs_super_root(sb), 4096)) 4057 if (!is_power_of_2(sectorsize) || sectorsize < 4096 ||
4058 sectorsize > BTRFS_MAX_METADATA_BLOCKSIZE) {
4059 printk(KERN_ERR "BTRFS: invalid sectorsize %llu\n", sectorsize);
4060 ret = -EINVAL;
4061 }
4062 /* Only PAGE SIZE is supported yet */
4063 if (sectorsize != PAGE_CACHE_SIZE) {
4064 printk(KERN_ERR "BTRFS: sectorsize %llu not supported yet, only support %lu\n",
4065 sectorsize, PAGE_CACHE_SIZE);
4066 ret = -EINVAL;
4067 }
4068 if (!is_power_of_2(nodesize) || nodesize < sectorsize ||
4069 nodesize > BTRFS_MAX_METADATA_BLOCKSIZE) {
4070 printk(KERN_ERR "BTRFS: invalid nodesize %llu\n", nodesize);
4071 ret = -EINVAL;
4072 }
4073 if (nodesize != le32_to_cpu(sb->__unused_leafsize)) {
4074 printk(KERN_ERR "BTRFS: invalid leafsize %u, should be %llu\n",
4075 le32_to_cpu(sb->__unused_leafsize),
4076 nodesize);
4077 ret = -EINVAL;
4078 }
4079
4080 /* Root alignment check */
4081 if (!IS_ALIGNED(btrfs_super_root(sb), sectorsize)) {
4074 printk(KERN_WARNING "BTRFS: tree_root block unaligned: %llu\n", 4082 printk(KERN_WARNING "BTRFS: tree_root block unaligned: %llu\n",
4075 btrfs_super_root(sb)); 4083 btrfs_super_root(sb));
4076 if (!IS_ALIGNED(btrfs_super_chunk_root(sb), 4096)) 4084 ret = -EINVAL;
4085 }
4086 if (!IS_ALIGNED(btrfs_super_chunk_root(sb), sectorsize)) {
4077 printk(KERN_WARNING "BTRFS: chunk_root block unaligned: %llu\n", 4087 printk(KERN_WARNING "BTRFS: chunk_root block unaligned: %llu\n",
4078 btrfs_super_chunk_root(sb)); 4088 btrfs_super_chunk_root(sb));
4079 if (!IS_ALIGNED(btrfs_super_log_root(sb), 4096))
4080 printk(KERN_WARNING "BTRFS: log_root block unaligned: %llu\n",
4081 btrfs_super_log_root(sb));
4082
4083 /*
4084 * Check the lower bound, the alignment and other constraints are
4085 * checked later.
4086 */
4087 if (btrfs_super_nodesize(sb) < 4096) {
4088 printk(KERN_ERR "BTRFS: nodesize too small: %u < 4096\n",
4089 btrfs_super_nodesize(sb));
4090 ret = -EINVAL; 4089 ret = -EINVAL;
4091 } 4090 }
4092 if (btrfs_super_sectorsize(sb) < 4096) { 4091 if (!IS_ALIGNED(btrfs_super_log_root(sb), sectorsize)) {
4093 printk(KERN_ERR "BTRFS: sectorsize too small: %u < 4096\n", 4092 printk(KERN_WARNING "BTRFS: log_root block unaligned: %llu\n",
4094 btrfs_super_sectorsize(sb)); 4093 btrfs_super_log_root(sb));
4095 ret = -EINVAL; 4094 ret = -EINVAL;
4096 } 4095 }
4097 4096