From: dongshengyuan <545258830@qq.com> Date: Tue, 14 Jul 2026 10:52:04 +0000 (+0800) Subject: boot: allow BCD fields to end at buffer limit X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=231857cfe8da749925ee2beb1352e74fa96f1372;p=thirdparty%2Fsystemd.git 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: aa1d0f25873f737fb9306a12f9283872012f2d9a. --- diff --git a/src/boot/bcd.c b/src/boot/bcd.c index 4533d479c14..67736d9483b 100644 --- a/src/boot/bcd.c +++ b/src/boot/bcd.c @@ -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) diff --git a/src/boot/test-bcd.c b/src/boot/test-bcd.c index 27102c236b8..d6e307b6ecf 100644 --- a/src/boot/test-bcd.c +++ b/src/boot/test-bcd.c @@ -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;