test: Add BCD unit test

This commit is contained in:
Jan Janssen 2021-12-10 11:55:38 +01:00
parent 986fd3ebc2
commit db7f5ab68f
16 changed files with 208 additions and 9 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',

View file

@ -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)

View file

@ -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]],

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

@ -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.