1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "alloc-util.h"
4 #include "compress.h"
5 #include "fileio.h"
6 #include "tests.h"
7 #include "utf8.h"
8
9 /* Include the implementation directly, so we can poke at some internals. */
10 #include "bcd.c"
11
load_bcd(const char * path,void ** ret_bcd,size_t * ret_bcd_len)12 static void load_bcd(const char *path, void **ret_bcd, size_t *ret_bcd_len) {
13 size_t len;
14 _cleanup_free_ char *fn = NULL, *compressed = NULL;
15
16 assert_se(get_testdata_dir(path, &fn) >= 0);
17 assert_se(read_full_file_full(AT_FDCWD, fn, UINT64_MAX, SIZE_MAX, 0, NULL, &compressed, &len) >= 0);
18 assert_se(decompress_blob_zstd(compressed, len, ret_bcd, ret_bcd_len, SIZE_MAX) >= 0);
19 }
20
test_get_bcd_title_one(const char * path,const char16_t * title_expect,size_t title_len_expect)21 static void test_get_bcd_title_one(
22 const char *path,
23 const char16_t *title_expect,
24 size_t title_len_expect) {
25
26 size_t len;
27 _cleanup_free_ void *bcd = NULL;
28
29 log_info("/* %s(%s) */", __func__, path);
30
31 load_bcd(path, &bcd, &len);
32
33 char16_t *title = get_bcd_title(bcd, len);
34 if (title_expect) {
35 assert_se(title);
36 assert_se(memcmp(title, title_expect, title_len_expect) == 0);
37 } else
38 assert_se(!title);
39 }
40
TEST(get_bcd_title)41 TEST(get_bcd_title) {
42 test_get_bcd_title_one("test-bcd/win10.bcd.zst", u"Windows 10", sizeof(u"Windows 10"));
43
44 test_get_bcd_title_one("test-bcd/description-bad-type.bcd.zst", NULL, 0);
45 test_get_bcd_title_one("test-bcd/description-empty.bcd.zst", NULL, 0);
46 test_get_bcd_title_one("test-bcd/description-missing.bcd.zst", NULL, 0);
47 test_get_bcd_title_one("test-bcd/description-too-small.bcd.zst", NULL, 0);
48 test_get_bcd_title_one("test-bcd/displayorder-bad-name.bcd.zst", NULL, 0);
49 test_get_bcd_title_one("test-bcd/displayorder-bad-size.bcd.zst", NULL, 0);
50 test_get_bcd_title_one("test-bcd/displayorder-bad-type.bcd.zst", NULL, 0);
51 test_get_bcd_title_one("test-bcd/empty.bcd.zst", NULL, 0);
52 }
53
TEST(base_block)54 TEST(base_block) {
55 size_t len;
56 BaseBlock backup;
57 uint8_t *bcd_base;
58 _cleanup_free_ BaseBlock *bcd = NULL;
59
60 load_bcd("test-bcd/win10.bcd.zst", (void **) &bcd, &len);
61 backup = *bcd;
62 bcd_base = (uint8_t *) bcd;
63
64 assert_se(get_bcd_title(bcd_base, len));
65
66 /* Try various "corruptions" of the base block. */
67
68 assert_se(!get_bcd_title(bcd_base, sizeof(BaseBlock) - 1));
69
70 bcd->sig = 0;
71 assert_se(!get_bcd_title(bcd_base, len));
72 *bcd = backup;
73
74 bcd->version_minor = 2;
75 assert_se(!get_bcd_title(bcd_base, len));
76 *bcd = backup;
77
78 bcd->version_major = 4;
79 assert_se(!get_bcd_title(bcd_base, len));
80 *bcd = backup;
81
82 bcd->type = 1;
83 assert_se(!get_bcd_title(bcd_base, len));
84 *bcd = backup;
85
86 bcd->primary_seqnum++;
87 assert_se(!get_bcd_title(bcd_base, len));
88 *bcd = backup;
89 }
90
TEST(bad_bcd)91 TEST(bad_bcd) {
92 size_t len;
93 uint8_t *hbins;
94 uint32_t offset;
95 _cleanup_free_ void *bcd = NULL;
96
97 /* This BCD hive has been manipulated to have bad offsets/sizes at various places. */
98 load_bcd("test-bcd/corrupt.bcd.zst", &bcd, &len);
99
100 assert_se(len >= HIVE_CELL_OFFSET);
101 hbins = (uint8_t *) bcd + HIVE_CELL_OFFSET;
102 len -= HIVE_CELL_OFFSET;
103 offset = ((BaseBlock *) bcd)->root_cell_offset;
104
105 const Key *root = get_key(hbins, len, offset, "\0");
106 assert_se(root);
107 assert_se(!get_key(hbins, sizeof(Key) - 1, offset, "\0"));
108
109 assert_se(!get_key(hbins, len, offset, "\0BadOffset\0"));
110 assert_se(!get_key(hbins, len, offset, "\0BadSig\0"));
111 assert_se(!get_key(hbins, len, offset, "\0BadKeyNameLen\0"));
112 assert_se(!get_key(hbins, len, offset, "\0SubkeyBadOffset\0Dummy\0"));
113 assert_se(!get_key(hbins, len, offset, "\0SubkeyBadSig\0Dummy\0"));
114 assert_se(!get_key(hbins, len, offset, "\0SubkeyBadNEntries\0Dummy\0"));
115
116 assert_se(!get_key_value(hbins, len, root, "Dummy"));
117
118 const Key *kv_bad_offset = get_key(hbins, len, offset, "\0KeyValuesBadOffset\0");
119 assert_se(kv_bad_offset);
120 assert_se(!get_key_value(hbins, len, kv_bad_offset, "Dummy"));
121
122 const Key *kv_bad_n_key_values = get_key(hbins, len, offset, "\0KeyValuesBadNKeyValues\0");
123 assert_se(kv_bad_n_key_values);
124 assert_se(!get_key_value(hbins, len, kv_bad_n_key_values, "Dummy"));
125
126 const Key *kv = get_key(hbins, len, offset, "\0KeyValues\0");
127 assert_se(kv);
128
129 assert_se(!get_key_value(hbins, len, kv, "BadOffset"));
130 assert_se(!get_key_value(hbins, len, kv, "BadSig"));
131 assert_se(!get_key_value(hbins, len, kv, "BadNameLen"));
132 assert_se(!get_key_value(hbins, len, kv, "InlineData"));
133 assert_se(!get_key_value(hbins, len, kv, "BadDataOffset"));
134 assert_se(!get_key_value(hbins, len, kv, "BadDataSize"));
135 }
136
TEST(argv_bcds)137 TEST(argv_bcds) {
138 for (int i = 1; i < saved_argc; i++) {
139 size_t len;
140 _cleanup_free_ void *bcd = NULL;
141
142 assert_se(read_full_file_full(
143 AT_FDCWD,
144 saved_argv[i],
145 UINT64_MAX,
146 SIZE_MAX,
147 0,
148 NULL,
149 (char **) &bcd,
150 &len) >= 0);
151
152 char16_t *title = get_bcd_title(bcd, len);
153 if (title) {
154 _cleanup_free_ char *title_utf8 = utf16_to_utf8(title, char16_strlen(title) * 2);
155 log_info("%s: \"%s\"", saved_argv[i], title_utf8);
156 } else
157 log_info("%s: Bad BCD", saved_argv[i]);
158 }
159 }
160
161 DEFINE_TEST_MAIN(LOG_INFO);
162