1
0
mirror of https://github.com/systemd/systemd synced 2026-04-11 17:44:58 +02:00

Compare commits

...

5 Commits

Author SHA1 Message Date
Luca Boccassi
b3bfe6b9e1
Merge pull request #21922 from medhefgo/boot-fix
boot: More BCD parser fixes
2021-12-29 19:35:42 +00:00
Ludwig Nussel
b13a8b5b37 test: mark partition bootable
Make test suite partition bootable so nspawn can use the image directly.
Useful for local testing.

https://systemd.io/DISCOVERABLE_PARTITIONS/
2021-12-29 19:23:26 +00:00
Jan Janssen
aa1d0f2587 boot: Introduce helper macros for offset checking
This fixes a subtle sizeof overflow on 32bit machines.
2021-12-29 14:39:54 +01:00
Jan Janssen
1cadb35fd6 boot: Reject unaligned data
The data seems to be properly aligned in real BCD stores, so it
should be fine to just reject bad ones.

Fixes: #21917
2021-12-29 14:39:54 +01:00
Jan Janssen
77fcf28cb8 boot: Build BCD parser only on arches supported by Windows 2021-12-29 14:39:54 +01:00
4 changed files with 38 additions and 20 deletions

View File

@ -112,20 +112,30 @@ assert_cc(offsetof(KeyValue, data_offset) == 8);
assert_cc(offsetof(KeyValue, data_type) == 12); assert_cc(offsetof(KeyValue, data_type) == 12);
assert_cc(offsetof(KeyValue, name) == 20); assert_cc(offsetof(KeyValue, name) == 20);
#define BAD_OFFSET(offset, len, max) \
((UINT64) (offset) + (len) >= (max))
#define BAD_STRUCT(type, offset, max) \
((UINT64) (offset) + sizeof(type) >= (max))
#define BAD_ARRAY(type, array, offset, array_len, max) \
((UINT64) (offset) + offsetof(type, array) + \
sizeof((type){}.array[0]) * (UINT64) (array_len) >= (max))
static const Key *get_key(const UINT8 *bcd, UINT32 bcd_len, UINT32 offset, const CHAR8 *name); static const Key *get_key(const UINT8 *bcd, UINT32 bcd_len, UINT32 offset, const CHAR8 *name);
static const Key *get_subkey(const UINT8 *bcd, UINT32 bcd_len, UINT32 offset, const CHAR8 *name) { static const Key *get_subkey(const UINT8 *bcd, UINT32 bcd_len, UINT32 offset, const CHAR8 *name) {
assert(bcd); assert(bcd);
assert(name); assert(name);
if ((UINT64) offset + sizeof(SubkeyFast) >= bcd_len) if (BAD_STRUCT(SubkeyFast, offset, bcd_len))
return NULL; return NULL;
const SubkeyFast *subkey = (const SubkeyFast *) (bcd + offset); const SubkeyFast *subkey = (const SubkeyFast *) (bcd + offset);
if (subkey->sig != SIG_SUBKEY_FAST) if (subkey->sig != SIG_SUBKEY_FAST)
return NULL; return NULL;
if ((UINT64) offset + offsetof(SubkeyFast, entries) + sizeof(struct SubkeyFastEntry[subkey->n_entries]) >= bcd_len) if (BAD_ARRAY(SubkeyFast, entries, offset, subkey->n_entries, bcd_len))
return NULL; return NULL;
for (UINT16 i = 0; i < subkey->n_entries; i++) { for (UINT16 i = 0; i < subkey->n_entries; i++) {
@ -147,14 +157,14 @@ static const Key *get_key(const UINT8 *bcd, UINT32 bcd_len, UINT32 offset, const
assert(bcd); assert(bcd);
assert(name); assert(name);
if ((UINT64) offset + sizeof(Key) >= bcd_len) if (BAD_STRUCT(Key, offset, bcd_len))
return NULL; return NULL;
const Key *key = (const Key *) (bcd + offset); const Key *key = (const Key *) (bcd + offset);
if (key->sig != SIG_KEY) if (key->sig != SIG_KEY)
return NULL; return NULL;
if ((UINT64) offset + offsetof(Key, key_name) + sizeof(CHAR8[key->key_name_len]) >= bcd_len) if (BAD_ARRAY(Key, key_name, offset, key->key_name_len, bcd_len))
return NULL; return NULL;
if (*name) { if (*name) {
@ -176,21 +186,22 @@ static const KeyValue *get_key_value(const UINT8 *bcd, UINT32 bcd_len, const Key
if (key->n_key_values == 0) if (key->n_key_values == 0)
return NULL; return NULL;
if ((UINT64) key->key_values_offset + sizeof(UINT32[key->n_key_values]) >= bcd_len) if (BAD_OFFSET(key->key_values_offset, sizeof(UINT32) * (UINT64) key->n_key_values, bcd_len) ||
(UINTN)(bcd + key->key_values_offset) % sizeof(UINT32) != 0)
return NULL; return NULL;
const UINT32 *key_value_list = (const UINT32 *) (bcd + key->key_values_offset); const UINT32 *key_value_list = (const UINT32 *) (bcd + key->key_values_offset);
for (UINT32 i = 0; i < key->n_key_values; i++) { for (UINT32 i = 0; i < key->n_key_values; i++) {
UINT32 offset = *(key_value_list + i); UINT32 offset = *(key_value_list + i);
if ((UINT64) offset + sizeof(KeyValue) >= bcd_len) if (BAD_STRUCT(KeyValue, offset, bcd_len))
continue; continue;
const KeyValue *kv = (const KeyValue *) (bcd + offset); const KeyValue *kv = (const KeyValue *) (bcd + offset);
if (kv->sig != SIG_KEY_VALUE) if (kv->sig != SIG_KEY_VALUE)
continue; continue;
if ((UINT64) offset + offsetof(KeyValue, name) + kv->name_len >= bcd_len) if (BAD_ARRAY(KeyValue, name, offset, kv->name_len, bcd_len))
continue; continue;
/* If most significant bit is set, data is stored in data_offset itself, but /* If most significant bit is set, data is stored in data_offset itself, but
@ -199,7 +210,7 @@ static const KeyValue *get_key_value(const UINT8 *bcd, UINT32 bcd_len, const Key
if (FLAGS_SET(kv->data_size, UINT32_C(1) << 31)) if (FLAGS_SET(kv->data_size, UINT32_C(1) << 31))
continue; continue;
if ((UINT64) kv->data_offset + kv->data_size >= bcd_len) if (BAD_OFFSET(kv->data_offset, kv->data_size, bcd_len))
continue; continue;
if (strncaseeqa(name, kv->name, kv->name_len) && strlena(name) == kv->name_len) if (strncaseeqa(name, kv->name, kv->name_len) && strlena(name) == kv->name_len)
@ -266,7 +277,8 @@ TEST_STATIC CHAR16 *get_bcd_title(UINT8 *bcd, UINTN bcd_len) {
CHAR8 order_guid[sizeof("{00000000-0000-0000-0000-000000000000}\0")]; CHAR8 order_guid[sizeof("{00000000-0000-0000-0000-000000000000}\0")];
if (displayorder_value->data_type != REG_MULTI_SZ || if (displayorder_value->data_type != REG_MULTI_SZ ||
displayorder_value->data_size != sizeof(CHAR16) * sizeof(order_guid)) displayorder_value->data_size != sizeof(CHAR16[sizeof(order_guid)]) ||
(UINTN)(bcd + displayorder_value->data_offset) % sizeof(CHAR16) != 0)
/* BCD is multi-boot. */ /* BCD is multi-boot. */
return NULL; return NULL;
@ -312,7 +324,8 @@ TEST_STATIC CHAR16 *get_bcd_title(UINT8 *bcd, UINTN bcd_len) {
if (description_value->data_type != REG_SZ || if (description_value->data_type != REG_SZ ||
description_value->data_size < sizeof(CHAR16) || description_value->data_size < sizeof(CHAR16) ||
description_value->data_size % sizeof(CHAR16) != 0) description_value->data_size % sizeof(CHAR16) != 0 ||
(UINTN)(bcd + description_value->data_offset) % sizeof(CHAR16))
return NULL; return NULL;
/* The data should already be NUL-terminated. */ /* The data should already be NUL-terminated. */

View File

@ -1941,6 +1941,7 @@ static void config_entry_add_osx(Config *config) {
} }
static void config_entry_add_windows(Config *config, EFI_HANDLE *device, EFI_FILE *root_dir) { static void config_entry_add_windows(Config *config, EFI_HANDLE *device, EFI_FILE *root_dir) {
#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
_cleanup_freepool_ CHAR8 *bcd = NULL; _cleanup_freepool_ CHAR8 *bcd = NULL;
CHAR16 *title = NULL; CHAR16 *title = NULL;
EFI_STATUS err; EFI_STATUS err;
@ -1961,6 +1962,7 @@ static void config_entry_add_windows(Config *config, EFI_HANDLE *device, EFI_FIL
config_entry_add_loader_auto(config, device, root_dir, NULL, config_entry_add_loader_auto(config, device, root_dir, NULL,
L"auto-windows", 'w', title ?: L"Windows Boot Manager", L"auto-windows", 'w', title ?: L"Windows Boot Manager",
L"\\EFI\\Microsoft\\Boot\\bootmgfw.efi"); L"\\EFI\\Microsoft\\Boot\\bootmgfw.efi");
#endif
} }
static void config_entry_add_linux( static void config_entry_add_linux(

View File

@ -331,7 +331,6 @@ common_sources = [
'util.c'] 'util.c']
systemd_boot_sources = [ systemd_boot_sources = [
'bcd.c',
'boot.c', 'boot.c',
'console.c', 'console.c',
'drivers.c', 'drivers.c',
@ -351,6 +350,18 @@ else
stub_sources += 'linux.c' stub_sources += 'linux.c'
endif endif
# BCD parser only makes sense on arches that Windows supports.
if efi_arch[1] in ['ia32', 'x86_64', 'arm', 'aarch64']
systemd_boot_sources += 'bcd.c'
tests += [
[['src/boot/efi/test-bcd.c'],
[],
[libzstd],
[],
'HAVE_ZSTD'],
]
endif
systemd_boot_objects = [] systemd_boot_objects = []
stub_objects = [] stub_objects = []
foreach file : fundamental_source_paths + common_sources + systemd_boot_sources + stub_sources foreach file : fundamental_source_paths + common_sources + systemd_boot_sources + stub_sources
@ -407,14 +418,6 @@ endforeach
############################################################ ############################################################
tests += [
[['src/boot/efi/test-bcd.c'],
[],
[libzstd],
[],
'HAVE_ZSTD'],
]
test_efi_disk_img = custom_target( test_efi_disk_img = custom_target(
'test-efi-disk.img', 'test-efi-disk.img',
input : [efi_stubs[0][0], efi_stubs[1][1]], input : [efi_stubs[0][0], efi_stubs[1][1]],

View File

@ -1238,7 +1238,7 @@ create_empty_image() {
LOOPDEV=$(losetup --show -P -f "$IMAGE_PUBLIC") LOOPDEV=$(losetup --show -P -f "$IMAGE_PUBLIC")
[ -b "$LOOPDEV" ] || return 1 [ -b "$LOOPDEV" ] || return 1
sfdisk "$LOOPDEV" <<EOF sfdisk "$LOOPDEV" <<EOF
,$((size - 50))M ,$((size - 50))M,L,*
, ,
EOF EOF