X Tutup
Skip to content

Commit db7f5ab

Browse files
committed
test: Add BCD unit test
1 parent 986fd3e commit db7f5ab

16 files changed

+208
-9
lines changed

meson.build

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1676,8 +1676,14 @@ conf.set10('ENABLE_TIMEDATECTL', get_option('timedated') or get_option('timesync
16761676

16771677
conf.set10('SYSTEMD_SLOW_TESTS_DEFAULT', slow_tests)
16781678

1679-
#####################################################################
1679+
############################################################
1680+
1681+
tests = []
1682+
fuzzers = []
1683+
1684+
############################################################
16801685

1686+
# Include these now as they provide gnu-efi detection.
16811687
subdir('src/fundamental')
16821688
subdir('src/boot/efi')
16831689

@@ -1695,7 +1701,7 @@ update_syscall_tables_sh = find_program('tools/update-syscall-tables.sh')
16951701
xml_helper_py = find_program('tools/xml_helper.py')
16961702
export_dbus_interfaces_py = find_program('tools/dbus_exporter.py')
16971703

1698-
#####################################################################
1704+
############################################################
16991705

17001706
config_h = configure_file(
17011707
output : 'config.h',
@@ -1716,9 +1722,6 @@ if dbus_interfaces_dir == ''
17161722
dbus_interfaces_dir = get_option('datadir') + '/dbus-1'
17171723
endif
17181724

1719-
tests = []
1720-
fuzzers = []
1721-
17221725
basic_includes = include_directories(
17231726
'src/basic',
17241727
'src/fundamental',

src/boot/efi/bcd.c

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,27 @@
11
/* SPDX-License-Identifier: LGPL-2.1-or-later */
22

3-
#include <efi.h>
4-
#include "macro-fundamental.h"
5-
#include "util.h"
3+
#ifdef SD_BOOT
4+
# include <efi.h>
5+
# include "macro-fundamental.h"
6+
# include "util.h"
7+
# define TEST_STATIC
8+
#else
9+
/* Provide our own "EFI API" if we are running as a unit test. */
10+
# include <stddef.h>
11+
# include <stdint.h>
12+
# include <uchar.h>
13+
# include "string-util-fundamental.h"
14+
15+
# define CHAR8 char
16+
# define CHAR16 char16_t
17+
# define UINT8 uint8_t
18+
# define UINT16 uint16_t
19+
# define UINT32 uint32_t
20+
# define UINT64 uint64_t
21+
# define UINTN size_t
22+
# define strncaseeqa(a, b, n) strncaseeq((a), (b), (n))
23+
# define TEST_STATIC static
24+
#endif
625

726
enum {
827
SIG_BASE_BLOCK = 1718052210, /* regf */
@@ -206,7 +225,7 @@ static const KeyValue *get_key_value(const UINT8 *bcd, UINT32 bcd_len, const Key
206225
* (it always has the GUID 9dea862c-5cdd-4e70-acc1-f32b344d4795). If it contains more than
207226
* one GUID, the BCD is multi-boot and we stop looking. Otherwise we take that GUID, look it
208227
* up, and return its description property. */
209-
CHAR16 *get_bcd_title(UINT8 *bcd, UINTN bcd_len) {
228+
TEST_STATIC CHAR16 *get_bcd_title(UINT8 *bcd, UINTN bcd_len) {
210229
assert(bcd);
211230

212231
if (HIVE_CELL_OFFSET > bcd_len)

src/boot/efi/meson.build

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,14 @@ endforeach
373373

374374
############################################################
375375

376+
tests += [
377+
[['src/boot/efi/test-bcd.c'],
378+
[],
379+
[libzstd],
380+
[],
381+
'HAVE_ZSTD'],
382+
]
383+
376384
test_efi_disk_img = custom_target(
377385
'test-efi-disk.img',
378386
input : [efi_stubs[0][0], efi_stubs[1][1]],

src/boot/efi/test-bcd.c

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
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+
/* Inlcude the implementation directly, so we can poke at some internals. */
10+
#include "bcd.c"
11+
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+
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+
41+
TEST(get_bcd_title) {
42+
const char16_t win10[] = { 'W', 'i', 'n', 'd', 'o', 'w', 's', ' ', '1', '0', '\0' };
43+
test_get_bcd_title_one("test-bcd/win10.bcd.zst", win10, sizeof(win10));
44+
45+
test_get_bcd_title_one("test-bcd/description-bad-type.bcd.zst", NULL, 0);
46+
test_get_bcd_title_one("test-bcd/description-empty.bcd.zst", NULL, 0);
47+
test_get_bcd_title_one("test-bcd/description-missing.bcd.zst", NULL, 0);
48+
test_get_bcd_title_one("test-bcd/description-too-small.bcd.zst", NULL, 0);
49+
test_get_bcd_title_one("test-bcd/displayorder-bad-name.bcd.zst", NULL, 0);
50+
test_get_bcd_title_one("test-bcd/displayorder-bad-size.bcd.zst", NULL, 0);
51+
test_get_bcd_title_one("test-bcd/displayorder-bad-type.bcd.zst", NULL, 0);
52+
test_get_bcd_title_one("test-bcd/empty.bcd.zst", NULL, 0);
53+
}
54+
55+
TEST(base_block) {
56+
size_t len;
57+
BaseBlock backup;
58+
uint8_t *bcd_base;
59+
_cleanup_free_ BaseBlock *bcd = NULL;
60+
61+
load_bcd("test-bcd/win10.bcd.zst", (void **) &bcd, &len);
62+
backup = *bcd;
63+
bcd_base = (uint8_t *) bcd;
64+
65+
assert_se(get_bcd_title(bcd_base, len));
66+
67+
/* Try various "corruptions" of the base block. */
68+
69+
assert_se(!get_bcd_title(bcd_base, sizeof(BaseBlock) - 1));
70+
71+
bcd->sig = 0;
72+
assert_se(!get_bcd_title(bcd_base, len));
73+
*bcd = backup;
74+
75+
bcd->version_minor = 2;
76+
assert_se(!get_bcd_title(bcd_base, len));
77+
*bcd = backup;
78+
79+
bcd->version_major = 4;
80+
assert_se(!get_bcd_title(bcd_base, len));
81+
*bcd = backup;
82+
83+
bcd->type = 1;
84+
assert_se(!get_bcd_title(bcd_base, len));
85+
*bcd = backup;
86+
87+
bcd->primary_seqnum++;
88+
assert_se(!get_bcd_title(bcd_base, len));
89+
*bcd = backup;
90+
}
91+
92+
TEST(bad_bcd) {
93+
size_t len;
94+
uint8_t *hbins;
95+
uint32_t offset;
96+
_cleanup_free_ void *bcd = NULL;
97+
98+
/* This BCD hive has been manipulated to have bad offsets/sizes at various places. */
99+
load_bcd("test-bcd/corrupt.bcd.zst", &bcd, &len);
100+
101+
assert_se(len >= HIVE_CELL_OFFSET);
102+
hbins = (uint8_t *) bcd + HIVE_CELL_OFFSET;
103+
len -= HIVE_CELL_OFFSET;
104+
offset = ((BaseBlock *) bcd)->root_cell_offset;
105+
106+
const Key *root = get_key(hbins, len, offset, "\0");
107+
assert_se(root);
108+
assert_se(!get_key(hbins, sizeof(Key) - 1, offset, "\0"));
109+
110+
assert_se(!get_key(hbins, len, offset, "\0BadOffset\0"));
111+
assert_se(!get_key(hbins, len, offset, "\0BadSig\0"));
112+
assert_se(!get_key(hbins, len, offset, "\0BadKeyNameLen\0"));
113+
assert_se(!get_key(hbins, len, offset, "\0SubkeyBadOffset\0Dummy\0"));
114+
assert_se(!get_key(hbins, len, offset, "\0SubkeyBadSig\0Dummy\0"));
115+
assert_se(!get_key(hbins, len, offset, "\0SubkeyBadNEntries\0Dummy\0"));
116+
117+
assert_se(!get_key_value(hbins, len, root, "Dummy"));
118+
119+
const Key *kv_bad_offset = get_key(hbins, len, offset, "\0KeyValuesBadOffset\0");
120+
assert_se(kv_bad_offset);
121+
assert_se(!get_key_value(hbins, len, kv_bad_offset, "Dummy"));
122+
123+
const Key *kv_bad_n_key_values = get_key(hbins, len, offset, "\0KeyValuesBadNKeyValues\0");
124+
assert_se(kv_bad_n_key_values);
125+
assert_se(!get_key_value(hbins, len, kv_bad_n_key_values, "Dummy"));
126+
127+
const Key *kv = get_key(hbins, len, offset, "\0KeyValues\0");
128+
assert_se(kv);
129+
130+
assert_se(!get_key_value(hbins, len, kv, "BadOffset"));
131+
assert_se(!get_key_value(hbins, len, kv, "BadSig"));
132+
assert_se(!get_key_value(hbins, len, kv, "BadNameLen"));
133+
assert_se(!get_key_value(hbins, len, kv, "InlineData"));
134+
assert_se(!get_key_value(hbins, len, kv, "BadDataOffset"));
135+
assert_se(!get_key_value(hbins, len, kv, "BadDataSize"));
136+
}
137+
138+
TEST(argv_bcds) {
139+
for (int i = 1; i < saved_argc; i++) {
140+
size_t len;
141+
_cleanup_free_ void *bcd = NULL;
142+
143+
assert_se(read_full_file_full(
144+
AT_FDCWD,
145+
saved_argv[i],
146+
UINT64_MAX,
147+
SIZE_MAX,
148+
0,
149+
NULL,
150+
(char **) &bcd,
151+
&len) >= 0);
152+
153+
char16_t *title = get_bcd_title(bcd, len);
154+
if (title) {
155+
_cleanup_free_ char *title_utf8 = utf16_to_utf8(title, char16_strlen(title) * 2);
156+
log_info("%s: \"%s\"", saved_argv[i], title_utf8);
157+
} else
158+
log_info("%s: Bad BCD", saved_argv[i]);
159+
}
160+
}
161+
162+
DEFINE_TEST_MAIN(LOG_INFO);

test/meson.build

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ if install_tests
6767
'../-.mount',
6868
testsuite08_dir + '/local-fs.target.wants/-.mount')
6969

70+
if conf.get('HAVE_GNU_EFI') == 1 and conf.get('HAVE_ZSTD') == 1
71+
install_subdir('test-bcd',
72+
exclude_files : '.gitattributes',
73+
install_dir : testdata_dir)
74+
endif
7075
if conf.get('ENABLE_RESOLVE') == 1
7176
install_subdir('test-resolve',
7277
exclude_files : '.gitattributes',

test/test-bcd/.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*.bcd binary
2+
*.bcd.zst binary

test/test-bcd/corrupt.bcd.zst

823 Bytes
Binary file not shown.
733 Bytes
Binary file not shown.
713 Bytes
Binary file not shown.
703 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)
X Tutup