bcachefs: Check for packed bkeys that are too big
authorKent Overstreet <kent.overstreet@linux.dev>
Fri, 12 Apr 2024 01:30:43 +0000 (21:30 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 14 Apr 2024 02:48:16 +0000 (22:48 -0400)
add missing validation; fixes assertion pop in bkey unpack

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/bkey.h
fs/bcachefs/btree_io.c

index cf23ff47bed8be588593a7fb193ee21ca8298c65..3a45d128f608db86d060d43573219d60762e3038 100644 (file)
@@ -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)
 {
index d7de82ac389354f9a0d5eef0a66c8694f1752b94..b1aaf0550644a27a49280b46eac46bdee4a2ad70 100644 (file)
@@ -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 @@ drop_this_key:
                         * 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;
-
                        }
 
                        /*