@@ -910,6 +910,250 @@ static int check_root_item(struct extent_buffer *leaf, struct btrfs_key *key,
910910 return 0 ;
911911}
912912
913+ __printf (3 ,4 )
914+ __cold
915+ static void extent_err (const struct extent_buffer * eb , int slot ,
916+ const char * fmt , ...)
917+ {
918+ struct btrfs_key key ;
919+ struct va_format vaf ;
920+ va_list args ;
921+ u64 bytenr ;
922+ u64 len ;
923+
924+ btrfs_item_key_to_cpu (eb , & key , slot );
925+ bytenr = key .objectid ;
926+ if (key .type == BTRFS_METADATA_ITEM_KEY )
927+ len = eb -> fs_info -> nodesize ;
928+ else
929+ len = key .offset ;
930+ va_start (args , fmt );
931+
932+ vaf .fmt = fmt ;
933+ vaf .va = & args ;
934+
935+ btrfs_crit (eb -> fs_info ,
936+ "corrupt %s: block=%llu slot=%d extent bytenr=%llu len=%llu %pV" ,
937+ btrfs_header_level (eb ) == 0 ? "leaf" : "node" ,
938+ eb -> start , slot , bytenr , len , & vaf );
939+ va_end (args );
940+ }
941+
942+ static int check_extent_item (struct extent_buffer * leaf ,
943+ struct btrfs_key * key , int slot )
944+ {
945+ struct btrfs_fs_info * fs_info = leaf -> fs_info ;
946+ struct btrfs_extent_item * ei ;
947+ bool is_tree_block = false;
948+ unsigned long ptr ; /* Current pointer inside inline refs */
949+ unsigned long end ; /* Extent item end */
950+ const u32 item_size = btrfs_item_size_nr (leaf , slot );
951+ u64 flags ;
952+ u64 generation ;
953+ u64 total_refs ; /* Total refs in btrfs_extent_item */
954+ u64 inline_refs = 0 ; /* found total inline refs */
955+
956+ if (key -> type == BTRFS_METADATA_ITEM_KEY &&
957+ !btrfs_fs_incompat (fs_info , SKINNY_METADATA )) {
958+ generic_err (leaf , slot ,
959+ "invalid key type, METADATA_ITEM type invalid when SKINNY_METADATA feature disabled" );
960+ return - EUCLEAN ;
961+ }
962+ /* key->objectid is the bytenr for both key types */
963+ if (!IS_ALIGNED (key -> objectid , fs_info -> sectorsize )) {
964+ generic_err (leaf , slot ,
965+ "invalid key objectid, have %llu expect to be aligned to %u" ,
966+ key -> objectid , fs_info -> sectorsize );
967+ return - EUCLEAN ;
968+ }
969+
970+ /* key->offset is tree level for METADATA_ITEM_KEY */
971+ if (key -> type == BTRFS_METADATA_ITEM_KEY &&
972+ key -> offset >= BTRFS_MAX_LEVEL ) {
973+ extent_err (leaf , slot ,
974+ "invalid tree level, have %llu expect [0, %u]" ,
975+ key -> offset , BTRFS_MAX_LEVEL - 1 );
976+ return - EUCLEAN ;
977+ }
978+
979+ /*
980+ * EXTENT/METADATA_ITEM consists of:
981+ * 1) One btrfs_extent_item
982+ * Records the total refs, type and generation of the extent.
983+ *
984+ * 2) One btrfs_tree_block_info (for EXTENT_ITEM and tree backref only)
985+ * Records the first key and level of the tree block.
986+ *
987+ * 2) Zero or more btrfs_extent_inline_ref(s)
988+ * Each inline ref has one btrfs_extent_inline_ref shows:
989+ * 2.1) The ref type, one of the 4
990+ * TREE_BLOCK_REF Tree block only
991+ * SHARED_BLOCK_REF Tree block only
992+ * EXTENT_DATA_REF Data only
993+ * SHARED_DATA_REF Data only
994+ * 2.2) Ref type specific data
995+ * Either using btrfs_extent_inline_ref::offset, or specific
996+ * data structure.
997+ */
998+ if (item_size < sizeof (* ei )) {
999+ extent_err (leaf , slot ,
1000+ "invalid item size, have %u expect [%zu, %u)" ,
1001+ item_size , sizeof (* ei ),
1002+ BTRFS_LEAF_DATA_SIZE (fs_info ));
1003+ return - EUCLEAN ;
1004+ }
1005+ end = item_size + btrfs_item_ptr_offset (leaf , slot );
1006+
1007+ /* Checks against extent_item */
1008+ ei = btrfs_item_ptr (leaf , slot , struct btrfs_extent_item );
1009+ flags = btrfs_extent_flags (leaf , ei );
1010+ total_refs = btrfs_extent_refs (leaf , ei );
1011+ generation = btrfs_extent_generation (leaf , ei );
1012+ if (generation > btrfs_super_generation (fs_info -> super_copy ) + 1 ) {
1013+ extent_err (leaf , slot ,
1014+ "invalid generation, have %llu expect (0, %llu]" ,
1015+ generation ,
1016+ btrfs_super_generation (fs_info -> super_copy ) + 1 );
1017+ return - EUCLEAN ;
1018+ }
1019+ if (!is_power_of_2 (flags & (BTRFS_EXTENT_FLAG_DATA |
1020+ BTRFS_EXTENT_FLAG_TREE_BLOCK ))) {
1021+ extent_err (leaf , slot ,
1022+ "invalid extent flag, have 0x%llx expect 1 bit set in 0x%llx" ,
1023+ flags , BTRFS_EXTENT_FLAG_DATA |
1024+ BTRFS_EXTENT_FLAG_TREE_BLOCK );
1025+ return - EUCLEAN ;
1026+ }
1027+ is_tree_block = !!(flags & BTRFS_EXTENT_FLAG_TREE_BLOCK );
1028+ if (is_tree_block ) {
1029+ if (key -> type == BTRFS_EXTENT_ITEM_KEY &&
1030+ key -> offset != fs_info -> nodesize ) {
1031+ extent_err (leaf , slot ,
1032+ "invalid extent length, have %llu expect %u" ,
1033+ key -> offset , fs_info -> nodesize );
1034+ return - EUCLEAN ;
1035+ }
1036+ } else {
1037+ if (key -> type != BTRFS_EXTENT_ITEM_KEY ) {
1038+ extent_err (leaf , slot ,
1039+ "invalid key type, have %u expect %u for data backref" ,
1040+ key -> type , BTRFS_EXTENT_ITEM_KEY );
1041+ return - EUCLEAN ;
1042+ }
1043+ if (!IS_ALIGNED (key -> offset , fs_info -> sectorsize )) {
1044+ extent_err (leaf , slot ,
1045+ "invalid extent length, have %llu expect aligned to %u" ,
1046+ key -> offset , fs_info -> sectorsize );
1047+ return - EUCLEAN ;
1048+ }
1049+ }
1050+ ptr = (unsigned long )(struct btrfs_extent_item * )(ei + 1 );
1051+
1052+ /* Check the special case of btrfs_tree_block_info */
1053+ if (is_tree_block && key -> type != BTRFS_METADATA_ITEM_KEY ) {
1054+ struct btrfs_tree_block_info * info ;
1055+
1056+ info = (struct btrfs_tree_block_info * )ptr ;
1057+ if (btrfs_tree_block_level (leaf , info ) >= BTRFS_MAX_LEVEL ) {
1058+ extent_err (leaf , slot ,
1059+ "invalid tree block info level, have %u expect [0, %u]" ,
1060+ btrfs_tree_block_level (leaf , info ),
1061+ BTRFS_MAX_LEVEL - 1 );
1062+ return - EUCLEAN ;
1063+ }
1064+ ptr = (unsigned long )(struct btrfs_tree_block_info * )(info + 1 );
1065+ }
1066+
1067+ /* Check inline refs */
1068+ while (ptr < end ) {
1069+ struct btrfs_extent_inline_ref * iref ;
1070+ struct btrfs_extent_data_ref * dref ;
1071+ struct btrfs_shared_data_ref * sref ;
1072+ u64 dref_offset ;
1073+ u64 inline_offset ;
1074+ u8 inline_type ;
1075+
1076+ if (ptr + sizeof (* iref ) > end ) {
1077+ extent_err (leaf , slot ,
1078+ "inline ref item overflows extent item, ptr %lu iref size %zu end %lu" ,
1079+ ptr , sizeof (* iref ), end );
1080+ return - EUCLEAN ;
1081+ }
1082+ iref = (struct btrfs_extent_inline_ref * )ptr ;
1083+ inline_type = btrfs_extent_inline_ref_type (leaf , iref );
1084+ inline_offset = btrfs_extent_inline_ref_offset (leaf , iref );
1085+ if (ptr + btrfs_extent_inline_ref_size (inline_type ) > end ) {
1086+ extent_err (leaf , slot ,
1087+ "inline ref item overflows extent item, ptr %lu iref size %u end %lu" ,
1088+ ptr , inline_type , end );
1089+ return - EUCLEAN ;
1090+ }
1091+
1092+ switch (inline_type ) {
1093+ /* inline_offset is subvolid of the owner, no need to check */
1094+ case BTRFS_TREE_BLOCK_REF_KEY :
1095+ inline_refs ++ ;
1096+ break ;
1097+ /* Contains parent bytenr */
1098+ case BTRFS_SHARED_BLOCK_REF_KEY :
1099+ if (!IS_ALIGNED (inline_offset , fs_info -> sectorsize )) {
1100+ extent_err (leaf , slot ,
1101+ "invalid tree parent bytenr, have %llu expect aligned to %u" ,
1102+ inline_offset , fs_info -> sectorsize );
1103+ return - EUCLEAN ;
1104+ }
1105+ inline_refs ++ ;
1106+ break ;
1107+ /*
1108+ * Contains owner subvolid, owner key objectid, adjusted offset.
1109+ * The only obvious corruption can happen in that offset.
1110+ */
1111+ case BTRFS_EXTENT_DATA_REF_KEY :
1112+ dref = (struct btrfs_extent_data_ref * )(& iref -> offset );
1113+ dref_offset = btrfs_extent_data_ref_offset (leaf , dref );
1114+ if (!IS_ALIGNED (dref_offset , fs_info -> sectorsize )) {
1115+ extent_err (leaf , slot ,
1116+ "invalid data ref offset, have %llu expect aligned to %u" ,
1117+ dref_offset , fs_info -> sectorsize );
1118+ return - EUCLEAN ;
1119+ }
1120+ inline_refs += btrfs_extent_data_ref_count (leaf , dref );
1121+ break ;
1122+ /* Contains parent bytenr and ref count */
1123+ case BTRFS_SHARED_DATA_REF_KEY :
1124+ sref = (struct btrfs_shared_data_ref * )(iref + 1 );
1125+ if (!IS_ALIGNED (inline_offset , fs_info -> sectorsize )) {
1126+ extent_err (leaf , slot ,
1127+ "invalid data parent bytenr, have %llu expect aligned to %u" ,
1128+ inline_offset , fs_info -> sectorsize );
1129+ return - EUCLEAN ;
1130+ }
1131+ inline_refs += btrfs_shared_data_ref_count (leaf , sref );
1132+ break ;
1133+ default :
1134+ extent_err (leaf , slot , "unknown inline ref type: %u" ,
1135+ inline_type );
1136+ return - EUCLEAN ;
1137+ }
1138+ ptr += btrfs_extent_inline_ref_size (inline_type );
1139+ }
1140+ /* No padding is allowed */
1141+ if (ptr != end ) {
1142+ extent_err (leaf , slot ,
1143+ "invalid extent item size, padding bytes found" );
1144+ return - EUCLEAN ;
1145+ }
1146+
1147+ /* Finally, check the inline refs against total refs */
1148+ if (inline_refs > total_refs ) {
1149+ extent_err (leaf , slot ,
1150+ "invalid extent refs, have %llu expect >= inline %llu" ,
1151+ total_refs , inline_refs );
1152+ return - EUCLEAN ;
1153+ }
1154+ return 0 ;
1155+ }
1156+
9131157/*
9141158 * Common point to switch the item-specific validation.
9151159 */
@@ -948,6 +1192,10 @@ static int check_leaf_item(struct extent_buffer *leaf,
9481192 case BTRFS_ROOT_ITEM_KEY :
9491193 ret = check_root_item (leaf , key , slot );
9501194 break ;
1195+ case BTRFS_EXTENT_ITEM_KEY :
1196+ case BTRFS_METADATA_ITEM_KEY :
1197+ ret = check_extent_item (leaf , key , slot );
1198+ break ;
9511199 }
9521200 return ret ;
9531201}
0 commit comments