]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
boot: allow BCD fields to end at buffer limit
authordongshengyuan <545258830@qq.com>
Tue, 14 Jul 2026 10:52:04 +0000 (18:52 +0800)
committerdongshengyuan <545258830@qq.com>
Tue, 14 Jul 2026 10:52:04 +0000 (18:52 +0800)
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.

src/boot/bcd.c
src/boot/test-bcd.c

index 4533d479c1470bffbdaeb4a0a986b93c5b322f34..67736d9483bb32b037f1797d0a19057e98d1caef 100644 (file)
@@ -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)
index 27102c236b8abce6619a0b2b12984ec59fd8da5f..d6e307b6ecf2622564588cfd8cbbdad9a9cbdc65 100644 (file)
@@ -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;