mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
bcachefs: Add missing validation for jset_entry_data_usage
Validation was completely missing for replicas entries in the journal (not the superblock replicas section) - we can't have replicas entries pointing to invalid devices. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
bbc3a46065
commit
d5bd37872a
4 changed files with 53 additions and 31 deletions
|
@ -210,6 +210,7 @@
|
|||
x(BCH_ERR_invalid_sb, invalid_sb_members) \
|
||||
x(BCH_ERR_invalid_sb, invalid_sb_disk_groups) \
|
||||
x(BCH_ERR_invalid_sb, invalid_sb_replicas) \
|
||||
x(BCH_ERR_invalid_sb, invalid_replicas_entry) \
|
||||
x(BCH_ERR_invalid_sb, invalid_sb_journal) \
|
||||
x(BCH_ERR_invalid_sb, invalid_sb_journal_seq_blacklist) \
|
||||
x(BCH_ERR_invalid_sb, invalid_sb_crypt) \
|
||||
|
|
|
@ -547,6 +547,7 @@ static int journal_entry_data_usage_validate(struct bch_fs *c,
|
|||
struct jset_entry_data_usage *u =
|
||||
container_of(entry, struct jset_entry_data_usage, entry);
|
||||
unsigned bytes = jset_u64s(le16_to_cpu(entry->u64s)) * sizeof(u64);
|
||||
struct printbuf err = PRINTBUF;
|
||||
int ret = 0;
|
||||
|
||||
if (journal_entry_err_on(bytes < sizeof(*u) ||
|
||||
|
@ -555,10 +556,19 @@ static int journal_entry_data_usage_validate(struct bch_fs *c,
|
|||
journal_entry_data_usage_bad_size,
|
||||
"invalid journal entry usage: bad size")) {
|
||||
journal_entry_null_range(entry, vstruct_next(entry));
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (journal_entry_err_on(bch2_replicas_entry_validate(&u->r, c->disk_sb.sb, &err),
|
||||
c, version, jset, entry,
|
||||
journal_entry_data_usage_bad_size,
|
||||
"invalid journal entry usage: %s", err.buf)) {
|
||||
journal_entry_null_range(entry, vstruct_next(entry));
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
fsck_err:
|
||||
printbuf_exit(&err);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -68,6 +68,33 @@ void bch2_replicas_entry_to_text(struct printbuf *out,
|
|||
prt_printf(out, "]");
|
||||
}
|
||||
|
||||
int bch2_replicas_entry_validate(struct bch_replicas_entry *r,
|
||||
struct bch_sb *sb,
|
||||
struct printbuf *err)
|
||||
{
|
||||
if (!r->nr_devs) {
|
||||
prt_printf(err, "no devices in entry ");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (r->nr_required > 1 &&
|
||||
r->nr_required >= r->nr_devs) {
|
||||
prt_printf(err, "bad nr_required in entry ");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < r->nr_devs; i++)
|
||||
if (!bch2_dev_exists(sb, r->devs[i])) {
|
||||
prt_printf(err, "invalid device %u in entry ", r->devs[i]);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
return 0;
|
||||
bad:
|
||||
bch2_replicas_entry_to_text(err, r);
|
||||
return -BCH_ERR_invalid_replicas_entry;
|
||||
}
|
||||
|
||||
void bch2_cpu_replicas_to_text(struct printbuf *out,
|
||||
struct bch_replicas_cpu *r)
|
||||
{
|
||||
|
@ -163,7 +190,8 @@ void bch2_devlist_to_replicas(struct bch_replicas_entry *e,
|
|||
}
|
||||
|
||||
static struct bch_replicas_cpu
|
||||
cpu_replicas_add_entry(struct bch_replicas_cpu *old,
|
||||
cpu_replicas_add_entry(struct bch_fs *c,
|
||||
struct bch_replicas_cpu *old,
|
||||
struct bch_replicas_entry *new_entry)
|
||||
{
|
||||
unsigned i;
|
||||
|
@ -173,6 +201,9 @@ cpu_replicas_add_entry(struct bch_replicas_cpu *old,
|
|||
replicas_entry_bytes(new_entry)),
|
||||
};
|
||||
|
||||
for (i = 0; i < new_entry->nr_devs; i++)
|
||||
BUG_ON(!bch2_dev_exists2(c, new_entry->devs[i]));
|
||||
|
||||
BUG_ON(!new_entry->data_type);
|
||||
verify_replicas_entry(new_entry);
|
||||
|
||||
|
@ -382,7 +413,7 @@ static int bch2_mark_replicas_slowpath(struct bch_fs *c,
|
|||
|
||||
if (c->replicas_gc.entries &&
|
||||
!__replicas_has_entry(&c->replicas_gc, new_entry)) {
|
||||
new_gc = cpu_replicas_add_entry(&c->replicas_gc, new_entry);
|
||||
new_gc = cpu_replicas_add_entry(c, &c->replicas_gc, new_entry);
|
||||
if (!new_gc.entries) {
|
||||
ret = -BCH_ERR_ENOMEM_cpu_replicas;
|
||||
goto err;
|
||||
|
@ -390,7 +421,7 @@ static int bch2_mark_replicas_slowpath(struct bch_fs *c,
|
|||
}
|
||||
|
||||
if (!__replicas_has_entry(&c->replicas, new_entry)) {
|
||||
new_r = cpu_replicas_add_entry(&c->replicas, new_entry);
|
||||
new_r = cpu_replicas_add_entry(c, &c->replicas, new_entry);
|
||||
if (!new_r.entries) {
|
||||
ret = -BCH_ERR_ENOMEM_cpu_replicas;
|
||||
goto err;
|
||||
|
@ -598,7 +629,7 @@ int bch2_replicas_set_usage(struct bch_fs *c,
|
|||
if (idx < 0) {
|
||||
struct bch_replicas_cpu n;
|
||||
|
||||
n = cpu_replicas_add_entry(&c->replicas, r);
|
||||
n = cpu_replicas_add_entry(c, &c->replicas, r);
|
||||
if (!n.entries)
|
||||
return -BCH_ERR_ENOMEM_cpu_replicas;
|
||||
|
||||
|
@ -797,7 +828,7 @@ static int bch2_cpu_replicas_validate(struct bch_replicas_cpu *cpu_r,
|
|||
struct bch_sb *sb,
|
||||
struct printbuf *err)
|
||||
{
|
||||
unsigned i, j;
|
||||
unsigned i;
|
||||
|
||||
sort_cmp_size(cpu_r->entries,
|
||||
cpu_r->nr,
|
||||
|
@ -808,31 +839,9 @@ static int bch2_cpu_replicas_validate(struct bch_replicas_cpu *cpu_r,
|
|||
struct bch_replicas_entry *e =
|
||||
cpu_replicas_entry(cpu_r, i);
|
||||
|
||||
if (e->data_type >= BCH_DATA_NR) {
|
||||
prt_printf(err, "invalid data type in entry ");
|
||||
bch2_replicas_entry_to_text(err, e);
|
||||
return -BCH_ERR_invalid_sb_replicas;
|
||||
}
|
||||
|
||||
if (!e->nr_devs) {
|
||||
prt_printf(err, "no devices in entry ");
|
||||
bch2_replicas_entry_to_text(err, e);
|
||||
return -BCH_ERR_invalid_sb_replicas;
|
||||
}
|
||||
|
||||
if (e->nr_required > 1 &&
|
||||
e->nr_required >= e->nr_devs) {
|
||||
prt_printf(err, "bad nr_required in entry ");
|
||||
bch2_replicas_entry_to_text(err, e);
|
||||
return -BCH_ERR_invalid_sb_replicas;
|
||||
}
|
||||
|
||||
for (j = 0; j < e->nr_devs; j++)
|
||||
if (!bch2_dev_exists(sb, e->devs[j])) {
|
||||
prt_printf(err, "invalid device %u in entry ", e->devs[j]);
|
||||
bch2_replicas_entry_to_text(err, e);
|
||||
return -BCH_ERR_invalid_sb_replicas;
|
||||
}
|
||||
int ret = bch2_replicas_entry_validate(e, sb, err);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (i + 1 < cpu_r->nr) {
|
||||
struct bch_replicas_entry *n =
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
void bch2_replicas_entry_sort(struct bch_replicas_entry *);
|
||||
void bch2_replicas_entry_to_text(struct printbuf *,
|
||||
struct bch_replicas_entry *);
|
||||
int bch2_replicas_entry_validate(struct bch_replicas_entry *,
|
||||
struct bch_sb *, struct printbuf *);
|
||||
void bch2_cpu_replicas_to_text(struct printbuf *, struct bch_replicas_cpu *);
|
||||
|
||||
static inline struct bch_replicas_entry *
|
||||
|
|
Loading…
Add table
Reference in a new issue