[PATCH v2 6/7] test: boot: add runtime unit test for fit_verity_build_cmdline()
Daniel Golle
daniel at makrotopia.org
Thu Apr 16 03:47:03 CEST 2026
Add test/boot/fit_verity.c with four tests that construct FIT blobs
in memory and exercise fit_verity_build_cmdline().
Signed-off-by: Daniel Golle <daniel at makrotopia.org>
---
v2: new patch
test/boot/Makefile | 1 +
test/boot/fit_verity.c | 298 +++++++++++++++++++++++++++++++++++++++++
test/cmd_ut.c | 2 +
3 files changed, 301 insertions(+)
create mode 100644 test/boot/fit_verity.c
diff --git a/test/boot/Makefile b/test/boot/Makefile
index 89538d4f0a6..d98f212b243 100644
--- a/test/boot/Makefile
+++ b/test/boot/Makefile
@@ -15,6 +15,7 @@ endif
ifdef CONFIG_SANDBOX
obj-$(CONFIG_$(PHASE_)CMDLINE) += bootm.o
endif
+obj-$(CONFIG_$(PHASE_)FIT_VERITY) += fit_verity.o
obj-$(CONFIG_MEASURED_BOOT) += measurement.o
ifdef CONFIG_OF_LIVE
diff --git a/test/boot/fit_verity.c b/test/boot/fit_verity.c
new file mode 100644
index 00000000000..40c54998387
--- /dev/null
+++ b/test/boot/fit_verity.c
@@ -0,0 +7,302 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Tests for FIT dm-verity cmdline generation
+ *
+ * Copyright 2026 Daniel Golle <daniel at makrotopia.org>
+ */
+
+#include <image.h>
+#include <test/test.h>
+#include <test/ut.h>
+
+#define FIT_VERITY_TEST(_name, _flags) UNIT_TEST(_name, _flags, fit_verity)
+
+/* FIT blob buffer size — generous to avoid FDT_ERR_NOSPACE */
+#define FIT_BUF_SIZE 4096
+
+/* Test digest (32 bytes = sha256) */
+static const u8 test_digest[32] = {
+ 0x8e, 0x67, 0x91, 0x63, 0x7f, 0x93, 0xcb, 0xb8,
+ 0x1f, 0xc4, 0x52, 0x99, 0xe2, 0x03, 0xcb, 0xe8,
+ 0x5c, 0xa2, 0xe4, 0x7a, 0x38, 0xf5, 0x05, 0x1b,
+ 0xdd, 0xee, 0xce, 0x92, 0xd7, 0xb1, 0xc9, 0xf9,
+};
+
+/* Test salt (32 bytes) */
+static const u8 test_salt[32] = {
+ 0xaa, 0x7b, 0x11, 0xf8, 0xdb, 0x8f, 0xe2, 0xe5,
+ 0xbf, 0xd4, 0xec, 0xa1, 0xd1, 0x8a, 0x22, 0xb5,
+ 0xde, 0x7e, 0xa3, 0x9d, 0x2e, 0x1b, 0x93, 0xbb,
+ 0x72, 0x72, 0xce, 0x0c, 0x6c, 0xa3, 0xcc, 0x8e,
+};
+
+/**
+ * build_verity_fit() - construct a minimal FIT blob with dm-verity metadata
+ * @buf: output buffer (at least FIT_BUF_SIZE bytes)
+ * @num_loadables: number of filesystem loadables to create (1 or 2)
+ *
+ * Builds a FIT blob containing:
+ * - /images/rootfsN with type="filesystem" and a dm-verity subnode
+ * - /configurations/conf-1 referencing the loadable(s)
+ *
+ * Return: configuration node offset, or -ve on error
+ */
+static int build_verity_fit(void *buf, int num_loadables)
+{
+ int images_node, conf_node, confs_node, img_node, verity_node;
+ fdt32_t val;
+ int ret, i;
+ char name[32];
+ /*
+ * Build the loadables string list. FDT stringlists are concatenated
+ * NUL-terminated strings. E.g. "rootfs0\0rootfs1\0"
+ */
+ char loadables[128];
+ int loadables_len = 0;
+
+ ret = fdt_create_empty_tree(buf, FIT_BUF_SIZE);
+ if (ret)
+ return ret;
+
+ /* /images */
+ images_node = fdt_add_subnode(buf, 0, "images");
+ if (images_node < 0)
+ return images_node;
+
+ for (i = 0; i < num_loadables; i++) {
+ snprintf(name, sizeof(name), "rootfs%d", i);
+
+ img_node = fdt_add_subnode(buf, images_node, name);
+ if (img_node < 0)
+ return img_node;
+
+ ret = fdt_setprop_string(buf, img_node, "type", "filesystem");
+ if (ret)
+ return ret;
+
+ verity_node = fdt_add_subnode(buf, img_node, "dm-verity");
+ if (verity_node < 0)
+ return verity_node;
+
+ ret = fdt_setprop_string(buf, verity_node, "algo", "sha256");
+ if (ret)
+ return ret;
+
+ val = cpu_to_fdt32(4096);
+ ret = fdt_setprop(buf, verity_node, "data-block-size",
+ &val, sizeof(val));
+ if (ret)
+ return ret;
+
+ ret = fdt_setprop(buf, verity_node, "hash-block-size",
+ &val, sizeof(val));
+ if (ret)
+ return ret;
+
+ val = cpu_to_fdt32(100);
+ ret = fdt_setprop(buf, verity_node, "num-data-blocks",
+ &val, sizeof(val));
+ if (ret)
+ return ret;
+
+ val = cpu_to_fdt32(100);
+ ret = fdt_setprop(buf, verity_node, "hash-start-block",
+ &val, sizeof(val));
+ if (ret)
+ return ret;
+
+ ret = fdt_setprop(buf, verity_node, "digest",
+ test_digest, sizeof(test_digest));
+ if (ret)
+ return ret;
+
+ ret = fdt_setprop(buf, verity_node, "salt",
+ test_salt, sizeof(test_salt));
+ if (ret)
+ return ret;
+
+ /* Append to loadables stringlist */
+ loadables_len += snprintf(loadables + loadables_len,
+ sizeof(loadables) - loadables_len,
+ "%s", name) + 1;
+ }
+
+ /* /configurations/conf-1 */
+ confs_node = fdt_add_subnode(buf, 0, "configurations");
+ if (confs_node < 0)
+ return confs_node;
+
+ conf_node = fdt_add_subnode(buf, confs_node, "conf-1");
+ if (conf_node < 0)
+ return conf_node;
+
+ ret = fdt_setprop(buf, conf_node, "loadables",
+ loadables, loadables_len);
+ if (ret)
+ return ret;
+
+ return conf_node;
+}
+
+/* Test: single dm-verity loadable produces correct cmdline fragments */
+static int fit_verity_test_single(struct unit_test_state *uts)
+{
+ char buf[FIT_BUF_SIZE];
+ struct bootm_headers images;
+ int conf_noffset;
+
+ conf_noffset = build_verity_fit(buf, 1);
+ ut_assert(conf_noffset >= 0);
+
+ memset(&images, 0, sizeof(images));
+ ut_assertok(fit_verity_build_cmdline(buf, conf_noffset, &images));
+
+ /* dm_mod_create should contain the target spec for rootfs0 */
+ ut_assertnonnull(images.dm_mod_create);
+ ut_assert(strstr(images.dm_mod_create, "rootfs0,,,"));
+ ut_assert(strstr(images.dm_mod_create, "verity 1"));
+ ut_assert(strstr(images.dm_mod_create, "/dev/fit0"));
+ ut_assert(strstr(images.dm_mod_create, "4096 4096 100 100"));
+ ut_assert(strstr(images.dm_mod_create, "sha256"));
+ /* Check hex-encoded digest prefix */
+ ut_assert(strstr(images.dm_mod_create, "8e6791637f93cbb8"));
+ /* Check hex-encoded salt prefix */
+ ut_assert(strstr(images.dm_mod_create, "aa7b11f8db8fe2e5"));
+
+ /* dm_mod_waitfor should reference /dev/fit0 */
+ ut_assertnonnull(images.dm_mod_waitfor);
+ ut_asserteq_str("/dev/fit0", images.dm_mod_waitfor);
+
+ fit_verity_free(&images);
+ ut_assertnull(images.dm_mod_create);
+ ut_assertnull(images.dm_mod_waitfor);
+
+ return 0;
+}
+
+FIT_VERITY_TEST(fit_verity_test_single, 0);
+
+/* Test: FIT with no dm-verity subnode returns 0, pointers stay NULL */
+static int fit_verity_test_no_verity(struct unit_test_state *uts)
+{
+ char buf[FIT_BUF_SIZE];
+ struct bootm_headers images;
+ int conf_node, images_node, img_node, confs_node;
+ int ret;
+
+ ret = fdt_create_empty_tree(buf, FIT_BUF_SIZE);
+ ut_assertok(ret);
+
+ images_node = fdt_add_subnode(buf, 0, "images");
+ ut_assert(images_node >= 0);
+
+ img_node = fdt_add_subnode(buf, images_node, "rootfs");
+ ut_assert(img_node >= 0);
+ ut_assertok(fdt_setprop_string(buf, img_node, "type", "filesystem"));
+ /* No dm-verity subnode */
+
+ confs_node = fdt_add_subnode(buf, 0, "configurations");
+ ut_assert(confs_node >= 0);
+ conf_node = fdt_add_subnode(buf, confs_node, "conf-1");
+ ut_assert(conf_node >= 0);
+ ut_assertok(fdt_setprop_string(buf, conf_node, "loadables", "rootfs"));
+
+ memset(&images, 0, sizeof(images));
+ ut_asserteq(0, fit_verity_build_cmdline(buf, conf_node, &images));
+ ut_assertnull(images.dm_mod_create);
+ ut_assertnull(images.dm_mod_waitfor);
+
+ return 0;
+}
+
+FIT_VERITY_TEST(fit_verity_test_no_verity, 0);
+
+/* Test: two dm-verity loadables produce combined cmdline */
+static int fit_verity_test_two_loadables(struct unit_test_state *uts)
+{
+ char buf[FIT_BUF_SIZE];
+ struct bootm_headers images;
+ int conf_noffset;
+
+ conf_noffset = build_verity_fit(buf, 2);
+ ut_assert(conf_noffset >= 0);
+
+ memset(&images, 0, sizeof(images));
+ ut_assertok(fit_verity_build_cmdline(buf, conf_noffset, &images));
+
+ /* Both targets should appear, separated by ";" */
+ ut_assertnonnull(images.dm_mod_create);
+ ut_assert(strstr(images.dm_mod_create, "rootfs0,,,"));
+ ut_assert(strstr(images.dm_mod_create, ";rootfs1,,,"));
+ ut_assert(strstr(images.dm_mod_create, "/dev/fit0"));
+ ut_assert(strstr(images.dm_mod_create, "/dev/fit1"));
+
+ /* dm_mod_waitfor should list both devices */
+ ut_assertnonnull(images.dm_mod_waitfor);
+ ut_assert(strstr(images.dm_mod_waitfor, "/dev/fit0"));
+ ut_assert(strstr(images.dm_mod_waitfor, "/dev/fit1"));
+
+ fit_verity_free(&images);
+ return 0;
+}
+
+FIT_VERITY_TEST(fit_verity_test_two_loadables, 0);
+
+/* Test: invalid block size (not power of two) returns -EINVAL */
+static int fit_verity_test_bad_blocksize(struct unit_test_state *uts)
+{
+ char buf[FIT_BUF_SIZE];
+ struct bootm_headers images;
+ int images_node, conf_node, confs_node, img_node, verity_node;
+ fdt32_t val;
+ int ret;
+
+ ret = fdt_create_empty_tree(buf, FIT_BUF_SIZE);
+ ut_assertok(ret);
+
+ images_node = fdt_add_subnode(buf, 0, "images");
+ ut_assert(images_node >= 0);
+
+ img_node = fdt_add_subnode(buf, images_node, "rootfs");
+ ut_assert(img_node >= 0);
+ ut_assertok(fdt_setprop_string(buf, img_node, "type", "filesystem"));
+
+ verity_node = fdt_add_subnode(buf, img_node, "dm-verity");
+ ut_assert(verity_node >= 0);
+
+ ut_assertok(fdt_setprop_string(buf, verity_node, "algo", "sha256"));
+
+ /* 3000 is not a power of two */
+ val = cpu_to_fdt32(3000);
+ ut_assertok(fdt_setprop(buf, verity_node, "data-block-size",
+ &val, sizeof(val)));
+ val = cpu_to_fdt32(4096);
+ ut_assertok(fdt_setprop(buf, verity_node, "hash-block-size",
+ &val, sizeof(val)));
+
+ val = cpu_to_fdt32(100);
+ ut_assertok(fdt_setprop(buf, verity_node, "num-data-blocks",
+ &val, sizeof(val)));
+ ut_assertok(fdt_setprop(buf, verity_node, "hash-start-block",
+ &val, sizeof(val)));
+
+ ut_assertok(fdt_setprop(buf, verity_node, "digest",
+ test_digest, sizeof(test_digest)));
+ ut_assertok(fdt_setprop(buf, verity_node, "salt",
+ test_salt, sizeof(test_salt)));
+
+ confs_node = fdt_add_subnode(buf, 0, "configurations");
+ ut_assert(confs_node >= 0);
+ conf_node = fdt_add_subnode(buf, confs_node, "conf-1");
+ ut_assert(conf_node >= 0);
+ ut_assertok(fdt_setprop_string(buf, conf_node, "loadables", "rootfs"));
+
+ memset(&images, 0, sizeof(images));
+ ut_asserteq(-EINVAL, fit_verity_build_cmdline(buf, conf_node, &images));
+ ut_assertnull(images.dm_mod_create);
+ ut_assertnull(images.dm_mod_waitfor);
+
+ return 0;
+}
+
+FIT_VERITY_TEST(fit_verity_test_bad_blocksize, 0);
diff --git a/test/cmd_ut.c b/test/cmd_ut.c
index 44e5fdfdaa6..d1b376f617c 100644
--- a/test/cmd_ut.c
+++ b/test/cmd_ut.c
@@ -59,6 +59,7 @@ SUITE_DECL(env);
SUITE_DECL(exit);
SUITE_DECL(fdt);
SUITE_DECL(fdt_overlay);
+SUITE_DECL(fit_verity);
SUITE_DECL(font);
SUITE_DECL(hush);
SUITE_DECL(lib);
@@ -86,6 +87,7 @@ static struct suite suites[] = {
SUITE(exit, "shell exit and variables"),
SUITE(fdt, "fdt command"),
SUITE(fdt_overlay, "device tree overlays"),
+ SUITE(fit_verity, "FIT dm-verity cmdline generation"),
SUITE(font, "font command"),
SUITE(hush, "hush behaviour"),
SUITE(lib, "library functions"),
--
2.53.0
More information about the U-Boot
mailing list