mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-09 14:43:16 +00:00
bcachefs: Fix a buffer overrun in bch2_fs_usage_read()
We were copying the size of a struct bch_fs_usage_online to a struct bch_fs_usage, which is 8 bytes smaller. This adds some new helpers so we can do this correctly, and get rid of some magic +1s too. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
0b438c5bfa
commit
962210b281
@ -137,17 +137,17 @@ u64 bch2_fs_usage_read_one(struct bch_fs *c, u64 *v)
|
||||
struct bch_fs_usage_online *bch2_fs_usage_read(struct bch_fs *c)
|
||||
{
|
||||
struct bch_fs_usage_online *ret;
|
||||
unsigned seq, i, v, u64s = fs_usage_u64s(c) + 1;
|
||||
unsigned nr_replicas = READ_ONCE(c->replicas.nr);
|
||||
unsigned seq, i;
|
||||
retry:
|
||||
ret = kmalloc(u64s * sizeof(u64), GFP_NOFS);
|
||||
ret = kmalloc(__fs_usage_online_u64s(nr_replicas) * sizeof(u64), GFP_NOFS);
|
||||
if (unlikely(!ret))
|
||||
return NULL;
|
||||
|
||||
percpu_down_read(&c->mark_lock);
|
||||
|
||||
v = fs_usage_u64s(c) + 1;
|
||||
if (unlikely(u64s != v)) {
|
||||
u64s = v;
|
||||
if (nr_replicas != c->replicas.nr) {
|
||||
nr_replicas = c->replicas.nr;
|
||||
percpu_up_read(&c->mark_lock);
|
||||
kfree(ret);
|
||||
goto retry;
|
||||
@ -157,10 +157,12 @@ retry:
|
||||
|
||||
do {
|
||||
seq = read_seqcount_begin(&c->usage_lock);
|
||||
unsafe_memcpy(&ret->u, c->usage_base, u64s * sizeof(u64),
|
||||
unsafe_memcpy(&ret->u, c->usage_base,
|
||||
__fs_usage_u64s(nr_replicas) * sizeof(u64),
|
||||
"embedded variable length struct");
|
||||
for (i = 0; i < ARRAY_SIZE(c->usage); i++)
|
||||
acc_u64s_percpu((u64 *) &ret->u, (u64 __percpu *) c->usage[i], u64s);
|
||||
acc_u64s_percpu((u64 *) &ret->u, (u64 __percpu *) c->usage[i],
|
||||
__fs_usage_u64s(nr_replicas));
|
||||
} while (read_seqcount_retry(&c->usage_lock, seq));
|
||||
|
||||
return ret;
|
||||
|
@ -207,10 +207,24 @@ static inline u64 dev_buckets_available(struct bch_dev *ca,
|
||||
|
||||
/* Filesystem usage: */
|
||||
|
||||
static inline unsigned __fs_usage_u64s(unsigned nr_replicas)
|
||||
{
|
||||
return sizeof(struct bch_fs_usage) / sizeof(u64) + nr_replicas;
|
||||
}
|
||||
|
||||
static inline unsigned fs_usage_u64s(struct bch_fs *c)
|
||||
{
|
||||
return sizeof(struct bch_fs_usage) / sizeof(u64) +
|
||||
READ_ONCE(c->replicas.nr);
|
||||
return __fs_usage_u64s(READ_ONCE(c->replicas.nr));
|
||||
}
|
||||
|
||||
static inline unsigned __fs_usage_online_u64s(unsigned nr_replicas)
|
||||
{
|
||||
return sizeof(struct bch_fs_usage_online) / sizeof(u64) + nr_replicas;
|
||||
}
|
||||
|
||||
static inline unsigned fs_usage_online_u64s(struct bch_fs *c)
|
||||
{
|
||||
return __fs_usage_online_u64s(READ_ONCE(c->replicas.nr));
|
||||
}
|
||||
|
||||
static inline unsigned dev_usage_u64s(void)
|
||||
|
Loading…
x
Reference in New Issue
Block a user