xref: /openbmc/linux/fs/btrfs/tree-checker.c (revision ba61bb17)
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.
9  *
10  * The objective is to do leaf/node validation checks when tree block is read
11  * from disk, and check *every* possible member, so other code won't
12  * need to checking them again.
13  *
14  * Due to the potential and unwanted damage, every checker needs to be
15  * carefully reviewed otherwise so it does not prevent mount of valid images.
16  */
17 
18 #include "ctree.h"
19 #include "tree-checker.h"
20 #include "disk-io.h"
21 #include "compression.h"
22 
23 /*
24  * Error message should follow the following format:
25  * corrupt <type>: <identifier>, <reason>[, <bad_value>]
26  *
27  * @type:	leaf or node
28  * @identifier:	the necessary info to locate the leaf/node.
29  * 		It's recommened to decode key.objecitd/offset if it's
30  * 		meaningful.
31  * @reason:	describe the error
32  * @bad_value:	optional, it's recommened to output bad value and its
33  *		expected value (range).
34  *
35  * Since comma is used to separate the components, only space is allowed
36  * inside each component.
37  */
38 
39 /*
40  * Append generic "corrupt leaf/node root=%llu block=%llu slot=%d: " to @fmt.
41  * Allows callers to customize the output.
42  */
43 __printf(4, 5)
44 __cold
45 static void generic_err(const struct btrfs_fs_info *fs_info,
46 			const struct extent_buffer *eb, int slot,
47 			const char *fmt, ...)
48 {
49 	struct va_format vaf;
50 	va_list args;
51 
52 	va_start(args, fmt);
53 
54 	vaf.fmt = fmt;
55 	vaf.va = &args;
56 
57 	btrfs_crit(fs_info,
58 		"corrupt %s: root=%llu block=%llu slot=%d, %pV",
59 		btrfs_header_level(eb) == 0 ? "leaf" : "node",
60 		btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot, &vaf);
61 	va_end(args);
62 }
63 
64 /*
65  * Customized reporter for extent data item, since its key objectid and
66  * offset has its own meaning.
67  */
68 __printf(4, 5)
69 __cold
70 static void file_extent_err(const struct btrfs_fs_info *fs_info,
71 			    const struct extent_buffer *eb, int slot,
72 			    const char *fmt, ...)
73 {
74 	struct btrfs_key key;
75 	struct va_format vaf;
76 	va_list args;
77 
78 	btrfs_item_key_to_cpu(eb, &key, slot);
79 	va_start(args, fmt);
80 
81 	vaf.fmt = fmt;
82 	vaf.va = &args;
83 
84 	btrfs_crit(fs_info,
85 	"corrupt %s: root=%llu block=%llu slot=%d ino=%llu file_offset=%llu, %pV",
86 		btrfs_header_level(eb) == 0 ? "leaf" : "node",
87 		btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot,
88 		key.objectid, key.offset, &vaf);
89 	va_end(args);
90 }
91 
92 /*
93  * Return 0 if the btrfs_file_extent_##name is aligned to @alignment
94  * Else return 1
95  */
96 #define CHECK_FE_ALIGNED(fs_info, leaf, slot, fi, name, alignment)	      \
97 ({									      \
98 	if (!IS_ALIGNED(btrfs_file_extent_##name((leaf), (fi)), (alignment))) \
99 		file_extent_err((fs_info), (leaf), (slot),		      \
100 	"invalid %s for file extent, have %llu, should be aligned to %u",     \
101 			(#name), btrfs_file_extent_##name((leaf), (fi)),      \
102 			(alignment));					      \
103 	(!IS_ALIGNED(btrfs_file_extent_##name((leaf), (fi)), (alignment)));   \
104 })
105 
106 static int check_extent_data_item(struct btrfs_fs_info *fs_info,
107 				  struct extent_buffer *leaf,
108 				  struct btrfs_key *key, int slot)
109 {
110 	struct btrfs_file_extent_item *fi;
111 	u32 sectorsize = fs_info->sectorsize;
112 	u32 item_size = btrfs_item_size_nr(leaf, slot);
113 
114 	if (!IS_ALIGNED(key->offset, sectorsize)) {
115 		file_extent_err(fs_info, leaf, slot,
116 "unaligned file_offset for file extent, have %llu should be aligned to %u",
117 			key->offset, sectorsize);
118 		return -EUCLEAN;
119 	}
120 
121 	fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);
122 
123 	if (btrfs_file_extent_type(leaf, fi) > BTRFS_FILE_EXTENT_TYPES) {
124 		file_extent_err(fs_info, leaf, slot,
125 		"invalid type for file extent, have %u expect range [0, %u]",
126 			btrfs_file_extent_type(leaf, fi),
127 			BTRFS_FILE_EXTENT_TYPES);
128 		return -EUCLEAN;
129 	}
130 
131 	/*
132 	 * Support for new compression/encrption must introduce incompat flag,
133 	 * and must be caught in open_ctree().
134 	 */
135 	if (btrfs_file_extent_compression(leaf, fi) > BTRFS_COMPRESS_TYPES) {
136 		file_extent_err(fs_info, leaf, slot,
137 	"invalid compression for file extent, have %u expect range [0, %u]",
138 			btrfs_file_extent_compression(leaf, fi),
139 			BTRFS_COMPRESS_TYPES);
140 		return -EUCLEAN;
141 	}
142 	if (btrfs_file_extent_encryption(leaf, fi)) {
143 		file_extent_err(fs_info, leaf, slot,
144 			"invalid encryption for file extent, have %u expect 0",
145 			btrfs_file_extent_encryption(leaf, fi));
146 		return -EUCLEAN;
147 	}
148 	if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) {
149 		/* Inline extent must have 0 as key offset */
150 		if (key->offset) {
151 			file_extent_err(fs_info, leaf, slot,
152 		"invalid file_offset for inline file extent, have %llu expect 0",
153 				key->offset);
154 			return -EUCLEAN;
155 		}
156 
157 		/* Compressed inline extent has no on-disk size, skip it */
158 		if (btrfs_file_extent_compression(leaf, fi) !=
159 		    BTRFS_COMPRESS_NONE)
160 			return 0;
161 
162 		/* Uncompressed inline extent size must match item size */
163 		if (item_size != BTRFS_FILE_EXTENT_INLINE_DATA_START +
164 		    btrfs_file_extent_ram_bytes(leaf, fi)) {
165 			file_extent_err(fs_info, leaf, slot,
166 	"invalid ram_bytes for uncompressed inline extent, have %u expect %llu",
167 				item_size, BTRFS_FILE_EXTENT_INLINE_DATA_START +
168 				btrfs_file_extent_ram_bytes(leaf, fi));
169 			return -EUCLEAN;
170 		}
171 		return 0;
172 	}
173 
174 	/* Regular or preallocated extent has fixed item size */
175 	if (item_size != sizeof(*fi)) {
176 		file_extent_err(fs_info, leaf, slot,
177 	"invalid item size for reg/prealloc file extent, have %u expect %zu",
178 			item_size, sizeof(*fi));
179 		return -EUCLEAN;
180 	}
181 	if (CHECK_FE_ALIGNED(fs_info, leaf, slot, fi, ram_bytes, sectorsize) ||
182 	    CHECK_FE_ALIGNED(fs_info, leaf, slot, fi, disk_bytenr, sectorsize) ||
183 	    CHECK_FE_ALIGNED(fs_info, leaf, slot, fi, disk_num_bytes, sectorsize) ||
184 	    CHECK_FE_ALIGNED(fs_info, leaf, slot, fi, offset, sectorsize) ||
185 	    CHECK_FE_ALIGNED(fs_info, leaf, slot, fi, num_bytes, sectorsize))
186 		return -EUCLEAN;
187 	return 0;
188 }
189 
190 static int check_csum_item(struct btrfs_fs_info *fs_info,
191 			   struct extent_buffer *leaf, struct btrfs_key *key,
192 			   int slot)
193 {
194 	u32 sectorsize = fs_info->sectorsize;
195 	u32 csumsize = btrfs_super_csum_size(fs_info->super_copy);
196 
197 	if (key->objectid != BTRFS_EXTENT_CSUM_OBJECTID) {
198 		generic_err(fs_info, leaf, slot,
199 		"invalid key objectid for csum item, have %llu expect %llu",
200 			key->objectid, BTRFS_EXTENT_CSUM_OBJECTID);
201 		return -EUCLEAN;
202 	}
203 	if (!IS_ALIGNED(key->offset, sectorsize)) {
204 		generic_err(fs_info, leaf, slot,
205 	"unaligned key offset for csum item, have %llu should be aligned to %u",
206 			key->offset, sectorsize);
207 		return -EUCLEAN;
208 	}
209 	if (!IS_ALIGNED(btrfs_item_size_nr(leaf, slot), csumsize)) {
210 		generic_err(fs_info, leaf, slot,
211 	"unaligned item size for csum item, have %u should be aligned to %u",
212 			btrfs_item_size_nr(leaf, slot), csumsize);
213 		return -EUCLEAN;
214 	}
215 	return 0;
216 }
217 
218 /*
219  * Customized reported for dir_item, only important new info is key->objectid,
220  * which represents inode number
221  */
222 __printf(4, 5)
223 __cold
224 static void dir_item_err(const struct btrfs_fs_info *fs_info,
225 			 const struct extent_buffer *eb, int slot,
226 			 const char *fmt, ...)
227 {
228 	struct btrfs_key key;
229 	struct va_format vaf;
230 	va_list args;
231 
232 	btrfs_item_key_to_cpu(eb, &key, slot);
233 	va_start(args, fmt);
234 
235 	vaf.fmt = fmt;
236 	vaf.va = &args;
237 
238 	btrfs_crit(fs_info,
239 	"corrupt %s: root=%llu block=%llu slot=%d ino=%llu, %pV",
240 		btrfs_header_level(eb) == 0 ? "leaf" : "node",
241 		btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot,
242 		key.objectid, &vaf);
243 	va_end(args);
244 }
245 
246 static int check_dir_item(struct btrfs_fs_info *fs_info,
247 			  struct extent_buffer *leaf,
248 			  struct btrfs_key *key, int slot)
249 {
250 	struct btrfs_dir_item *di;
251 	u32 item_size = btrfs_item_size_nr(leaf, slot);
252 	u32 cur = 0;
253 
254 	di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
255 	while (cur < item_size) {
256 		u32 name_len;
257 		u32 data_len;
258 		u32 max_name_len;
259 		u32 total_size;
260 		u32 name_hash;
261 		u8 dir_type;
262 
263 		/* header itself should not cross item boundary */
264 		if (cur + sizeof(*di) > item_size) {
265 			dir_item_err(fs_info, leaf, slot,
266 		"dir item header crosses item boundary, have %zu boundary %u",
267 				cur + sizeof(*di), item_size);
268 			return -EUCLEAN;
269 		}
270 
271 		/* dir type check */
272 		dir_type = btrfs_dir_type(leaf, di);
273 		if (dir_type >= BTRFS_FT_MAX) {
274 			dir_item_err(fs_info, leaf, slot,
275 			"invalid dir item type, have %u expect [0, %u)",
276 				dir_type, BTRFS_FT_MAX);
277 			return -EUCLEAN;
278 		}
279 
280 		if (key->type == BTRFS_XATTR_ITEM_KEY &&
281 		    dir_type != BTRFS_FT_XATTR) {
282 			dir_item_err(fs_info, leaf, slot,
283 		"invalid dir item type for XATTR key, have %u expect %u",
284 				dir_type, BTRFS_FT_XATTR);
285 			return -EUCLEAN;
286 		}
287 		if (dir_type == BTRFS_FT_XATTR &&
288 		    key->type != BTRFS_XATTR_ITEM_KEY) {
289 			dir_item_err(fs_info, leaf, slot,
290 			"xattr dir type found for non-XATTR key");
291 			return -EUCLEAN;
292 		}
293 		if (dir_type == BTRFS_FT_XATTR)
294 			max_name_len = XATTR_NAME_MAX;
295 		else
296 			max_name_len = BTRFS_NAME_LEN;
297 
298 		/* Name/data length check */
299 		name_len = btrfs_dir_name_len(leaf, di);
300 		data_len = btrfs_dir_data_len(leaf, di);
301 		if (name_len > max_name_len) {
302 			dir_item_err(fs_info, leaf, slot,
303 			"dir item name len too long, have %u max %u",
304 				name_len, max_name_len);
305 			return -EUCLEAN;
306 		}
307 		if (name_len + data_len > BTRFS_MAX_XATTR_SIZE(fs_info)) {
308 			dir_item_err(fs_info, leaf, slot,
309 			"dir item name and data len too long, have %u max %u",
310 				name_len + data_len,
311 				BTRFS_MAX_XATTR_SIZE(fs_info));
312 			return -EUCLEAN;
313 		}
314 
315 		if (data_len && dir_type != BTRFS_FT_XATTR) {
316 			dir_item_err(fs_info, leaf, slot,
317 			"dir item with invalid data len, have %u expect 0",
318 				data_len);
319 			return -EUCLEAN;
320 		}
321 
322 		total_size = sizeof(*di) + name_len + data_len;
323 
324 		/* header and name/data should not cross item boundary */
325 		if (cur + total_size > item_size) {
326 			dir_item_err(fs_info, leaf, slot,
327 		"dir item data crosses item boundary, have %u boundary %u",
328 				cur + total_size, item_size);
329 			return -EUCLEAN;
330 		}
331 
332 		/*
333 		 * Special check for XATTR/DIR_ITEM, as key->offset is name
334 		 * hash, should match its name
335 		 */
336 		if (key->type == BTRFS_DIR_ITEM_KEY ||
337 		    key->type == BTRFS_XATTR_ITEM_KEY) {
338 			char namebuf[max(BTRFS_NAME_LEN, XATTR_NAME_MAX)];
339 
340 			read_extent_buffer(leaf, namebuf,
341 					(unsigned long)(di + 1), name_len);
342 			name_hash = btrfs_name_hash(namebuf, name_len);
343 			if (key->offset != name_hash) {
344 				dir_item_err(fs_info, leaf, slot,
345 		"name hash mismatch with key, have 0x%016x expect 0x%016llx",
346 					name_hash, key->offset);
347 				return -EUCLEAN;
348 			}
349 		}
350 		cur += total_size;
351 		di = (struct btrfs_dir_item *)((void *)di + total_size);
352 	}
353 	return 0;
354 }
355 
356 /*
357  * Common point to switch the item-specific validation.
358  */
359 static int check_leaf_item(struct btrfs_fs_info *fs_info,
360 			   struct extent_buffer *leaf,
361 			   struct btrfs_key *key, int slot)
362 {
363 	int ret = 0;
364 
365 	switch (key->type) {
366 	case BTRFS_EXTENT_DATA_KEY:
367 		ret = check_extent_data_item(fs_info, leaf, key, slot);
368 		break;
369 	case BTRFS_EXTENT_CSUM_KEY:
370 		ret = check_csum_item(fs_info, leaf, key, slot);
371 		break;
372 	case BTRFS_DIR_ITEM_KEY:
373 	case BTRFS_DIR_INDEX_KEY:
374 	case BTRFS_XATTR_ITEM_KEY:
375 		ret = check_dir_item(fs_info, leaf, key, slot);
376 		break;
377 	}
378 	return ret;
379 }
380 
381 static int check_leaf(struct btrfs_fs_info *fs_info, struct extent_buffer *leaf,
382 		      bool check_item_data)
383 {
384 	/* No valid key type is 0, so all key should be larger than this key */
385 	struct btrfs_key prev_key = {0, 0, 0};
386 	struct btrfs_key key;
387 	u32 nritems = btrfs_header_nritems(leaf);
388 	int slot;
389 
390 	/*
391 	 * Extent buffers from a relocation tree have a owner field that
392 	 * corresponds to the subvolume tree they are based on. So just from an
393 	 * extent buffer alone we can not find out what is the id of the
394 	 * corresponding subvolume tree, so we can not figure out if the extent
395 	 * buffer corresponds to the root of the relocation tree or not. So
396 	 * skip this check for relocation trees.
397 	 */
398 	if (nritems == 0 && !btrfs_header_flag(leaf, BTRFS_HEADER_FLAG_RELOC)) {
399 		struct btrfs_root *check_root;
400 
401 		key.objectid = btrfs_header_owner(leaf);
402 		key.type = BTRFS_ROOT_ITEM_KEY;
403 		key.offset = (u64)-1;
404 
405 		check_root = btrfs_get_fs_root(fs_info, &key, false);
406 		/*
407 		 * The only reason we also check NULL here is that during
408 		 * open_ctree() some roots has not yet been set up.
409 		 */
410 		if (!IS_ERR_OR_NULL(check_root)) {
411 			struct extent_buffer *eb;
412 
413 			eb = btrfs_root_node(check_root);
414 			/* if leaf is the root, then it's fine */
415 			if (leaf != eb) {
416 				generic_err(fs_info, leaf, 0,
417 		"invalid nritems, have %u should not be 0 for non-root leaf",
418 					nritems);
419 				free_extent_buffer(eb);
420 				return -EUCLEAN;
421 			}
422 			free_extent_buffer(eb);
423 		}
424 		return 0;
425 	}
426 
427 	if (nritems == 0)
428 		return 0;
429 
430 	/*
431 	 * Check the following things to make sure this is a good leaf, and
432 	 * leaf users won't need to bother with similar sanity checks:
433 	 *
434 	 * 1) key ordering
435 	 * 2) item offset and size
436 	 *    No overlap, no hole, all inside the leaf.
437 	 * 3) item content
438 	 *    If possible, do comprehensive sanity check.
439 	 *    NOTE: All checks must only rely on the item data itself.
440 	 */
441 	for (slot = 0; slot < nritems; slot++) {
442 		u32 item_end_expected;
443 		int ret;
444 
445 		btrfs_item_key_to_cpu(leaf, &key, slot);
446 
447 		/* Make sure the keys are in the right order */
448 		if (btrfs_comp_cpu_keys(&prev_key, &key) >= 0) {
449 			generic_err(fs_info, leaf, slot,
450 	"bad key order, prev (%llu %u %llu) current (%llu %u %llu)",
451 				prev_key.objectid, prev_key.type,
452 				prev_key.offset, key.objectid, key.type,
453 				key.offset);
454 			return -EUCLEAN;
455 		}
456 
457 		/*
458 		 * Make sure the offset and ends are right, remember that the
459 		 * item data starts at the end of the leaf and grows towards the
460 		 * front.
461 		 */
462 		if (slot == 0)
463 			item_end_expected = BTRFS_LEAF_DATA_SIZE(fs_info);
464 		else
465 			item_end_expected = btrfs_item_offset_nr(leaf,
466 								 slot - 1);
467 		if (btrfs_item_end_nr(leaf, slot) != item_end_expected) {
468 			generic_err(fs_info, leaf, slot,
469 				"unexpected item end, have %u expect %u",
470 				btrfs_item_end_nr(leaf, slot),
471 				item_end_expected);
472 			return -EUCLEAN;
473 		}
474 
475 		/*
476 		 * Check to make sure that we don't point outside of the leaf,
477 		 * just in case all the items are consistent to each other, but
478 		 * all point outside of the leaf.
479 		 */
480 		if (btrfs_item_end_nr(leaf, slot) >
481 		    BTRFS_LEAF_DATA_SIZE(fs_info)) {
482 			generic_err(fs_info, leaf, slot,
483 			"slot end outside of leaf, have %u expect range [0, %u]",
484 				btrfs_item_end_nr(leaf, slot),
485 				BTRFS_LEAF_DATA_SIZE(fs_info));
486 			return -EUCLEAN;
487 		}
488 
489 		/* Also check if the item pointer overlaps with btrfs item. */
490 		if (btrfs_item_nr_offset(slot) + sizeof(struct btrfs_item) >
491 		    btrfs_item_ptr_offset(leaf, slot)) {
492 			generic_err(fs_info, leaf, slot,
493 		"slot overlaps with its data, item end %lu data start %lu",
494 				btrfs_item_nr_offset(slot) +
495 				sizeof(struct btrfs_item),
496 				btrfs_item_ptr_offset(leaf, slot));
497 			return -EUCLEAN;
498 		}
499 
500 		if (check_item_data) {
501 			/*
502 			 * Check if the item size and content meet other
503 			 * criteria
504 			 */
505 			ret = check_leaf_item(fs_info, leaf, &key, slot);
506 			if (ret < 0)
507 				return ret;
508 		}
509 
510 		prev_key.objectid = key.objectid;
511 		prev_key.type = key.type;
512 		prev_key.offset = key.offset;
513 	}
514 
515 	return 0;
516 }
517 
518 int btrfs_check_leaf_full(struct btrfs_fs_info *fs_info,
519 			  struct extent_buffer *leaf)
520 {
521 	return check_leaf(fs_info, leaf, true);
522 }
523 
524 int btrfs_check_leaf_relaxed(struct btrfs_fs_info *fs_info,
525 			     struct extent_buffer *leaf)
526 {
527 	return check_leaf(fs_info, leaf, false);
528 }
529 
530 int btrfs_check_node(struct btrfs_fs_info *fs_info, struct extent_buffer *node)
531 {
532 	unsigned long nr = btrfs_header_nritems(node);
533 	struct btrfs_key key, next_key;
534 	int slot;
535 	u64 bytenr;
536 	int ret = 0;
537 
538 	if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(fs_info)) {
539 		btrfs_crit(fs_info,
540 "corrupt node: root=%llu block=%llu, nritems too %s, have %lu expect range [1,%u]",
541 			   btrfs_header_owner(node), node->start,
542 			   nr == 0 ? "small" : "large", nr,
543 			   BTRFS_NODEPTRS_PER_BLOCK(fs_info));
544 		return -EUCLEAN;
545 	}
546 
547 	for (slot = 0; slot < nr - 1; slot++) {
548 		bytenr = btrfs_node_blockptr(node, slot);
549 		btrfs_node_key_to_cpu(node, &key, slot);
550 		btrfs_node_key_to_cpu(node, &next_key, slot + 1);
551 
552 		if (!bytenr) {
553 			generic_err(fs_info, node, slot,
554 				"invalid NULL node pointer");
555 			ret = -EUCLEAN;
556 			goto out;
557 		}
558 		if (!IS_ALIGNED(bytenr, fs_info->sectorsize)) {
559 			generic_err(fs_info, node, slot,
560 			"unaligned pointer, have %llu should be aligned to %u",
561 				bytenr, fs_info->sectorsize);
562 			ret = -EUCLEAN;
563 			goto out;
564 		}
565 
566 		if (btrfs_comp_cpu_keys(&key, &next_key) >= 0) {
567 			generic_err(fs_info, node, slot,
568 	"bad key order, current (%llu %u %llu) next (%llu %u %llu)",
569 				key.objectid, key.type, key.offset,
570 				next_key.objectid, next_key.type,
571 				next_key.offset);
572 			ret = -EUCLEAN;
573 			goto out;
574 		}
575 	}
576 out:
577 	return ret;
578 }
579