bcachefs: Fix buffer overrun in ec_stripe_update_extent()
authorKent Overstreet <kent.overstreet@linux.dev>
Wed, 22 Feb 2023 22:57:59 +0000 (17:57 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:09:54 +0000 (17:09 -0400)
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/ec.c
fs/bcachefs/extents.c
fs/bcachefs/extents.h

index 9244948..4b054f7 100644 (file)
@@ -865,25 +865,6 @@ err:
        return ret;
 }
 
-static void extent_stripe_ptr_add(struct bkey_s_extent e,
-                                 struct ec_stripe_buf *s,
-                                 struct bch_extent_ptr *ptr,
-                                 unsigned block)
-{
-       struct bch_extent_stripe_ptr *dst = (void *) ptr;
-       union bch_extent_entry *end = extent_entry_last(e);
-
-       memmove_u64s_up(dst + 1, dst, (u64 *) end - (u64 *) dst);
-       e.k->u64s += sizeof(*dst) / sizeof(u64);
-
-       *dst = (struct bch_extent_stripe_ptr) {
-               .type = 1 << BCH_EXTENT_ENTRY_stripe_ptr,
-               .block          = block,
-               .redundancy     = s->key.v.nr_redundant,
-               .idx            = s->key.k.p.offset,
-       };
-}
-
 static int ec_stripe_update_extent(struct btree_trans *trans,
                                   struct bpos bucket, u8 gen,
                                   struct ec_stripe_buf *s,
@@ -895,6 +876,7 @@ static int ec_stripe_update_extent(struct btree_trans *trans,
        struct bkey_s_c k;
        const struct bch_extent_ptr *ptr_c;
        struct bch_extent_ptr *ptr, *ec_ptr = NULL;
+       struct bch_extent_stripe_ptr stripe_ptr;
        struct bkey_i *n;
        int ret, dev, block;
 
@@ -933,16 +915,27 @@ static int ec_stripe_update_extent(struct btree_trans *trans,
 
        dev = s->key.v.ptrs[block].dev;
 
-       n = bch2_bkey_make_mut(trans, k);
+       n = bch2_trans_kmalloc(trans, bkey_bytes(k.k) + sizeof(stripe_ptr));
        ret = PTR_ERR_OR_ZERO(n);
        if (ret)
                goto out;
 
+       bkey_reassemble(n, k);
+
        bch2_bkey_drop_ptrs(bkey_i_to_s(n), ptr, ptr->dev != dev);
        ec_ptr = (void *) bch2_bkey_has_device(bkey_i_to_s_c(n), dev);
        BUG_ON(!ec_ptr);
 
-       extent_stripe_ptr_add(bkey_i_to_s_extent(n), s, ec_ptr, block);
+       stripe_ptr = (struct bch_extent_stripe_ptr) {
+               .type = 1 << BCH_EXTENT_ENTRY_stripe_ptr,
+               .block          = block,
+               .redundancy     = s->key.v.nr_redundant,
+               .idx            = s->key.k.p.offset,
+       };
+
+       __extent_entry_insert(n,
+                       (union bch_extent_entry *) ec_ptr,
+                       (union bch_extent_entry *) &stripe_ptr);
 
        ret = bch2_trans_update(trans, &iter, n, 0);
 out:
index a55e0ed..38be9bf 100644 (file)
@@ -705,18 +705,6 @@ void bch2_bkey_extent_entry_drop(struct bkey_i *k, union bch_extent_entry *entry
        k->k.u64s -= extent_entry_u64s(entry);
 }
 
-static inline void __extent_entry_insert(struct bkey_i *k,
-                                        union bch_extent_entry *dst,
-                                        union bch_extent_entry *new)
-{
-       union bch_extent_entry *end = bkey_val_end(bkey_i_to_s(k));
-
-       memmove_u64s_up_small((u64 *) dst + extent_entry_u64s(new),
-                             dst, (u64 *) end - (u64 *) dst);
-       k->k.u64s += extent_entry_u64s(new);
-       memcpy_u64s_small(dst, new, extent_entry_u64s(new));
-}
-
 void bch2_extent_ptr_decoded_append(struct bkey_i *k,
                                    struct extent_ptr_decoded *p)
 {
index c52a098..2e37543 100644 (file)
@@ -76,6 +76,18 @@ static inline size_t extent_entry_u64s(const union bch_extent_entry *entry)
        return extent_entry_bytes(entry) / sizeof(u64);
 }
 
+static inline void __extent_entry_insert(struct bkey_i *k,
+                                        union bch_extent_entry *dst,
+                                        union bch_extent_entry *new)
+{
+       union bch_extent_entry *end = bkey_val_end(bkey_i_to_s(k));
+
+       memmove_u64s_up_small((u64 *) dst + extent_entry_u64s(new),
+                             dst, (u64 *) end - (u64 *) dst);
+       k->k.u64s += extent_entry_u64s(new);
+       memcpy_u64s_small(dst, new, extent_entry_u64s(new));
+}
+
 static inline bool extent_entry_is_ptr(const union bch_extent_entry *e)
 {
        return extent_entry_type(e) == BCH_EXTENT_ENTRY_ptr;