Commit 031ad9e7 authored by Kent Overstreet's avatar Kent Overstreet
Browse files

bcachefs: Check for packed bkeys that are too big



add missing validation; fixes assertion pop in bkey unpack

Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 58caa786
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -314,6 +314,12 @@ static inline unsigned bkeyp_key_u64s(const struct bkey_format *format,
	return bkey_packed(k) ? format->key_u64s : BKEY_U64s;
}

static inline bool bkeyp_u64s_valid(const struct bkey_format *f,
				    const struct bkey_packed *k)
{
	return ((unsigned) k->u64s - bkeyp_key_u64s(f, k) <= U8_MAX - BKEY_U64s);
}

static inline unsigned bkeyp_key_bytes(const struct bkey_format *format,
				       const struct bkey_packed *k)
{
+8 −7
Original line number Diff line number Diff line
@@ -831,7 +831,7 @@ static int bset_key_invalid(struct bch_fs *c, struct btree *b,
		(rw == WRITE ? bch2_bkey_val_invalid(c, k, READ, err) : 0);
}

static bool __bkey_valid(struct bch_fs *c, struct btree *b,
static bool bkey_packed_valid(struct bch_fs *c, struct btree *b,
			 struct bset *i, struct bkey_packed *k)
{
	if (bkey_p_next(k) > vstruct_last(i))
@@ -840,7 +840,7 @@ static bool __bkey_valid(struct bch_fs *c, struct btree *b,
	if (k->format > KEY_FORMAT_CURRENT)
		return false;

	if (k->u64s < bkeyp_key_u64s(&b->format, k))
	if (!bkeyp_u64s_valid(&b->format, k))
		return false;

	struct printbuf buf = PRINTBUF;
@@ -884,11 +884,13 @@ static int validate_bset_keys(struct bch_fs *c, struct btree *b,
				 "invalid bkey format %u", k->format))
			goto drop_this_key;

		if (btree_err_on(k->u64s < bkeyp_key_u64s(&b->format, k),
		if (btree_err_on(!bkeyp_u64s_valid(&b->format, k),
				 -BCH_ERR_btree_node_read_err_fixable,
				 c, NULL, b, i,
				 btree_node_bkey_bad_u64s,
				 "k->u64s too small (%u < %u)", k->u64s, bkeyp_key_u64s(&b->format, k)))
				 "bad k->u64s %u (min %u max %lu)", k->u64s,
				 bkeyp_key_u64s(&b->format, k),
				 U8_MAX - BKEY_U64s + bkeyp_key_u64s(&b->format, k)))
			goto drop_this_key;

		if (!write)
@@ -947,13 +949,12 @@ static int validate_bset_keys(struct bch_fs *c, struct btree *b,
			 * do
			 */

			if (!__bkey_valid(c, b, i, (void *) ((u64 *) k + next_good_key))) {
			if (!bkey_packed_valid(c, b, i, (void *) ((u64 *) k + next_good_key))) {
				for (next_good_key = 1;
				     next_good_key < (u64 *) vstruct_last(i) - (u64 *) k;
				     next_good_key++)
					if (__bkey_valid(c, b, i, (void *) ((u64 *) k + next_good_key)))
					if (bkey_packed_valid(c, b, i, (void *) ((u64 *) k + next_good_key)))
						goto got_good_key;

			}

			/*