Browse Source

libfdt: Check that there is only one root node

At present it is possible to have two root nodes and even access nodes
in the 'second' root. Such trees should not be considered valid. This
was discovered as part of a security investigation into U-Boot verified
boot.

Add a check for this to fdt_check_full().

Signed-off-by: Simon Glass <sjg@chromium.org>
Reported-by: Arie Haenel <arie.haenel@intel.com>
Reported-by: Julien Lenoir <julien.lenoir@intel.com>
Message-Id: <20210323000926.3210733-1-sjg@chromium.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
main
Simon Glass 4 years ago committed by David Gibson
parent
commit
4ca61f84dc
  1. 7
      libfdt/fdt_check.c
  2. 4
      tests/Makefile.tests
  3. 1
      tests/dumptrees.c
  4. 2
      tests/run_tests.sh
  5. 1
      tests/testdata.h
  6. 19
      tests/trees.S

7
libfdt/fdt_check.c

@ -19,6 +19,7 @@ int fdt_check_full(const void *fdt, size_t bufsize) @@ -19,6 +19,7 @@ int fdt_check_full(const void *fdt, size_t bufsize)
unsigned int depth = 0;
const void *prop;
const char *propname;
bool expect_end = false;

if (bufsize < FDT_V1_SIZE)
return -FDT_ERR_TRUNCATED;
@ -41,6 +42,10 @@ int fdt_check_full(const void *fdt, size_t bufsize) @@ -41,6 +42,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_BADSTRUCTURE;

switch (tag) {
case FDT_NOP:
break;
@ -60,6 +65,8 @@ int fdt_check_full(const void *fdt, size_t bufsize) @@ -60,6 +65,8 @@ int fdt_check_full(const void *fdt, size_t bufsize)
if (depth == 0)
return -FDT_ERR_BADSTRUCTURE;
depth--;
if (depth == 0)
expect_end = true;
break;

case FDT_PROP:

4
tests/Makefile.tests

@ -32,7 +32,9 @@ LIB_TESTS_L = get_mem_rsv \ @@ -32,7 +32,9 @@ LIB_TESTS_L = get_mem_rsv \
fs_tree1
LIB_TESTS = $(LIB_TESTS_L:%=$(TESTS_PREFIX)%)

LIBTREE_TESTS_L = truncated_property truncated_string truncated_memrsv
LIBTREE_TESTS_L = truncated_property truncated_string truncated_memrsv \
two_roots

LIBTREE_TESTS = $(LIBTREE_TESTS_L:%=$(TESTS_PREFIX)%)

DL_LIB_TESTS_L = asm_tree_dump value-labels

1
tests/dumptrees.c

@ -24,6 +24,7 @@ static struct { @@ -24,6 +24,7 @@ static struct {
TREE(ovf_size_strings),
TREE(truncated_property), TREE(truncated_string),
TREE(truncated_memrsv),
TREE(two_roots)
};

#define NUM_TREES (sizeof(trees) / sizeof(trees[0]))

2
tests/run_tests.sh

@ -518,7 +518,7 @@ libfdt_tests () { @@ -518,7 +518,7 @@ libfdt_tests () {
run_test check_full $good
done
for bad in truncated_property.dtb truncated_string.dtb \
truncated_memrsv.dtb; do
truncated_memrsv.dtb two_roots.dtb; do
run_test check_full -n $bad
done
}

1
tests/testdata.h

@ -55,4 +55,5 @@ extern struct fdt_header bad_prop_char; @@ -55,4 +55,5 @@ extern struct fdt_header bad_prop_char;
extern struct fdt_header ovf_size_strings;
extern struct fdt_header truncated_string;
extern struct fdt_header truncated_memrsv;
extern struct fdt_header two_roots;
#endif /* ! __ASSEMBLY */

19
tests/trees.S

@ -279,3 +279,22 @@ truncated_memrsv_rsvmap: @@ -279,3 +279,22 @@ truncated_memrsv_rsvmap:
truncated_memrsv_rsvmap_end:

truncated_memrsv_end:


/* two root nodes */
TREE_HDR(two_roots)
EMPTY_RSVMAP(two_roots)

two_roots_struct:
BEGIN_NODE("")
END_NODE
BEGIN_NODE("")
END_NODE
FDTLONG(FDT_END)
two_roots_struct_end:

two_roots_strings:
two_roots_strings_end:

two_roots_end:


Loading…
Cancel
Save