libfdt: Check that the root-node name is empty
The root node is supposed to have an empty name, but at present this is not checked. The behaviour of such a tree is not well defined. Most software rightly assumes that the root node is at offset 0 and does not check the name. This oddity 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: <20210323010410.3222701-2-sjg@chromium.org> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>main
parent
4ca61f84dc
commit
a2def54799
|
@ -59,6 +59,16 @@ int fdt_check_full(const void *fdt, size_t bufsize)
|
||||||
depth++;
|
depth++;
|
||||||
if (depth > INT_MAX)
|
if (depth > INT_MAX)
|
||||||
return -FDT_ERR_BADSTRUCTURE;
|
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_BADSTRUCTURE;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FDT_END_NODE:
|
case FDT_END_NODE:
|
||||||
|
|
|
@ -33,7 +33,7 @@ LIB_TESTS_L = get_mem_rsv \
|
||||||
LIB_TESTS = $(LIB_TESTS_L:%=$(TESTS_PREFIX)%)
|
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
|
two_roots named_root
|
||||||
|
|
||||||
LIBTREE_TESTS = $(LIBTREE_TESTS_L:%=$(TESTS_PREFIX)%)
|
LIBTREE_TESTS = $(LIBTREE_TESTS_L:%=$(TESTS_PREFIX)%)
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,8 @@ static struct {
|
||||||
TREE(ovf_size_strings),
|
TREE(ovf_size_strings),
|
||||||
TREE(truncated_property), TREE(truncated_string),
|
TREE(truncated_property), TREE(truncated_string),
|
||||||
TREE(truncated_memrsv),
|
TREE(truncated_memrsv),
|
||||||
TREE(two_roots)
|
TREE(two_roots),
|
||||||
|
TREE(named_root)
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NUM_TREES (sizeof(trees) / sizeof(trees[0]))
|
#define NUM_TREES (sizeof(trees) / sizeof(trees[0]))
|
||||||
|
|
|
@ -518,7 +518,7 @@ libfdt_tests () {
|
||||||
run_test check_full $good
|
run_test check_full $good
|
||||||
done
|
done
|
||||||
for bad in truncated_property.dtb truncated_string.dtb \
|
for bad in truncated_property.dtb truncated_string.dtb \
|
||||||
truncated_memrsv.dtb two_roots.dtb; do
|
truncated_memrsv.dtb two_roots.dtb named_root.dtb; do
|
||||||
run_test check_full -n $bad
|
run_test check_full -n $bad
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,4 +56,5 @@ extern struct fdt_header ovf_size_strings;
|
||||||
extern struct fdt_header truncated_string;
|
extern struct fdt_header truncated_string;
|
||||||
extern struct fdt_header truncated_memrsv;
|
extern struct fdt_header truncated_memrsv;
|
||||||
extern struct fdt_header two_roots;
|
extern struct fdt_header two_roots;
|
||||||
|
extern struct fdt_header named_root;
|
||||||
#endif /* ! __ASSEMBLY */
|
#endif /* ! __ASSEMBLY */
|
||||||
|
|
|
@ -298,3 +298,18 @@ two_roots_strings_end:
|
||||||
|
|
||||||
two_roots_end:
|
two_roots_end:
|
||||||
|
|
||||||
|
|
||||||
|
/* root node with a non-empty name */
|
||||||
|
TREE_HDR(named_root)
|
||||||
|
EMPTY_RSVMAP(named_root)
|
||||||
|
|
||||||
|
named_root_struct:
|
||||||
|
BEGIN_NODE("fake")
|
||||||
|
END_NODE
|
||||||
|
FDTLONG(FDT_END)
|
||||||
|
named_root_struct_end:
|
||||||
|
|
||||||
|
named_root_strings:
|
||||||
|
named_root_strings_end:
|
||||||
|
|
||||||
|
named_root_end:
|
||||||
|
|
Loading…
Reference in New Issue