[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