1
0
mirror of https://github.com/systemd/systemd.git synced 2025-03-31 14:50:15 +03:00

Merge pull request #21614 from medhefgo/boot-bcd

boot: Add BCD store parser
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2021-12-12 09:18:26 +01:00 committed by GitHub
commit 6d7bc744ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 550 additions and 62 deletions

View File

@ -1676,8 +1676,14 @@ conf.set10('ENABLE_TIMEDATECTL', get_option('timedated') or get_option('timesync
conf.set10('SYSTEMD_SLOW_TESTS_DEFAULT', slow_tests)
#####################################################################
############################################################
tests = []
fuzzers = []
############################################################
# Include these now as they provide gnu-efi detection.
subdir('src/fundamental')
subdir('src/boot/efi')
@ -1695,7 +1701,7 @@ update_syscall_tables_sh = find_program('tools/update-syscall-tables.sh')
xml_helper_py = find_program('tools/xml_helper.py')
export_dbus_interfaces_py = find_program('tools/dbus_exporter.py')
#####################################################################
############################################################
config_h = configure_file(
output : 'config.h',
@ -1716,9 +1722,6 @@ if dbus_interfaces_dir == ''
dbus_interfaces_dir = get_option('datadir') + '/dbus-1'
endif
tests = []
fuzzers = []
basic_includes = include_directories(
'src/basic',
'src/fundamental',

321
src/boot/efi/bcd.c Normal file
View File

@ -0,0 +1,321 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#ifdef SD_BOOT
# include <efi.h>
# include "macro-fundamental.h"
# include "util.h"
# define TEST_STATIC
#else
/* Provide our own "EFI API" if we are running as a unit test. */
# include <stddef.h>
# include <stdint.h>
# include <uchar.h>
# include "string-util-fundamental.h"
# define CHAR8 char
# define CHAR16 char16_t
# define UINT8 uint8_t
# define UINT16 uint16_t
# define UINT32 uint32_t
# define UINT64 uint64_t
# define UINTN size_t
# define strncaseeqa(a, b, n) strncaseeq((a), (b), (n))
# define TEST_STATIC static
#endif
enum {
SIG_BASE_BLOCK = 1718052210, /* regf */
SIG_KEY = 27502, /* nk */
SIG_SUBKEY_FAST = 26220, /* lf */
SIG_KEY_VALUE = 27510, /* vk */
};
enum {
REG_SZ = 1,
REG_MULTI_SZ = 7,
};
/* These structs contain a lot more members than we care for. They have all
* been squashed into _padN for our convenience. */
typedef struct {
UINT32 sig;
UINT32 primary_seqnum;
UINT32 secondary_seqnum;
UINT64 _pad1;
UINT32 version_major;
UINT32 version_minor;
UINT32 type;
UINT32 _pad2;
UINT32 root_cell_offset;
UINT64 _pad3[507];
} _packed_ BaseBlock;
assert_cc(sizeof(BaseBlock) == 4096);
assert_cc(offsetof(BaseBlock, sig) == 0);
assert_cc(offsetof(BaseBlock, primary_seqnum) == 4);
assert_cc(offsetof(BaseBlock, secondary_seqnum) == 8);
assert_cc(offsetof(BaseBlock, version_major) == 20);
assert_cc(offsetof(BaseBlock, version_minor) == 24);
assert_cc(offsetof(BaseBlock, type) == 28);
assert_cc(offsetof(BaseBlock, root_cell_offset) == 36);
/* All offsets are relative to the base block and technically point to a hive
* cell struct. But for our usecase we don't need to bother about that one,
* so skip over the cell_size UINT32. */
#define HIVE_CELL_OFFSET (sizeof(BaseBlock) + 4)
typedef struct {
UINT16 sig;
UINT16 _pad1[13];
UINT32 subkeys_offset;
UINT32 _pad2;
UINT32 n_key_values;
UINT32 key_values_offset;
UINT32 _pad3[7];
UINT16 key_name_len;
UINT16 _pad4;
CHAR8 key_name[];
} _packed_ Key;
assert_cc(offsetof(Key, sig) == 0);
assert_cc(offsetof(Key, subkeys_offset) == 28);
assert_cc(offsetof(Key, n_key_values) == 36);
assert_cc(offsetof(Key, key_values_offset) == 40);
assert_cc(offsetof(Key, key_name_len) == 72);
assert_cc(offsetof(Key, key_name) == 76);
typedef struct {
UINT16 sig;
UINT16 n_entries;
struct SubkeyFastEntry {
UINT32 key_offset;
CHAR8 name_hint[4];
} _packed_ entries[];
} _packed_ SubkeyFast;
assert_cc(offsetof(SubkeyFast, sig) == 0);
assert_cc(offsetof(SubkeyFast, n_entries) == 2);
assert_cc(offsetof(SubkeyFast, entries) == 4);
typedef struct {
UINT16 sig;
UINT16 name_len;
UINT32 data_size;
UINT32 data_offset;
UINT32 data_type;
UINT32 _pad;
CHAR8 name[];
} _packed_ KeyValue;
assert_cc(offsetof(KeyValue, sig) == 0);
assert_cc(offsetof(KeyValue, name_len) == 2);
assert_cc(offsetof(KeyValue, data_size) == 4);
assert_cc(offsetof(KeyValue, data_offset) == 8);
assert_cc(offsetof(KeyValue, data_type) == 12);
assert_cc(offsetof(KeyValue, name) == 20);
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) {
assert(bcd);
assert(name);
if ((UINT64) offset + sizeof(SubkeyFast) > bcd_len)
return NULL;
const SubkeyFast *subkey = (const SubkeyFast *) (bcd + offset);
if (subkey->sig != SIG_SUBKEY_FAST)
return NULL;
if ((UINT64) offset + offsetof(SubkeyFast, entries) + sizeof(struct SubkeyFastEntry[subkey->n_entries]) > bcd_len)
return NULL;
for (UINT16 i = 0; i < subkey->n_entries; i++) {
if (!strncaseeqa(name, subkey->entries[i].name_hint, sizeof(subkey->entries[i].name_hint)))
continue;
const Key *key = get_key(bcd, bcd_len, subkey->entries[i].key_offset, name);
if (key)
return key;
}
return NULL;
}
/* We use NUL as registry path separators for convenience. To start from the root, begin
* name with a NUL. Name must end with two NUL. The lookup depth is not restricted, so
* name must be properly validated before calling get_key(). */
static const Key *get_key(const UINT8 *bcd, UINT32 bcd_len, UINT32 offset, const CHAR8 *name) {
assert(bcd);
assert(name);
if ((UINT64) offset + sizeof(Key) > bcd_len)
return NULL;
const Key *key = (const Key *) (bcd + offset);
if (key->sig != SIG_KEY)
return NULL;
if ((UINT64) offset + offsetof(Key, key_name) + sizeof(CHAR8[key->key_name_len]) > bcd_len)
return NULL;
if (*name) {
if (strncaseeqa(name, key->key_name, key->key_name_len) && !name[key->key_name_len])
name += key->key_name_len;
else
return NULL;
}
name++;
return *name ? get_subkey(bcd, bcd_len, key->subkeys_offset, name) : key;
}
static const KeyValue *get_key_value(const UINT8 *bcd, UINT32 bcd_len, const Key *key, const CHAR8 *name) {
assert(bcd);
assert(key);
assert(name);
if (key->n_key_values == 0)
return NULL;
if ((UINT64) key->key_values_offset + sizeof(UINT32[key->n_key_values]) > bcd_len)
return NULL;
const UINT32 *key_value_list = (const UINT32 *) (bcd + key->key_values_offset);
for (UINT32 i = 0; i < key->n_key_values; i++) {
UINT32 offset = *(key_value_list + i);
if ((UINT64) offset + sizeof(KeyValue) > bcd_len)
continue;
const KeyValue *kv = (const KeyValue *) (bcd + offset);
if (kv->sig != SIG_KEY_VALUE)
continue;
if ((UINT64) offset + offsetof(KeyValue, name) + kv->name_len > bcd_len)
continue;
/* If most significant bit is set, data is stored in data_offset itself, but
* we are only interested in UTF16 strings. The only strings that could fit
* would have just one char in it, so let's not bother with this. */
if (FLAGS_SET(kv->data_size, UINT32_C(1) << 31))
continue;
if ((UINT64) kv->data_offset + kv->data_size > bcd_len)
continue;
if (strncaseeqa(name, kv->name, kv->name_len) && !name[kv->name_len])
return kv;
}
return NULL;
}
/* The BCD store is really just a regular windows registry hive with a rather cryptic internal
* key structure. On a running system it gets mounted to HKEY_LOCAL_MACHINE\BCD00000000.
*
* Of interest to us are the these two keys:
* - \Objects\{bootmgr}\Elements\24000001
* This key is the "displayorder" property and contains a value of type REG_MULTI_SZ
* with the name "Element" that holds a {GUID} list (UTF16, NUL-separated).
* - \Objects\{GUID}\Elements\12000004
* This key is the "description" property and contains a value of type REG_SZ with the
* name "Element" that holds a NUL-terminated UTF16 string.
*
* The GUIDs and properties are as reported by "bcdedit.exe /v".
*
* To get a title for the BCD store we first look at the displayorder property of {bootmgr}
* (it always has the GUID 9dea862c-5cdd-4e70-acc1-f32b344d4795). If it contains more than
* one GUID, the BCD is multi-boot and we stop looking. Otherwise we take that GUID, look it
* up, and return its description property. */
TEST_STATIC CHAR16 *get_bcd_title(UINT8 *bcd, UINTN bcd_len) {
assert(bcd);
if (HIVE_CELL_OFFSET > bcd_len)
return NULL;
BaseBlock *base_block = (BaseBlock *) bcd;
if (base_block->sig != SIG_BASE_BLOCK ||
base_block->version_major != 1 ||
base_block->version_minor != 3 ||
base_block->type != 0 ||
base_block->primary_seqnum != base_block->secondary_seqnum)
return NULL;
bcd += HIVE_CELL_OFFSET;
bcd_len -= HIVE_CELL_OFFSET;
const Key *objects_key = get_key(
bcd, bcd_len,
base_block->root_cell_offset,
(const CHAR8 *) "\0Objects\0");
if (!objects_key)
return NULL;
const Key *displayorder_key = get_subkey(
bcd, bcd_len,
objects_key->subkeys_offset,
(const CHAR8 *) "{9dea862c-5cdd-4e70-acc1-f32b344d4795}\0Elements\00024000001\0");
if (!displayorder_key)
return NULL;
const KeyValue *displayorder_value = get_key_value(
bcd, bcd_len,
displayorder_key,
(const CHAR8 *) "Element");
if (!displayorder_value)
return NULL;
CHAR8 order_guid[sizeof("{00000000-0000-0000-0000-000000000000}\0")];
if (displayorder_value->data_type != REG_MULTI_SZ ||
displayorder_value->data_size != sizeof(CHAR16) * sizeof(order_guid))
/* BCD is multi-boot. */
return NULL;
/* Keys are stored as ASCII in registry hives if the data fits (and GUIDS always should). */
CHAR16 *order_guid_utf16 = (CHAR16 *) (bcd + displayorder_value->data_offset);
for (UINTN i = 0; i < sizeof(order_guid) - 2; i++) {
CHAR16 c = order_guid_utf16[i];
switch (c) {
case '-':
case '{':
case '}':
case '0' ... '9':
case 'a' ... 'f':
case 'A' ... 'F':
order_guid[i] = c;
break;
default:
/* Not a valid GUID. */
return NULL;
}
}
/* Our functions expect the lookup key to be double-derminated. */
order_guid[sizeof(order_guid) - 2] = '\0';
order_guid[sizeof(order_guid) - 1] = '\0';
const Key *default_key = get_subkey(bcd, bcd_len, objects_key->subkeys_offset, order_guid);
if (!default_key)
return NULL;
const Key *description_key = get_subkey(
bcd, bcd_len,
default_key->subkeys_offset,
(const CHAR8 *) "Elements\00012000004\0");
if (!description_key)
return NULL;
const KeyValue *description_value = get_key_value(
bcd, bcd_len,
description_key,
(const CHAR8 *) "Element");
if (!description_value)
return NULL;
if (description_value->data_type != REG_SZ ||
description_value->data_size < sizeof(CHAR16) ||
description_value->data_size % sizeof(CHAR16) != 0)
return NULL;
/* The data should already be NUL-terminated. */
CHAR16 *title = (CHAR16 *) (bcd + description_value->data_offset);
title[description_value->data_size / sizeof(CHAR16)] = '\0';
return title;
}

6
src/boot/efi/bcd.h Normal file
View File

@ -0,0 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <efi.h>
CHAR16 *get_bcd_title(UINT8 *bcd, UINTN bcd_len);

View File

@ -4,6 +4,7 @@
#include <efigpt.h>
#include <efilib.h>
#include "bcd.h"
#include "bootspec-fundamental.h"
#include "console.h"
#include "devicetree.h"
@ -1941,7 +1942,7 @@ static void config_entry_add_osx(Config *config) {
static void config_entry_add_windows(Config *config, EFI_HANDLE *device, EFI_FILE *root_dir) {
_cleanup_freepool_ CHAR8 *bcd = NULL;
const CHAR16 *title = NULL;
CHAR16 *title = NULL;
EFI_STATUS err;
UINTN len;
@ -1954,34 +1955,8 @@ static void config_entry_add_windows(Config *config, EFI_HANDLE *device, EFI_FIL
/* Try to find a better title. */
err = file_read(root_dir, L"\\EFI\\Microsoft\\Boot\\BCD", 0, 100*1024, &bcd, &len);
if (!EFI_ERROR(err)) {
static const CHAR16 *versions[] = {
L"Windows 11",
L"Windows 10",
L"Windows 8.1",
L"Windows 8",
L"Windows 7",
L"Windows Vista",
};
CHAR8 *p = bcd;
while (!title) {
CHAR8 *q = mempmem_safe(p, len, versions[0], STRLEN(L"Windows "));
if (!q)
break;
len -= q - p;
p = q;
/* We found the prefix, now try all the version strings. */
for (UINTN i = 0; i < ELEMENTSOF(versions); i++) {
if (memory_startswith(p, len, versions[i] + STRLEN("Windows "))) {
title = versions[i];
break;
}
}
}
}
if (!EFI_ERROR(err))
title = get_bcd_title((UINT8 *) bcd, len);
config_entry_add_loader_auto(config, device, root_dir, NULL,
L"auto-windows", 'w', title ?: L"Windows Boot Manager",

View File

@ -26,7 +26,7 @@ static EFI_STATUS tpm1_measure_to_pcr_and_event_log(
assert(description);
desc_len = StrSize(description);
tcg_event = xallocate_zero_pool(OFFSETOF(TCG_PCR_EVENT, Event) + desc_len);
tcg_event = xallocate_zero_pool(offsetof(TCG_PCR_EVENT, Event) + desc_len);
*tcg_event = (TCG_PCR_EVENT) {
.EventSize = desc_len,
.PCRIndex = pcrindex,
@ -57,9 +57,9 @@ static EFI_STATUS tpm2_measure_to_pcr_and_event_log(
assert(description);
desc_len = StrSize(description);
tcg_event = xallocate_zero_pool(OFFSETOF(EFI_TCG2_EVENT, Event) + desc_len);
tcg_event = xallocate_zero_pool(offsetof(EFI_TCG2_EVENT, Event) + desc_len);
*tcg_event = (EFI_TCG2_EVENT) {
.Size = OFFSETOF(EFI_TCG2_EVENT, Event) + desc_len,
.Size = offsetof(EFI_TCG2_EVENT, Event) + desc_len,
.Header.HeaderSize = sizeof(EFI_TCG2_EVENT_HEADER),
.Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION,
.Header.PCRIndex = pcrindex,

View File

@ -100,6 +100,7 @@ if efi_lds == ''
endif
efi_headers = files('''
bcd.h
console.h
cpio.h
devicetree.h
@ -129,6 +130,7 @@ common_sources = '''
'''.split()
systemd_boot_sources = '''
bcd.c
boot.c
console.c
drivers.c
@ -371,6 +373,14 @@ endforeach
############################################################
tests += [
[['src/boot/efi/test-bcd.c'],
[],
[libzstd],
[],
'HAVE_ZSTD'],
]
test_efi_disk_img = custom_target(
'test-efi-disk.img',
input : [efi_stubs[0][0], efi_stubs[1][1]],

View File

@ -129,7 +129,7 @@ static inline BOOLEAN verify_pe(const struct PeFileHeader *pe) {
static inline UINTN section_table_offset(const struct DosFileHeader *dos, const struct PeFileHeader *pe) {
assert(dos);
assert(pe);
return dos->ExeHeader + OFFSETOF(struct PeFileHeader, OptionalHeader) + pe->FileHeader.SizeOfOptionalHeader;
return dos->ExeHeader + offsetof(struct PeFileHeader, OptionalHeader) + pe->FileHeader.SizeOfOptionalHeader;
}
static void locate_sections(

162
src/boot/efi/test-bcd.c Normal file
View File

@ -0,0 +1,162 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "alloc-util.h"
#include "compress.h"
#include "fileio.h"
#include "tests.h"
#include "utf8.h"
/* Inlcude the implementation directly, so we can poke at some internals. */
#include "bcd.c"
static void load_bcd(const char *path, void **ret_bcd, size_t *ret_bcd_len) {
size_t len;
_cleanup_free_ char *fn = NULL, *compressed = NULL;
assert_se(get_testdata_dir(path, &fn) >= 0);
assert_se(read_full_file_full(AT_FDCWD, fn, UINT64_MAX, SIZE_MAX, 0, NULL, &compressed, &len) >= 0);
assert_se(decompress_blob_zstd(compressed, len, ret_bcd, ret_bcd_len, SIZE_MAX) >= 0);
}
static void test_get_bcd_title_one(
const char *path,
const char16_t *title_expect,
size_t title_len_expect) {
size_t len;
_cleanup_free_ void *bcd = NULL;
log_info("/* %s(%s) */", __func__, path);
load_bcd(path, &bcd, &len);
char16_t *title = get_bcd_title(bcd, len);
if (title_expect) {
assert_se(title);
assert_se(memcmp(title, title_expect, title_len_expect) == 0);
} else
assert_se(!title);
}
TEST(get_bcd_title) {
const char16_t win10[] = { 'W', 'i', 'n', 'd', 'o', 'w', 's', ' ', '1', '0', '\0' };
test_get_bcd_title_one("test-bcd/win10.bcd.zst", win10, sizeof(win10));
test_get_bcd_title_one("test-bcd/description-bad-type.bcd.zst", NULL, 0);
test_get_bcd_title_one("test-bcd/description-empty.bcd.zst", NULL, 0);
test_get_bcd_title_one("test-bcd/description-missing.bcd.zst", NULL, 0);
test_get_bcd_title_one("test-bcd/description-too-small.bcd.zst", NULL, 0);
test_get_bcd_title_one("test-bcd/displayorder-bad-name.bcd.zst", NULL, 0);
test_get_bcd_title_one("test-bcd/displayorder-bad-size.bcd.zst", NULL, 0);
test_get_bcd_title_one("test-bcd/displayorder-bad-type.bcd.zst", NULL, 0);
test_get_bcd_title_one("test-bcd/empty.bcd.zst", NULL, 0);
}
TEST(base_block) {
size_t len;
BaseBlock backup;
uint8_t *bcd_base;
_cleanup_free_ BaseBlock *bcd = NULL;
load_bcd("test-bcd/win10.bcd.zst", (void **) &bcd, &len);
backup = *bcd;
bcd_base = (uint8_t *) bcd;
assert_se(get_bcd_title(bcd_base, len));
/* Try various "corruptions" of the base block. */
assert_se(!get_bcd_title(bcd_base, sizeof(BaseBlock) - 1));
bcd->sig = 0;
assert_se(!get_bcd_title(bcd_base, len));
*bcd = backup;
bcd->version_minor = 2;
assert_se(!get_bcd_title(bcd_base, len));
*bcd = backup;
bcd->version_major = 4;
assert_se(!get_bcd_title(bcd_base, len));
*bcd = backup;
bcd->type = 1;
assert_se(!get_bcd_title(bcd_base, len));
*bcd = backup;
bcd->primary_seqnum++;
assert_se(!get_bcd_title(bcd_base, len));
*bcd = backup;
}
TEST(bad_bcd) {
size_t len;
uint8_t *hbins;
uint32_t offset;
_cleanup_free_ void *bcd = NULL;
/* This BCD hive has been manipulated to have bad offsets/sizes at various places. */
load_bcd("test-bcd/corrupt.bcd.zst", &bcd, &len);
assert_se(len >= HIVE_CELL_OFFSET);
hbins = (uint8_t *) bcd + HIVE_CELL_OFFSET;
len -= HIVE_CELL_OFFSET;
offset = ((BaseBlock *) bcd)->root_cell_offset;
const Key *root = get_key(hbins, len, offset, "\0");
assert_se(root);
assert_se(!get_key(hbins, sizeof(Key) - 1, offset, "\0"));
assert_se(!get_key(hbins, len, offset, "\0BadOffset\0"));
assert_se(!get_key(hbins, len, offset, "\0BadSig\0"));
assert_se(!get_key(hbins, len, offset, "\0BadKeyNameLen\0"));
assert_se(!get_key(hbins, len, offset, "\0SubkeyBadOffset\0Dummy\0"));
assert_se(!get_key(hbins, len, offset, "\0SubkeyBadSig\0Dummy\0"));
assert_se(!get_key(hbins, len, offset, "\0SubkeyBadNEntries\0Dummy\0"));
assert_se(!get_key_value(hbins, len, root, "Dummy"));
const Key *kv_bad_offset = get_key(hbins, len, offset, "\0KeyValuesBadOffset\0");
assert_se(kv_bad_offset);
assert_se(!get_key_value(hbins, len, kv_bad_offset, "Dummy"));
const Key *kv_bad_n_key_values = get_key(hbins, len, offset, "\0KeyValuesBadNKeyValues\0");
assert_se(kv_bad_n_key_values);
assert_se(!get_key_value(hbins, len, kv_bad_n_key_values, "Dummy"));
const Key *kv = get_key(hbins, len, offset, "\0KeyValues\0");
assert_se(kv);
assert_se(!get_key_value(hbins, len, kv, "BadOffset"));
assert_se(!get_key_value(hbins, len, kv, "BadSig"));
assert_se(!get_key_value(hbins, len, kv, "BadNameLen"));
assert_se(!get_key_value(hbins, len, kv, "InlineData"));
assert_se(!get_key_value(hbins, len, kv, "BadDataOffset"));
assert_se(!get_key_value(hbins, len, kv, "BadDataSize"));
}
TEST(argv_bcds) {
for (int i = 1; i < saved_argc; i++) {
size_t len;
_cleanup_free_ void *bcd = NULL;
assert_se(read_full_file_full(
AT_FDCWD,
saved_argv[i],
UINT64_MAX,
SIZE_MAX,
0,
NULL,
(char **) &bcd,
&len) >= 0);
char16_t *title = get_bcd_title(bcd, len);
if (title) {
_cleanup_free_ char *title_utf8 = utf16_to_utf8(title, char16_strlen(title) * 2);
log_info("%s: \"%s\"", saved_argv[i], title_utf8);
} else
log_info("%s: Bad BCD", saved_argv[i]);
}
}
DEFINE_TEST_MAIN(LOG_INFO);

View File

@ -505,20 +505,6 @@ EFI_STATUS log_oom(void) {
return EFI_OUT_OF_RESOURCES;
}
void *memmem_safe(const void *haystack, UINTN haystack_len, const void *needle, UINTN needle_len) {
assert(haystack || haystack_len == 0);
assert(needle || needle_len == 0);
if (needle_len == 0)
return (void*)haystack;
for (const CHAR8 *h = haystack, *n = needle; haystack_len >= needle_len; h++, haystack_len--)
if (*h == *n && CompareMem(h + 1, n + 1, needle_len - 1) == 0)
return (void*)h;
return NULL;
}
void print_at(UINTN x, UINTN y, UINTN attr, const CHAR16 *str) {
assert(str);
ST->ConOut->SetCursorPosition(ST->ConOut, x, y);
@ -566,7 +552,7 @@ EFI_STATUS get_file_info_harder(
EFI_FILE_INFO **ret,
UINTN *ret_size) {
UINTN size = OFFSETOF(EFI_FILE_INFO, FileName) + 256;
UINTN size = offsetof(EFI_FILE_INFO, FileName) + 256;
_cleanup_freepool_ EFI_FILE_INFO *fi = NULL;
EFI_STATUS err;
@ -610,7 +596,7 @@ EFI_STATUS readdir_harder(
* the specified buffer needs to be freed by caller, after final use. */
if (!*buffer) {
sz = OFFSETOF(EFI_FILE_INFO, FileName) /* + 256 */;
sz = offsetof(EFI_FILE_INFO, FileName) /* + 256 */;
*buffer = xallocate_pool(sz);
*buffer_size = sz;
} else
@ -649,6 +635,27 @@ UINTN strnlena(const CHAR8 *p, UINTN maxlen) {
return c;
}
INTN strncasecmpa(const CHAR8 *a, const CHAR8 *b, UINTN maxlen) {
if (!a || !b)
return CMP(a, b);
while (maxlen > 0) {
CHAR8 ca = *a, cb = *b;
if (ca >= 'A' && ca <= 'Z')
ca += 'a' - 'A';
if (cb >= 'A' && cb <= 'Z')
cb += 'a' - 'A';
if (!ca || ca != cb)
return ca - cb;
a++;
b++;
maxlen--;
}
return 0;
}
CHAR8 *xstrndup8(const CHAR8 *p, UINTN sz) {
CHAR8 *n;

View File

@ -13,7 +13,7 @@
/* This TPM PCR is where most Linux infrastructure extends the initrd binary images into, and so do we. */
#define TPM_PCR_INDEX_INITRD 4
#define OFFSETOF(x,y) __builtin_offsetof(x,y)
#define offsetof(type, member) __builtin_offsetof(type, member)
#define UINTN_MAX (~(UINTN)0)
#define INTN_MAX ((INTN)(UINTN_MAX>>1))
@ -111,13 +111,6 @@ EFI_STATUS log_oom(void);
err; \
})
void *memmem_safe(const void *haystack, UINTN haystack_len, const void *needle, UINTN needle_len);
static inline void *mempmem_safe(const void *haystack, UINTN haystack_len, const void *needle, UINTN needle_len) {
CHAR8 *p = memmem_safe(haystack, haystack_len, needle, needle_len);
return p ? p + needle_len : NULL;
}
void print_at(UINTN x, UINTN y, UINTN attr, const CHAR16 *str);
void clear_screen(UINTN attr);
@ -130,6 +123,10 @@ EFI_STATUS readdir_harder(EFI_FILE_HANDLE handle, EFI_FILE_INFO **buffer, UINTN
UINTN strnlena(const CHAR8 *p, UINTN maxlen);
CHAR8 *xstrndup8(const CHAR8 *p, UINTN sz);
INTN strncasecmpa(const CHAR8 *a, const CHAR8 *b, UINTN maxlen);
static inline BOOLEAN strncaseeqa(const CHAR8 *a, const CHAR8 *b, UINTN maxlen) {
return strncasecmpa(a, b, maxlen) == 0;
}
BOOLEAN is_ascii(const CHAR16 *f);

View File

@ -67,6 +67,11 @@ if install_tests
'../-.mount',
testsuite08_dir + '/local-fs.target.wants/-.mount')
if conf.get('HAVE_GNU_EFI') == 1 and conf.get('HAVE_ZSTD') == 1
install_subdir('test-bcd',
exclude_files : '.gitattributes',
install_dir : testdata_dir)
endif
if conf.get('ENABLE_RESOLVE') == 1
install_subdir('test-resolve',
exclude_files : '.gitattributes',

2
test/test-bcd/.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
*.bcd binary
*.bcd.zst binary

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
test/test-bcd/empty.bcd.zst Normal file

Binary file not shown.

BIN
test/test-bcd/win10.bcd.zst Normal file

Binary file not shown.