[RFC PATCH 1/3] boot/fit: require exact subnode matches for FIT references
Lorenz Kofler
lorenz at sigma-star.at
Tue Jun 2 09:43:33 CEST 2026
Libfdt lookup semantics can match a node by its base name even when the
actual node name includes a unit address. As a result, a request for
"kernel" can resolve to a node named "kernel at 1".
This aliasing was the basis of CVE-2021-27138, which was fixed by two
commits:
commit 3f04db891a35 ("image: Check for unit addresses in FITs")
commit 79af75f7776f ("fit: Don't allow verification of images with @
nodes")
Both address it by rejecting any FIT node whose name contains '@'. That is
overly broad: it also breaks FIT images that legitimately use unit
addresses in their node names.
Harden the lookup itself instead. Add a fit_subnode_offset_exact() helper
that wraps fdt_subnode_offset(), reads the resolved node name back with
fdt_get_name() and rejects the match unless it is identical to the
requested string, so a config referencing "kernel" no longer resolves to
"kernel at 1".
Use it in place of fdt_subnode_offset() at the FIT reference lookups in
fit_image_get_node(), fit_conf_get_node() and fit_conf_find_compat(), and
at the matching image lookups in the SPL FIT loader.
Signed-off-by: Lorenz Kofler <lorenz at sigma-star.at>
---
boot/image-fit.c | 7 +++----
common/spl/spl_fit.c | 4 ++--
include/image.h | 28 ++++++++++++++++++++++++++++
3 files changed, 33 insertions(+), 6 deletions(-)
diff --git a/boot/image-fit.c b/boot/image-fit.c
index b0fcaf6e17f..a6504cd8041 100644
--- a/boot/image-fit.c
+++ b/boot/image-fit.c
@@ -678,7 +678,7 @@ int fit_image_get_node(const void *fit, const char *image_uname)
return images_noffset;
}
- noffset = fdt_subnode_offset(fit, images_noffset, image_uname);
+ noffset = fit_subnode_offset_exact(fit, images_noffset, image_uname);
if (noffset < 0) {
debug("Can't get node offset for image unit name: '%s' (%s)\n",
image_uname, fdt_strerror(noffset));
@@ -1781,8 +1781,7 @@ int fit_conf_find_compat(const void *fit, const void *fdt)
debug("No fdt property found.\n");
continue;
}
- kfdt_noffset = fdt_subnode_offset(fit, images_noffset,
- kfdt_name);
+ kfdt_noffset = fit_subnode_offset_exact(fit, images_noffset, kfdt_name);
if (kfdt_noffset < 0) {
debug("No image node named \"%s\" found.\n",
kfdt_name);
@@ -1881,7 +1880,7 @@ int fit_conf_get_node(const void *fit, const char *conf_uname)
conf_uname = conf_uname_copy;
}
- noffset = fdt_subnode_offset(fit, confs_noffset, conf_uname);
+ noffset = fit_subnode_offset_exact(fit, confs_noffset, conf_uname);
if (noffset < 0) {
debug("Can't get node offset for configuration unit name: '%s' (%s)\n",
conf_uname, fdt_strerror(noffset));
diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c
index 46ebcabe56a..baa0214fa46 100644
--- a/common/spl/spl_fit.c
+++ b/common/spl/spl_fit.c
@@ -166,7 +166,7 @@ static int spl_fit_get_image_node(const struct spl_fit_info *ctx,
debug("%s: '%s'\n", type, str);
- node = fdt_subnode_offset(ctx->fit, ctx->images_node, str);
+ node = fit_subnode_offset_exact(ctx->fit, ctx->images_node, str);
if (node < 0) {
pr_err("cannot find image node '%s': %d\n", str, node);
return -EINVAL;
@@ -456,7 +456,7 @@ static int spl_fit_append_fdt(struct spl_image_info *spl_image,
if (ret)
continue;
- node = fdt_subnode_offset(ctx->fit, ctx->images_node, str);
+ node = fit_subnode_offset_exact(ctx->fit, ctx->images_node, str);
if (node < 0) {
debug("%s: unable to find FDT node %d\n",
__func__, index);
diff --git a/include/image.h b/include/image.h
index 34efac6056d..b3ddc9202a5 100644
--- a/include/image.h
+++ b/include/image.h
@@ -1156,6 +1156,34 @@ static inline const char *fit_get_name(const void *fit_hdr,
return fdt_get_name(fit_hdr, noffset, len);
}
+/**
+ * fit_subnode_offset_exact() - Find a subnode by exact node name
+ * @fit: FIT image
+ * @parent: Parent node offset
+ * @name: Exact child node name to look up
+ *
+ * fdt_subnode_offset() may ignore the unit-address suffix, so a request for
+ * "kernel" may resolve to a node named "kernel at 1". Verify that the returned
+ * node name exactly matches the requested name.
+ *
+ * Return: node offset on success, negative libfdt error value otherwise
+ */
+static inline int fit_subnode_offset_exact(const void *fit, int parent, const char *name)
+{
+ const char *actual;
+ int noffset;
+
+ noffset = fdt_subnode_offset(fit, parent, name);
+ if (noffset < 0)
+ return noffset;
+
+ actual = fdt_get_name(fit, noffset, NULL);
+ if (!actual || strcmp(actual, name))
+ return -FDT_ERR_NOTFOUND;
+
+ return noffset;
+}
+
int fit_get_desc(const void *fit, int noffset, char **desc);
int fit_get_timestamp(const void *fit, int noffset, time_t *timestamp);
--
2.54.0
More information about the U-Boot
mailing list