[PATCH v3 1/3] image-fit.c: introduce CONTROL_DTB_AS_FIT config knob
Rasmus Villemoes
rv at rasmusvillemoes.dk
Fri May 29 21:46:19 CEST 2026
Having scripts embedded one way or the other in the U-Boot binary
means they are automatically verified/trusted by whatever mechanism
verifies U-Boot.
Writing those scripts in the built-in environment leads to
backslatitis and missing or wrong quoting and is generally not very
readable or maintainable.
Maintaining scripts in external files allows one
to have both syntax highlighting and to some extent apply shellcheck
on it (though U-Boot's shell is of course not quite POSIX sh, so some
'#shellcheck disable' directives are needed). Getting those into the
U-Boot binary is then a matter of having a suitable .dtsi file such as
/ {
images {
default = "boot";
boot {
description = "Bootscript";
data = /incbin/("boot.sh");
type = "script";
compression = "none";
};
factory-reset {
description = "Script for performing factory reset";
data = /incbin/("factory-reset.sh");
type = "script";
compression = "none";
};
};
};
and making that part of CONFIG_DEVICE_TREE_INCLUDES, so that U-Boot's
control DTB effectively doubles as a FIT image containing a few
"script" entries. At run-time, one's default bootcommand can then
simply be
source ${fdtcontroladdr}:boot
Except of course that the control DTB is in fact not quite a FIT
image. The lack of timestamp and description properties could
potentially be worked around (by just adding those via that same
.dtsi), but the no-@ check is not possible to get around. But since
the control dtb is by definition trusted, we can make an exception for
that particular address, if the new CONTROL_DTB_AS_FIT config option
is enabled.
One can of course build an ordinary FIT image with those
scripts. However, that requires extra steps in the boot command for
loading that script from storage, requires one to use "configurations"
for pointing at a single script to run, and signing the FIT image
using the same key used for verifying the kernel. Moreover, in certain
situations, such as bootstrapping/production, there is no place to
load that FIT image from, and it is much simpler to just have the
necessary scripts be part of the U-Boot image itself.
Signed-off-by: Rasmus Villemoes <ravi at prevas.dk>
Signed-off-by: Rasmus Villemoes <rv at rasmusvillemoes.dk>
---
boot/Kconfig | 13 +++++++++++++
boot/image-fit.c | 21 +++++++++++++++------
2 files changed, 28 insertions(+), 6 deletions(-)
diff --git a/boot/Kconfig b/boot/Kconfig
index ae6f09a6ede..19a170957c6 100644
--- a/boot/Kconfig
+++ b/boot/Kconfig
@@ -103,6 +103,19 @@ config FIT_FULL_CHECK
of bugs or omissions in the code. This includes a bad structure,
multiple root nodes and the like.
+config CONTROL_DTB_AS_FIT
+ bool "Allow U-Boot's control DTB to act as FIT image"
+ help
+ Enable this to exempt U-Boot's control DTB from the sanity
+ checks done to ensure FIT images are valid. This can for
+ example be used to embed whole scripts in the control DTB,
+ that can then be invoked using 'source ${fdtcontroladdr}'.
+ In a secure boot setup, this is safe, as the control DTB is
+ necessarily covered by any mechanism verifying U-Boot and
+ can therefore be trusted. This only affects the case where
+ the image being checked is gd->fdt_blob. See
+ doc/develop/devicetree/control.rst for details.
+
config FIT_SIGNATURE
bool "Enable signature verification of FIT uImages"
depends on DM
diff --git a/boot/image-fit.c b/boot/image-fit.c
index b0fcaf6e17f..18498d0b51a 100644
--- a/boot/image-fit.c
+++ b/boot/image-fit.c
@@ -1664,6 +1664,16 @@ static int fdt_check_no_at(const void *fit, int parent)
return 0;
}
+static int fit_check_images_node(const void *fit)
+{
+ if (fdt_path_offset(fit, FIT_IMAGES_PATH) < 0) {
+ log_debug("Wrong FIT format: no images parent node\n");
+ return -ENOENT;
+ }
+
+ return 0;
+}
+
int fit_check_format(const void *fit, ulong size)
{
int ret;
@@ -1676,6 +1686,10 @@ int fit_check_format(const void *fit, ulong size)
return -ENOEXEC;
}
+ /* For the control DTB to act as a FIT image, we only require an /images node. */
+ if (CONFIG_IS_ENABLED(CONTROL_DTB_AS_FIT) && fit == gd_fdt_blob())
+ return fit_check_images_node(fit);
+
if (CONFIG_IS_ENABLED(FIT_FULL_CHECK)) {
/*
* If we are not given the size, make do with calculating it.
@@ -1724,12 +1738,7 @@ int fit_check_format(const void *fit, ulong size)
}
/* mandatory subimages parent '/images' node */
- if (fdt_path_offset(fit, FIT_IMAGES_PATH) < 0) {
- log_debug("Wrong FIT format: no images parent node\n");
- return -ENOENT;
- }
-
- return 0;
+ return fit_check_images_node(fit);
}
int fit_conf_find_compat(const void *fit, const void *fdt)
--
2.54.0
More information about the U-Boot
mailing list