blob: 0ee29477040827453f09d76abc6fea558476d894 [file] [log] [blame]
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "alloc-util.h"
#include "bcd.h"
#include "compress.h"
#include "fileio.h"
#include "tests.h"
#include "utf8.h"
/* Include 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) {
test_get_bcd_title_one("test-bcd/win10.bcd.zst", u"Windows 10", sizeof(u"Windows 10"));
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);