summaryrefslogtreecommitdiffstats
path: root/fs/bcachefs/bkey.c
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2021-06-24 13:19:25 -0400
committerKent Overstreet <kent.overstreet@linux.dev>2023-10-22 17:09:07 -0400
commitfdc6b08451167bfc1ae260b252ad2bf2f9735f50 (patch)
tree59a1d016ed2255d877644b257d64ba9a54268be5 /fs/bcachefs/bkey.c
parent78d66ab1ca541ba95a9ad89780466398b348c230 (diff)
downloadlinux-fdc6b08451167bfc1ae260b252ad2bf2f9735f50.tar.gz
linux-fdc6b08451167bfc1ae260b252ad2bf2f9735f50.tar.bz2
linux-fdc6b08451167bfc1ae260b252ad2bf2f9735f50.zip
bcachefs: Fix shift-by-64 in bch2_bkey_format_validate()
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 <kent.overstreet@gmail.com>
Diffstat (limited to 'fs/bcachefs/bkey.c')
-rw-r--r--fs/bcachefs/bkey.c20
1 files changed, 10 insertions, 10 deletions
diff --git a/fs/bcachefs/bkey.c b/fs/bcachefs/bkey.c
index 5de88a93f33f..3e62eeb6774e 100644
--- a/fs/bcachefs/bkey.c
+++ b/fs/bcachefs/bkey.c
@@ -623,22 +623,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];
}