mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-03 21:45:08 -04:00
bcachefs: Fix buffer overrun in ec_stripe_update_extent()
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
@@ -865,25 +865,6 @@ static int ec_stripe_key_update(struct btree_trans *trans,
|
||||
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:
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user