[PATCH] libfdt: Check for multiple/invalid root nodes
authorSimon Glass <sjg@chromium.org>
Tue, 16 Feb 2021 00:08:11 +0000 (17:08 -0700)
committerDaniel Leidert <dleidert@debian.org>
Sun, 29 Jun 2025 00:33:57 +0000 (02:33 +0200)
It is possible to construct a devicetree blob with multiple root nodes.
Update fdt_check_full() to check for this, along with a root node with an
invalid name.

CVE-2021-27097

Signed-off-by: Simon Glass <sjg@chromium.org>
Reported-by: Bruce Monroe <bruce.monroe@intel.com>
Reported-by: Arie Haenel <arie.haenel@intel.com>
Reported-by: Julien Lenoir <julien.lenoir@intel.com>
The test part has not been patched. It would require these patches as well:
https://github.com/u-boot/u-boot/commit/fafafacb470b345f2f41b86e4633ef91a7c5ed23
https://github.com/u-boot/u-boot/commit/d5f3aadacbc63df3b690d6fd9f0aa3f575b43356

Reviewed-By: Daniel Leidert <dleidert@debian.org>
Origin: https://github.com/u-boot/u-boot/commit/124c255731c76a2b09587378b2bcce561bcd3f2d
Bug: https://github.com/advisories/GHSA-3w66-96j7-fmcp
Bug-Debian: https://bugs.debian.org/983270
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2021-27097
Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2021-27097

Gbp-Pq: Name CVE-2021-27097-4.patch

scripts/dtc/libfdt/fdt_ro.c

index d984bab036b59b365328a7d46fd1b424bee4dc89..efe7efe92115117db7ff65ece031b175c3110ebc 100644 (file)
@@ -867,6 +867,7 @@ int fdt_check_full(const void *fdt, size_t bufsize)
        unsigned depth = 0;
        const void *prop;
        const char *propname;
+       bool expect_end = false;
 
        if (bufsize < FDT_V1_SIZE)
                return -FDT_ERR_TRUNCATED;
@@ -887,6 +888,10 @@ int fdt_check_full(const void *fdt, size_t bufsize)
                if (nextoffset < 0)
                        return nextoffset;
 
+               /* If we see two root nodes, something is wrong */
+               if (expect_end && tag != FDT_END)
+                       return -FDT_ERR_BADLAYOUT;
+
                switch (tag) {
                case FDT_NOP:
                        break;
@@ -900,12 +905,24 @@ int fdt_check_full(const void *fdt, size_t bufsize)
                        depth++;
                        if (depth > INT_MAX)
                                return -FDT_ERR_BADSTRUCTURE;
+
+                       /* The root node must have an empty name */
+                       if (depth == 1) {
+                               const char *name;
+                               int len;
+
+                               name = fdt_get_name(fdt, offset, &len);
+                               if (*name || len)
+                                       return -FDT_ERR_BADLAYOUT;
+                       }
                        break;
 
                case FDT_END_NODE:
                        if (depth == 0)
                                return -FDT_ERR_BADSTRUCTURE;
                        depth--;
+                       if (depth == 0)
+                               expect_end = true;
                        break;
 
                case FDT_PROP: