summaryrefslogtreecommitdiffstats
path: root/src/boot/efi/test-bcd.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:49:52 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:49:52 +0000
commit55944e5e40b1be2afc4855d8d2baf4b73d1876b5 (patch)
tree33f869f55a1b149e9b7c2b7e201867ca5dd52992 /src/boot/efi/test-bcd.c
parentInitial commit. (diff)
downloadsystemd-55944e5e40b1be2afc4855d8d2baf4b73d1876b5.tar.xz
systemd-55944e5e40b1be2afc4855d8d2baf4b73d1876b5.zip
Adding upstream version 255.4.upstream/255.4
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/boot/efi/test-bcd.c')
-rw-r--r--src/boot/efi/test-bcd.c162
1 files changed, 162 insertions, 0 deletions
diff --git a/src/boot/efi/test-bcd.c b/src/boot/efi/test-bcd.c
new file mode 100644
index 0000000..3f93ca0
--- /dev/null
+++ b/src/boot/efi/test-bcd.c
@@ -0,0 +1,162 @@
+/* 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, SIZE_MAX);
+ log_info("%s: \"%s\"", saved_argv[i], title_utf8);
+ } else
+ log_info("%s: Bad BCD", saved_argv[i]);
+ }
+}
+
+DEFINE_TEST_MAIN(LOG_INFO);