boot: allow BCD fields to end at buffer limit
Allow offset + len == max; the range ends exactly at the buffer boundary.
Keep the overflow-safe bounds check and cover the edge case in test-bcd.
Follow-up for: aa1d0f2587.
This commit is contained in:
+9
-7
@@ -93,15 +93,17 @@ assert_cc(offsetof(KeyValue, data_offset) == 8);
|
||||
assert_cc(offsetof(KeyValue, data_type) == 12);
|
||||
assert_cc(offsetof(KeyValue, name) == 20);
|
||||
|
||||
#define BAD_OFFSET(offset, len, max) \
|
||||
((uint64_t) (offset) + (len) >= (max))
|
||||
static bool bad_offset(uint64_t offset, uint64_t len, uint64_t max) {
|
||||
return offset > max || len > max - offset;
|
||||
}
|
||||
|
||||
#define BAD_STRUCT(type, offset, max) \
|
||||
((uint64_t) (offset) + sizeof(type) >= (max))
|
||||
bad_offset(offset, sizeof(type), max)
|
||||
|
||||
#define BAD_ARRAY(type, array, offset, array_len, max) \
|
||||
((uint64_t) (offset) + offsetof(type, array) + \
|
||||
sizeof((type){}.array[0]) * (uint64_t) (array_len) >= (max))
|
||||
bad_offset(offset, \
|
||||
offsetof(type, array) + sizeof((type){}.array[0]) * (uint64_t) (array_len), \
|
||||
max)
|
||||
|
||||
static const Key *get_key(const uint8_t *bcd, uint32_t bcd_len, uint32_t offset, const char *name);
|
||||
|
||||
@@ -167,7 +169,7 @@ static const KeyValue *get_key_value(const uint8_t *bcd, uint32_t bcd_len, const
|
||||
if (key->n_key_values == 0)
|
||||
return NULL;
|
||||
|
||||
if (BAD_OFFSET(key->key_values_offset, sizeof(uint32_t) * (uint64_t) key->n_key_values, bcd_len) ||
|
||||
if (bad_offset(key->key_values_offset, sizeof(uint32_t) * (uint64_t) key->n_key_values, bcd_len) ||
|
||||
(uintptr_t) (bcd + key->key_values_offset) % alignof(uint32_t) != 0)
|
||||
return NULL;
|
||||
|
||||
@@ -191,7 +193,7 @@ static const KeyValue *get_key_value(const uint8_t *bcd, uint32_t bcd_len, const
|
||||
if (FLAGS_SET(kv->data_size, UINT32_C(1) << 31))
|
||||
continue;
|
||||
|
||||
if (BAD_OFFSET(kv->data_offset, kv->data_size, bcd_len))
|
||||
if (bad_offset(kv->data_offset, kv->data_size, bcd_len))
|
||||
continue;
|
||||
|
||||
if (strncaseeq8(name, kv->name, kv->name_len) && strlen8(name) == kv->name_len)
|
||||
|
||||
@@ -90,6 +90,15 @@ TEST(base_block) {
|
||||
*bcd = backup;
|
||||
}
|
||||
|
||||
TEST(offset_bounds) {
|
||||
assert_se(!bad_offset(0, sizeof(Key), sizeof(Key)));
|
||||
assert_se(!BAD_STRUCT(Key, 0, sizeof(Key)));
|
||||
assert_se(!BAD_ARRAY(Key, key_name, 0, 0, sizeof(Key)));
|
||||
|
||||
assert_se(bad_offset(0, sizeof(Key) + 1, sizeof(Key)));
|
||||
assert_se(bad_offset(UINT32_MAX, 2, UINT32_MAX));
|
||||
}
|
||||
|
||||
TEST(bad_bcd) {
|
||||
size_t len;
|
||||
uint8_t *hbins;
|
||||
|
||||
Reference in New Issue
Block a user