test: Add BCD unit test
This commit is contained in:
+8
-5
@@ -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',
|
||||
|
||||
+23
-4
@@ -1,8 +1,27 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <efi.h>
|
||||
#include "macro-fundamental.h"
|
||||
#include "util.h"
|
||||
#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 */
|
||||
@@ -206,7 +225,7 @@ static const KeyValue *get_key_value(const UINT8 *bcd, UINT32 bcd_len, const Key
|
||||
* (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. */
|
||||
CHAR16 *get_bcd_title(UINT8 *bcd, UINTN bcd_len) {
|
||||
TEST_STATIC CHAR16 *get_bcd_title(UINT8 *bcd, UINTN bcd_len) {
|
||||
assert(bcd);
|
||||
|
||||
if (HIVE_CELL_OFFSET > bcd_len)
|
||||
|
||||
@@ -373,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]],
|
||||
|
||||
@@ -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);
|
||||
@@ -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',
|
||||
|
||||
@@ -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.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user