Skip to content

Commit

Permalink
bcachefs: Fix shift-by-64 in bformat_needs_redo()
Browse files Browse the repository at this point in the history
Ancient versions of bcachefs produced packed formats that could
represent keys that our in memory format cannot represent;
bformat_needs_redo() has some tricky shifts to check for this sort of
overflow.

Reported-by: syzbot+594427aebfefeebe91c6@syzkaller.appspotmail.com
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
  • Loading branch information
Kent Overstreet committed May 6, 2024
1 parent 2bb9600 commit 0ec5b3b
Showing 1 changed file with 14 additions and 8 deletions.
22 changes: 14 additions & 8 deletions fs/bcachefs/move.c
Original file line number Diff line number Diff line change
Expand Up @@ -968,24 +968,30 @@ static bool migrate_btree_pred(struct bch_fs *c, void *arg,
return migrate_pred(c, arg, bkey_i_to_s_c(&b->key), io_opts, data_opts);
}

/*
* Ancient versions of bcachefs produced packed formats which could represent
* keys that the in memory format cannot represent; this checks for those
* formats so we can get rid of them.
*/
static bool bformat_needs_redo(struct bkey_format *f)
{
unsigned i;

for (i = 0; i < f->nr_fields; i++) {
for (unsigned i = 0; i < f->nr_fields; i++) {
unsigned f_bits = f->bits_per_field[i];
unsigned unpacked_bits = bch2_bkey_format_current.bits_per_field[i];
u64 unpacked_mask = ~((~0ULL << 1) << (unpacked_bits - 1));
u64 field_offset = le64_to_cpu(f->field_offset[i]);

if (f->bits_per_field[i] > unpacked_bits)
if (f_bits > unpacked_bits)
return true;

if ((f->bits_per_field[i] == unpacked_bits) && field_offset)
if ((f_bits == unpacked_bits) && field_offset)
return true;

if (((field_offset + ((1ULL << f->bits_per_field[i]) - 1)) &
unpacked_mask) <
field_offset)
u64 f_mask = f_bits
? ~((~0ULL << (f_bits - 1)) << 1)
: 0;

if (((field_offset + f_mask) & unpacked_mask) < field_offset)
return true;
}

Expand Down

0 comments on commit 0ec5b3b

Please sign in to comment.