Skip to content

Commit

Permalink
bcachefs: Fix shift-by-64 in bch2_bkey_format_validate()
Browse files Browse the repository at this point in the history
We need to ensure that packed formats can't represent fields larger than
the unpacked format, which is a bit tricky since the calculations can
also overflow a u64. This patch fixes a shift and simplifies the overall
calculations.

Signed-off-by: Kent Overstreet <[email protected]>
  • Loading branch information
koverstreet committed Jun 24, 2021
1 parent ca3cfad commit cec8dcc
Showing 1 changed file with 10 additions and 10 deletions.
20 changes: 10 additions & 10 deletions fs/bcachefs/bkey.c
Original file line number Diff line number Diff line change
Expand Up @@ -620,22 +620,22 @@ const char *bch2_bkey_format_validate(struct bkey_format *f)
if (f->nr_fields != BKEY_NR_FIELDS)
return "incorrect number of fields";

/*
* Verify that the packed format can't represent fields larger than the
* unpacked format:
*/
for (i = 0; i < f->nr_fields; i++) {
unsigned unpacked_bits = bch2_bkey_format_current.bits_per_field[i];
u64 unpacked_mask = ~((~0ULL << 1) << (unpacked_bits - 1));
u64 unpacked_max = ~((~0ULL << 1) << (unpacked_bits - 1));
u64 packed_max = f->bits_per_field[i]
? ~((~0ULL << 1) << (f->bits_per_field[i] - 1))
: 0;
u64 field_offset = le64_to_cpu(f->field_offset[i]);

if (f->bits_per_field[i] > unpacked_bits)
if (packed_max + field_offset < packed_max ||
packed_max + field_offset > unpacked_max)
return "field too large";

if ((f->bits_per_field[i] == unpacked_bits) && field_offset)
return "offset + bits overflow";

if (((field_offset + ((1ULL << f->bits_per_field[i]) - 1)) &
unpacked_mask) <
field_offset)
return "offset + bits overflow";

bits += f->bits_per_field[i];
}

Expand Down

0 comments on commit cec8dcc

Please sign in to comment.