]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
test: Add BCD unit test 21614/head
authorJan Janssen <medhefgo@web.de>
Fri, 10 Dec 2021 10:55:38 +0000 (11:55 +0100)
committerJan Janssen <medhefgo@web.de>
Sat, 11 Dec 2021 20:32:29 +0000 (21:32 +0100)
16 files changed:
meson.build
src/boot/efi/bcd.c
src/boot/efi/meson.build
src/boot/efi/test-bcd.c [new file with mode: 0644]
test/meson.build
test/test-bcd/.gitattributes [new file with mode: 0644]
test/test-bcd/corrupt.bcd.zst [new file with mode: 0644]
test/test-bcd/description-bad-type.bcd.zst [new file with mode: 0644]
test/test-bcd/description-empty.bcd.zst [new file with mode: 0644]
test/test-bcd/description-missing.bcd.zst [new file with mode: 0644]
test/test-bcd/description-too-small.bcd.zst [new file with mode: 0644]
test/test-bcd/displayorder-bad-name.bcd.zst [new file with mode: 0644]
test/test-bcd/displayorder-bad-size.bcd.zst [new file with mode: 0644]
test/test-bcd/displayorder-bad-type.bcd.zst [new file with mode: 0644]
test/test-bcd/empty.bcd.zst [new file with mode: 0644]
test/test-bcd/win10.bcd.zst [new file with mode: 0644]

index 4c0dd6f8c99aa7842cf0d86d48ec636cf1ad00e6..e77c2aa3ac0e438fe891786812661495d016ec03 100644 (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',
index 7eabb4da1a513d483d973185fb828da507373c85..970c8b1c8ec3f701735274ac582a863e8d8b812b 100644 (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)
index 81e8734452b8f73a4d36fe281d4e07ad483f3d62..a108bf16ab48ca601f7c456e404f42ea4caab330 100644 (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]],
diff --git a/src/boot/efi/test-bcd.c b/src/boot/efi/test-bcd.c
new file mode 100644 (file)
index 0000000..a4d0906
--- /dev/null
@@ -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);
index fad40b8946494b1f5f70680685966e303bd80b3f..7d94032d09ef12a9b5bfb67660139241e7424ee5 100644 (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',
diff --git a/test/test-bcd/.gitattributes b/test/test-bcd/.gitattributes
new file mode 100644 (file)
index 0000000..b5f1b48
--- /dev/null
@@ -0,0 +1,2 @@
+*.bcd binary
+*.bcd.zst binary
diff --git a/test/test-bcd/corrupt.bcd.zst b/test/test-bcd/corrupt.bcd.zst
new file mode 100644 (file)
index 0000000..48b5701
Binary files /dev/null and b/test/test-bcd/corrupt.bcd.zst differ
diff --git a/test/test-bcd/description-bad-type.bcd.zst b/test/test-bcd/description-bad-type.bcd.zst
new file mode 100644 (file)
index 0000000..fdf23ca
Binary files /dev/null and b/test/test-bcd/description-bad-type.bcd.zst differ
diff --git a/test/test-bcd/description-empty.bcd.zst b/test/test-bcd/description-empty.bcd.zst
new file mode 100644 (file)
index 0000000..c1c801d
Binary files /dev/null and b/test/test-bcd/description-empty.bcd.zst differ
diff --git a/test/test-bcd/description-missing.bcd.zst b/test/test-bcd/description-missing.bcd.zst
new file mode 100644 (file)
index 0000000..a34ad8a
Binary files /dev/null and b/test/test-bcd/description-missing.bcd.zst differ
diff --git a/test/test-bcd/description-too-small.bcd.zst b/test/test-bcd/description-too-small.bcd.zst
new file mode 100644 (file)
index 0000000..76e7393
Binary files /dev/null and b/test/test-bcd/description-too-small.bcd.zst differ
diff --git a/test/test-bcd/displayorder-bad-name.bcd.zst b/test/test-bcd/displayorder-bad-name.bcd.zst
new file mode 100644 (file)
index 0000000..157f54e
Binary files /dev/null and b/test/test-bcd/displayorder-bad-name.bcd.zst differ
diff --git a/test/test-bcd/displayorder-bad-size.bcd.zst b/test/test-bcd/displayorder-bad-size.bcd.zst
new file mode 100644 (file)
index 0000000..ee89b77
Binary files /dev/null and b/test/test-bcd/displayorder-bad-size.bcd.zst differ
diff --git a/test/test-bcd/displayorder-bad-type.bcd.zst b/test/test-bcd/displayorder-bad-type.bcd.zst
new file mode 100644 (file)
index 0000000..cc2a887
Binary files /dev/null and b/test/test-bcd/displayorder-bad-type.bcd.zst differ
diff --git a/test/test-bcd/empty.bcd.zst b/test/test-bcd/empty.bcd.zst
new file mode 100644 (file)
index 0000000..5b3e938
Binary files /dev/null and b/test/test-bcd/empty.bcd.zst differ
diff --git a/test/test-bcd/win10.bcd.zst b/test/test-bcd/win10.bcd.zst
new file mode 100644 (file)
index 0000000..c922eb6
Binary files /dev/null and b/test/test-bcd/win10.bcd.zst differ