From 124c255731c76a2b09587378b2bcce561bcd3f2d Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Mon, 15 Feb 2021 17:08:11 -0700
Subject: [PATCH] libfdt: Check for multiple/invalid root nodes

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>

CVE: CVE-2021-27097
Upstream-Status: Backport[https://github.com/u-boot/u-boot/commit/124c255731c76a2b09587378b2bcce561bcd3f2d]
Signed-off-by: Scott Murray <scott.murray@konsulko.com>

---
 scripts/dtc/libfdt/fdt_ro.c | 17 +++++++++++++++++
 test/py/tests/test_vboot.py |  3 ++-
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/scripts/dtc/libfdt/fdt_ro.c b/scripts/dtc/libfdt/fdt_ro.c
index d984bab036..efe7efe921 100644
--- a/scripts/dtc/libfdt/fdt_ro.c
+++ b/scripts/dtc/libfdt/fdt_ro.c
@@ -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:
