test: Add BCD unit test

This commit is contained in:
Jan Janssen
2021-12-11 21:32:29 +01:00
parent 986fd3ebc2
commit db7f5ab68f
16 changed files with 208 additions and 9 deletions
+23 -4
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)
+8
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
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);