Commit d5bd3787 authored by Kent Overstreet's avatar Kent Overstreet

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: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent bbc3a460
...@@ -210,6 +210,7 @@ ...@@ -210,6 +210,7 @@
x(BCH_ERR_invalid_sb, invalid_sb_members) \ x(BCH_ERR_invalid_sb, invalid_sb_members) \
x(BCH_ERR_invalid_sb, invalid_sb_disk_groups) \ x(BCH_ERR_invalid_sb, invalid_sb_disk_groups) \
x(BCH_ERR_invalid_sb, invalid_sb_replicas) \ 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) \
x(BCH_ERR_invalid_sb, invalid_sb_journal_seq_blacklist) \ x(BCH_ERR_invalid_sb, invalid_sb_journal_seq_blacklist) \
x(BCH_ERR_invalid_sb, invalid_sb_crypt) \ x(BCH_ERR_invalid_sb, invalid_sb_crypt) \
......
...@@ -547,6 +547,7 @@ static int journal_entry_data_usage_validate(struct bch_fs *c, ...@@ -547,6 +547,7 @@ static int journal_entry_data_usage_validate(struct bch_fs *c,
struct jset_entry_data_usage *u = struct jset_entry_data_usage *u =
container_of(entry, struct jset_entry_data_usage, entry); container_of(entry, struct jset_entry_data_usage, entry);
unsigned bytes = jset_u64s(le16_to_cpu(entry->u64s)) * sizeof(u64); unsigned bytes = jset_u64s(le16_to_cpu(entry->u64s)) * sizeof(u64);
struct printbuf err = PRINTBUF;
int ret = 0; int ret = 0;
if (journal_entry_err_on(bytes < sizeof(*u) || if (journal_entry_err_on(bytes < sizeof(*u) ||
...@@ -555,10 +556,19 @@ static int journal_entry_data_usage_validate(struct bch_fs *c, ...@@ -555,10 +556,19 @@ static int journal_entry_data_usage_validate(struct bch_fs *c,
journal_entry_data_usage_bad_size, journal_entry_data_usage_bad_size,
"invalid journal entry usage: bad size")) { "invalid journal entry usage: bad size")) {
journal_entry_null_range(entry, vstruct_next(entry)); 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: fsck_err:
printbuf_exit(&err);
return ret; return ret;
} }
......
...@@ -68,6 +68,33 @@ void bch2_replicas_entry_to_text(struct printbuf *out, ...@@ -68,6 +68,33 @@ void bch2_replicas_entry_to_text(struct printbuf *out,
prt_printf(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, void bch2_cpu_replicas_to_text(struct printbuf *out,
struct bch_replicas_cpu *r) struct bch_replicas_cpu *r)
{ {
...@@ -163,7 +190,8 @@ void bch2_devlist_to_replicas(struct bch_replicas_entry *e, ...@@ -163,7 +190,8 @@ void bch2_devlist_to_replicas(struct bch_replicas_entry *e,
} }
static struct bch_replicas_cpu 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) struct bch_replicas_entry *new_entry)
{ {
unsigned i; unsigned i;
...@@ -173,6 +201,9 @@ cpu_replicas_add_entry(struct bch_replicas_cpu *old, ...@@ -173,6 +201,9 @@ cpu_replicas_add_entry(struct bch_replicas_cpu *old,
replicas_entry_bytes(new_entry)), 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); BUG_ON(!new_entry->data_type);
verify_replicas_entry(new_entry); verify_replicas_entry(new_entry);
...@@ -382,7 +413,7 @@ static int bch2_mark_replicas_slowpath(struct bch_fs *c, ...@@ -382,7 +413,7 @@ static int bch2_mark_replicas_slowpath(struct bch_fs *c,
if (c->replicas_gc.entries && if (c->replicas_gc.entries &&
!__replicas_has_entry(&c->replicas_gc, new_entry)) { !__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) { if (!new_gc.entries) {
ret = -BCH_ERR_ENOMEM_cpu_replicas; ret = -BCH_ERR_ENOMEM_cpu_replicas;
goto err; goto err;
...@@ -390,7 +421,7 @@ static int bch2_mark_replicas_slowpath(struct bch_fs *c, ...@@ -390,7 +421,7 @@ static int bch2_mark_replicas_slowpath(struct bch_fs *c,
} }
if (!__replicas_has_entry(&c->replicas, new_entry)) { 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) { if (!new_r.entries) {
ret = -BCH_ERR_ENOMEM_cpu_replicas; ret = -BCH_ERR_ENOMEM_cpu_replicas;
goto err; goto err;
...@@ -598,7 +629,7 @@ int bch2_replicas_set_usage(struct bch_fs *c, ...@@ -598,7 +629,7 @@ int bch2_replicas_set_usage(struct bch_fs *c,
if (idx < 0) { if (idx < 0) {
struct bch_replicas_cpu n; 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) if (!n.entries)
return -BCH_ERR_ENOMEM_cpu_replicas; return -BCH_ERR_ENOMEM_cpu_replicas;
...@@ -797,7 +828,7 @@ static int bch2_cpu_replicas_validate(struct bch_replicas_cpu *cpu_r, ...@@ -797,7 +828,7 @@ static int bch2_cpu_replicas_validate(struct bch_replicas_cpu *cpu_r,
struct bch_sb *sb, struct bch_sb *sb,
struct printbuf *err) struct printbuf *err)
{ {
unsigned i, j; unsigned i;
sort_cmp_size(cpu_r->entries, sort_cmp_size(cpu_r->entries,
cpu_r->nr, cpu_r->nr,
...@@ -808,31 +839,9 @@ static int bch2_cpu_replicas_validate(struct bch_replicas_cpu *cpu_r, ...@@ -808,31 +839,9 @@ static int bch2_cpu_replicas_validate(struct bch_replicas_cpu *cpu_r,
struct bch_replicas_entry *e = struct bch_replicas_entry *e =
cpu_replicas_entry(cpu_r, i); cpu_replicas_entry(cpu_r, i);
if (e->data_type >= BCH_DATA_NR) { int ret = bch2_replicas_entry_validate(e, sb, err);
prt_printf(err, "invalid data type in entry "); if (ret)
bch2_replicas_entry_to_text(err, e); return ret;
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;
}
if (i + 1 < cpu_r->nr) { if (i + 1 < cpu_r->nr) {
struct bch_replicas_entry *n = struct bch_replicas_entry *n =
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
void bch2_replicas_entry_sort(struct bch_replicas_entry *); void bch2_replicas_entry_sort(struct bch_replicas_entry *);
void bch2_replicas_entry_to_text(struct printbuf *, void bch2_replicas_entry_to_text(struct printbuf *,
struct bch_replicas_entry *); 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 *); void bch2_cpu_replicas_to_text(struct printbuf *, struct bch_replicas_cpu *);
static inline struct bch_replicas_entry * static inline struct bch_replicas_entry *
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment