tree-checker.c (c1499166d10ae734b5ec5cc7982bd9b9ee7f9fe6) | tree-checker.c (80d7fd1e09822daf8d94d46c6f9a17e7e34cf0b4) |
---|---|
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) Qu Wenruo 2017. All rights reserved. 4 */ 5 6/* 7 * The module is used to catch unexpected/corrupted tree block data. 8 * Such behavior can be caused either by a fuzzed image or bugs. --- 111 unchanged lines hidden (view full) --- 120 end = ALIGN(key->offset + len, leaf->fs_info->sectorsize); 121 } else { 122 len = btrfs_file_extent_num_bytes(leaf, extent); 123 end = key->offset + len; 124 } 125 return end; 126} 127 | 1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) Qu Wenruo 2017. All rights reserved. 4 */ 5 6/* 7 * The module is used to catch unexpected/corrupted tree block data. 8 * Such behavior can be caused either by a fuzzed image or bugs. --- 111 unchanged lines hidden (view full) --- 120 end = ALIGN(key->offset + len, leaf->fs_info->sectorsize); 121 } else { 122 len = btrfs_file_extent_num_bytes(leaf, extent); 123 end = key->offset + len; 124 } 125 return end; 126} 127 |
128/* 129 * Customized report for dir_item, the only new important information is 130 * key->objectid, which represents inode number 131 */ 132__printf(3, 4) 133__cold 134static void dir_item_err(const struct extent_buffer *eb, int slot, 135 const char *fmt, ...) 136{ 137 const struct btrfs_fs_info *fs_info = eb->fs_info; 138 struct btrfs_key key; 139 struct va_format vaf; 140 va_list args; 141 142 btrfs_item_key_to_cpu(eb, &key, slot); 143 va_start(args, fmt); 144 145 vaf.fmt = fmt; 146 vaf.va = &args; 147 148 btrfs_crit(fs_info, 149 "corrupt %s: root=%llu block=%llu slot=%d ino=%llu, %pV", 150 btrfs_header_level(eb) == 0 ? "leaf" : "node", 151 btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot, 152 key.objectid, &vaf); 153 va_end(args); 154} 155 156/* 157 * This functions checks prev_key->objectid, to ensure current key and prev_key 158 * share the same objectid as inode number. 159 * 160 * This is to detect missing INODE_ITEM in subvolume trees. 161 * 162 * Return true if everything is OK or we don't need to check. 163 * Return false if anything is wrong. 164 */ 165static bool check_prev_ino(struct extent_buffer *leaf, 166 struct btrfs_key *key, int slot, 167 struct btrfs_key *prev_key) 168{ 169 /* No prev key, skip check */ 170 if (slot == 0) 171 return true; 172 173 /* Only these key->types needs to be checked */ 174 ASSERT(key->type == BTRFS_XATTR_ITEM_KEY || 175 key->type == BTRFS_INODE_REF_KEY || 176 key->type == BTRFS_DIR_INDEX_KEY || 177 key->type == BTRFS_DIR_ITEM_KEY || 178 key->type == BTRFS_EXTENT_DATA_KEY); 179 180 /* 181 * Only subvolume trees along with their reloc trees need this check. 182 * Things like log tree doesn't follow this ino requirement. 183 */ 184 if (!is_fstree(btrfs_header_owner(leaf))) 185 return true; 186 187 if (key->objectid == prev_key->objectid) 188 return true; 189 190 /* Error found */ 191 dir_item_err(leaf, slot, 192 "invalid previous key objectid, have %llu expect %llu", 193 prev_key->objectid, key->objectid); 194 return false; 195} |
|
128static int check_extent_data_item(struct extent_buffer *leaf, 129 struct btrfs_key *key, int slot, 130 struct btrfs_key *prev_key) 131{ 132 struct btrfs_fs_info *fs_info = leaf->fs_info; 133 struct btrfs_file_extent_item *fi; 134 u32 sectorsize = fs_info->sectorsize; 135 u32 item_size = btrfs_item_size_nr(leaf, slot); --- 7 unchanged lines hidden (view full) --- 143 } 144 145 /* 146 * Previous key must have the same key->objectid (ino). 147 * It can be XATTR_ITEM, INODE_ITEM or just another EXTENT_DATA. 148 * But if objectids mismatch, it means we have a missing 149 * INODE_ITEM. 150 */ | 196static int check_extent_data_item(struct extent_buffer *leaf, 197 struct btrfs_key *key, int slot, 198 struct btrfs_key *prev_key) 199{ 200 struct btrfs_fs_info *fs_info = leaf->fs_info; 201 struct btrfs_file_extent_item *fi; 202 u32 sectorsize = fs_info->sectorsize; 203 u32 item_size = btrfs_item_size_nr(leaf, slot); --- 7 unchanged lines hidden (view full) --- 211 } 212 213 /* 214 * Previous key must have the same key->objectid (ino). 215 * It can be XATTR_ITEM, INODE_ITEM or just another EXTENT_DATA. 216 * But if objectids mismatch, it means we have a missing 217 * INODE_ITEM. 218 */ |
151 if (slot > 0 && is_fstree(btrfs_header_owner(leaf)) && 152 prev_key->objectid != key->objectid) { 153 file_extent_err(leaf, slot, 154 "invalid previous key objectid, have %llu expect %llu", 155 prev_key->objectid, key->objectid); | 219 if (!check_prev_ino(leaf, key, slot, prev_key)) |
156 return -EUCLEAN; | 220 return -EUCLEAN; |
157 } | |
158 159 fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); 160 161 if (btrfs_file_extent_type(leaf, fi) > BTRFS_FILE_EXTENT_TYPES) { 162 file_extent_err(leaf, slot, 163 "invalid type for file extent, have %u expect range [0, %u]", 164 btrfs_file_extent_type(leaf, fi), 165 BTRFS_FILE_EXTENT_TYPES); --- 114 unchanged lines hidden (view full) --- 280 generic_err(leaf, slot, 281 "unaligned item size for csum item, have %u should be aligned to %u", 282 btrfs_item_size_nr(leaf, slot), csumsize); 283 return -EUCLEAN; 284 } 285 return 0; 286} 287 | 221 222 fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); 223 224 if (btrfs_file_extent_type(leaf, fi) > BTRFS_FILE_EXTENT_TYPES) { 225 file_extent_err(leaf, slot, 226 "invalid type for file extent, have %u expect range [0, %u]", 227 btrfs_file_extent_type(leaf, fi), 228 BTRFS_FILE_EXTENT_TYPES); --- 114 unchanged lines hidden (view full) --- 343 generic_err(leaf, slot, 344 "unaligned item size for csum item, have %u should be aligned to %u", 345 btrfs_item_size_nr(leaf, slot), csumsize); 346 return -EUCLEAN; 347 } 348 return 0; 349} 350 |
288/* 289 * Customized reported for dir_item, only important new info is key->objectid, 290 * which represents inode number 291 */ 292__printf(3, 4) 293__cold 294static void dir_item_err(const struct extent_buffer *eb, int slot, 295 const char *fmt, ...) 296{ 297 const struct btrfs_fs_info *fs_info = eb->fs_info; 298 struct btrfs_key key; 299 struct va_format vaf; 300 va_list args; 301 302 btrfs_item_key_to_cpu(eb, &key, slot); 303 va_start(args, fmt); 304 305 vaf.fmt = fmt; 306 vaf.va = &args; 307 308 btrfs_crit(fs_info, 309 "corrupt %s: root=%llu block=%llu slot=%d ino=%llu, %pV", 310 btrfs_header_level(eb) == 0 ? "leaf" : "node", 311 btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot, 312 key.objectid, &vaf); 313 va_end(args); 314} 315 | |
316static int check_dir_item(struct extent_buffer *leaf, 317 struct btrfs_key *key, struct btrfs_key *prev_key, 318 int slot) 319{ 320 struct btrfs_fs_info *fs_info = leaf->fs_info; 321 struct btrfs_dir_item *di; 322 u32 item_size = btrfs_item_size_nr(leaf, slot); 323 u32 cur = 0; 324 | 351static int check_dir_item(struct extent_buffer *leaf, 352 struct btrfs_key *key, struct btrfs_key *prev_key, 353 int slot) 354{ 355 struct btrfs_fs_info *fs_info = leaf->fs_info; 356 struct btrfs_dir_item *di; 357 u32 item_size = btrfs_item_size_nr(leaf, slot); 358 u32 cur = 0; 359 |
325 /* Same check as in check_extent_data_item() */ 326 if (slot > 0 && is_fstree(btrfs_header_owner(leaf)) && 327 prev_key->objectid != key->objectid) { 328 dir_item_err(leaf, slot, 329 "invalid previous key objectid, have %llu expect %llu", 330 prev_key->objectid, key->objectid); | 360 if (!check_prev_ino(leaf, key, slot, prev_key)) |
331 return -EUCLEAN; | 361 return -EUCLEAN; |
332 } | |
333 di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item); 334 while (cur < item_size) { 335 u32 name_len; 336 u32 data_len; 337 u32 max_name_len; 338 u32 total_size; 339 u32 name_hash; 340 u8 dir_type; --- 912 unchanged lines hidden (view full) --- 1253static int check_inode_ref(struct extent_buffer *leaf, 1254 struct btrfs_key *key, struct btrfs_key *prev_key, 1255 int slot) 1256{ 1257 struct btrfs_inode_ref *iref; 1258 unsigned long ptr; 1259 unsigned long end; 1260 | 362 di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item); 363 while (cur < item_size) { 364 u32 name_len; 365 u32 data_len; 366 u32 max_name_len; 367 u32 total_size; 368 u32 name_hash; 369 u8 dir_type; --- 912 unchanged lines hidden (view full) --- 1282static int check_inode_ref(struct extent_buffer *leaf, 1283 struct btrfs_key *key, struct btrfs_key *prev_key, 1284 int slot) 1285{ 1286 struct btrfs_inode_ref *iref; 1287 unsigned long ptr; 1288 unsigned long end; 1289 |
1290 if (!check_prev_ino(leaf, key, slot, prev_key)) 1291 return -EUCLEAN; |
|
1261 /* namelen can't be 0, so item_size == sizeof() is also invalid */ 1262 if (btrfs_item_size_nr(leaf, slot) <= sizeof(*iref)) { 1263 inode_ref_err(fs_info, leaf, slot, 1264 "invalid item size, have %u expect (%zu, %u)", 1265 btrfs_item_size_nr(leaf, slot), 1266 sizeof(*iref), BTRFS_LEAF_DATA_SIZE(leaf->fs_info)); 1267 return -EUCLEAN; 1268 } --- 297 unchanged lines hidden --- | 1292 /* namelen can't be 0, so item_size == sizeof() is also invalid */ 1293 if (btrfs_item_size_nr(leaf, slot) <= sizeof(*iref)) { 1294 inode_ref_err(fs_info, leaf, slot, 1295 "invalid item size, have %u expect (%zu, %u)", 1296 btrfs_item_size_nr(leaf, slot), 1297 sizeof(*iref), BTRFS_LEAF_DATA_SIZE(leaf->fs_info)); 1298 return -EUCLEAN; 1299 } --- 297 unchanged lines hidden --- |