diff --git a/fs/bcachefs/sb-members.c b/fs/bcachefs/sb-members.c index 77809ee23c45..114656155ec5 100644 --- a/fs/bcachefs/sb-members.c +++ b/fs/bcachefs/sb-members.c @@ -64,6 +64,12 @@ struct bch_member *bch2_members_v2_get_mut(struct bch_sb *sb, int i) static struct bch_member members_v2_get(struct bch_sb_field_members_v2 *mi, int i) { struct bch_member ret, *p = __bch2_members_v2_get_mut(mi, i); + size_t array_size = le32_to_cpu(mi->field.u64s) * 8 - 16; + size_t member_bytes = le16_to_cpu(mi->member_bytes); + if (i < 0 || (member_bytes && i >= array_size / member_bytes)) { + memset(&ret, 0, sizeof(ret)); + return ret; + } memset(&ret, 0, sizeof(ret)); memcpy(&ret, p, min_t(size_t, le16_to_cpu(mi->member_bytes), sizeof(ret))); return ret; @@ -335,9 +341,17 @@ static void bch2_sb_members_v2_to_text(struct printbuf *out, struct bch_sb *sb, { struct bch_sb_field_members_v2 *mi = field_to_type(f, members_v2); struct bch_sb_field_disk_groups *gi = bch2_sb_field_get(sb, disk_groups); - unsigned i; + int nr = (vstruct_end(&mi->field) - (void *)&gi->entries[0]) / le16_to_cpu(mi->member_bytes); - for (i = 0; i < sb->nr_devices; i++) + if (nr != sb->nr_devices) + prt_printf(out, "nr_devices mismatch: have %i entries, should be %u", nr, sb->nr_devices); + + /* + * We call to_text() on superblock sections that haven't passed + * validate, so we can't trust sb->nr_devices. + */ + + for (int i = 0; i < nr; i++) member_to_text(out, members_v2_get(mi, i), gi, sb, i); }