diff options
author | Liu Bo <bo.li.liu@oracle.com> | 2017-08-18 17:15:18 -0400 |
---|---|---|
committer | David Sterba <dsterba@suse.com> | 2017-08-21 11:47:42 -0400 |
commit | 167ce953ca55bdee20fe56c3c0fa51002435f745 (patch) | |
tree | b85800ec47dd67e42d969c6c53a0257bae58c8a1 | |
parent | af1cbe0a66cb9e6c3f2acf7f0a7fc647b5dc4f2f (diff) |
Btrfs: add a helper to retrive extent inline ref type
An invalid value of extent inline ref type may be read from a
malicious image which may force btrfs to crash.
This adds a helper which does sanity check for the ref type, so we can
know if it's sane, return he type, otherwise return an error.
Signed-off-by: Liu Bo <bo.li.liu@oracle.com>
Reviewed-by: David Sterba <dsterba@suse.com>
[ minimal tweak const types, causing warnings due to other cleanup patches ]
Signed-off-by: David Sterba <dsterba@suse.com>
-rw-r--r-- | fs/btrfs/ctree.h | 11 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 37 |
2 files changed, 48 insertions, 0 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index ca087ad5ac48..542db9d0dbcd 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -2567,6 +2567,17 @@ static inline gfp_t btrfs_alloc_write_mask(struct address_space *mapping) | |||
2567 | 2567 | ||
2568 | /* extent-tree.c */ | 2568 | /* extent-tree.c */ |
2569 | 2569 | ||
2570 | enum btrfs_inline_ref_type { | ||
2571 | BTRFS_REF_TYPE_INVALID = 0, | ||
2572 | BTRFS_REF_TYPE_BLOCK = 1, | ||
2573 | BTRFS_REF_TYPE_DATA = 2, | ||
2574 | BTRFS_REF_TYPE_ANY = 3, | ||
2575 | }; | ||
2576 | |||
2577 | int btrfs_get_extent_inline_ref_type(const struct extent_buffer *eb, | ||
2578 | struct btrfs_extent_inline_ref *iref, | ||
2579 | enum btrfs_inline_ref_type is_data); | ||
2580 | |||
2570 | u64 btrfs_csum_bytes_to_leaves(struct btrfs_fs_info *fs_info, u64 csum_bytes); | 2581 | u64 btrfs_csum_bytes_to_leaves(struct btrfs_fs_info *fs_info, u64 csum_bytes); |
2571 | 2582 | ||
2572 | static inline u64 btrfs_calc_trans_metadata_size(struct btrfs_fs_info *fs_info, | 2583 | static inline u64 btrfs_calc_trans_metadata_size(struct btrfs_fs_info *fs_info, |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 1a80f6e58296..794b06dd824a 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -1148,6 +1148,43 @@ static int convert_extent_item_v0(struct btrfs_trans_handle *trans, | |||
1148 | } | 1148 | } |
1149 | #endif | 1149 | #endif |
1150 | 1150 | ||
1151 | /* | ||
1152 | * is_data == BTRFS_REF_TYPE_BLOCK, tree block type is required, | ||
1153 | * is_data == BTRFS_REF_TYPE_DATA, data type is requried, | ||
1154 | * is_data == BTRFS_REF_TYPE_ANY, either type is OK. | ||
1155 | */ | ||
1156 | int btrfs_get_extent_inline_ref_type(const struct extent_buffer *eb, | ||
1157 | struct btrfs_extent_inline_ref *iref, | ||
1158 | enum btrfs_inline_ref_type is_data) | ||
1159 | { | ||
1160 | int type = btrfs_extent_inline_ref_type(eb, iref); | ||
1161 | |||
1162 | if (type == BTRFS_TREE_BLOCK_REF_KEY || | ||
1163 | type == BTRFS_SHARED_BLOCK_REF_KEY || | ||
1164 | type == BTRFS_SHARED_DATA_REF_KEY || | ||
1165 | type == BTRFS_EXTENT_DATA_REF_KEY) { | ||
1166 | if (is_data == BTRFS_REF_TYPE_BLOCK) { | ||
1167 | if (type == BTRFS_TREE_BLOCK_REF_KEY || | ||
1168 | type == BTRFS_SHARED_BLOCK_REF_KEY) | ||
1169 | return type; | ||
1170 | } else if (is_data == BTRFS_REF_TYPE_DATA) { | ||
1171 | if (type == BTRFS_EXTENT_DATA_REF_KEY || | ||
1172 | type == BTRFS_SHARED_DATA_REF_KEY) | ||
1173 | return type; | ||
1174 | } else { | ||
1175 | ASSERT(is_data == BTRFS_REF_TYPE_ANY); | ||
1176 | return type; | ||
1177 | } | ||
1178 | } | ||
1179 | |||
1180 | btrfs_print_leaf((struct extent_buffer *)eb); | ||
1181 | btrfs_err(eb->fs_info, "eb %llu invalid extent inline ref type %d", | ||
1182 | eb->start, type); | ||
1183 | WARN_ON(1); | ||
1184 | |||
1185 | return BTRFS_REF_TYPE_INVALID; | ||
1186 | } | ||
1187 | |||
1151 | static u64 hash_extent_data_ref(u64 root_objectid, u64 owner, u64 offset) | 1188 | static u64 hash_extent_data_ref(u64 root_objectid, u64 owner, u64 offset) |
1152 | { | 1189 | { |
1153 | u32 high_crc = ~(u32)0; | 1190 | u32 high_crc = ~(u32)0; |