From: Binarly Vulnerability Research <[email protected]>
The fdt_find_regions() function in boot/fdt_region.c walks the FDT
structure block one tag at a time, building the list of regions to
feed into the signature hash. When it sees an FDT_PROP tag it reads
the property header to retrieve the property name:
case FDT_PROP:
include = want >= 2;
stop_at = offset;
prop = fdt_get_property_by_offset(fdt, offset, NULL);
str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
fdt_get_property_by_offset() in scripts/dtc/libfdt/fdt_ro.c
explicitly returns NULL for any FDT with 'fdt_version < 0x10':
const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
int offset,
int *lenp)
{
/* Prior to version 16, properties may need realignment
* and this API does not work. fdt_getprop_*() will, however. */
if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
if (lenp)
*lenp = -FDT_ERR_BADVERSION;
return NULL;
}
return fdt_get_property_by_offset_(fdt, offset, lenp);
}
A FIT image with a version less than 0x10 causes 'prop' to be null
on the very first FDT_PROP tag the iterator reaches. The next line
dereferences prop->nameoff, which leads to a null pointer
dereference on platforms where the zero page is not mapped.
The same lack of validation exists in fdt_add_alias_regions() and
in fdt_next_region() in boot/fdt_region.c.
Fix: Validate the returned pointer before use.
Signed-off-by: Binarly Vulnerability Research <[email protected]>
---
boot/fdt_region.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/boot/fdt_region.c b/boot/fdt_region.c
index 295ea08ac91..0a9d47bb2bd 100644
--- a/boot/fdt_region.c
+++ b/boot/fdt_region.c
@@ -69,6 +69,8 @@ int fdt_find_regions(const void *fdt, char * const inc[], int
inc_count,
include = want >= 2;
stop_at = offset;
prop = fdt_get_property_by_offset(fdt, offset, NULL);
+ if (!prop)
+ return -FDT_ERR_BADSTRUCTURE;
str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
if (!str)
return -FDT_ERR_BADSTRUCTURE;
@@ -271,7 +273,11 @@ int fdt_add_alias_regions(const void *fdt, struct
fdt_region *region, int count,
int target, next;
prop = fdt_get_property_by_offset(fdt, offset, NULL);
+ if (!prop)
+ return -FDT_ERR_BADSTRUCTURE;
name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
+ if (!name)
+ return -FDT_ERR_BADSTRUCTURE;
target = fdt_path_offset(fdt, name);
if (!region_list_contains_offset(info, fdt, target))
continue;
@@ -520,7 +526,11 @@ int fdt_next_region(const void *fdt,
case FDT_PROP:
stop_at = offset;
prop = fdt_get_property_by_offset(fdt, offset, NULL);
+ if (!prop)
+ return -FDT_ERR_BADSTRUCTURE;
str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
+ if (!str)
+ return -FDT_ERR_BADSTRUCTURE;
val = h_include(priv, fdt, last_node, FDT_IS_PROP, str,
strlen(str) + 1);
if (val == -1) {
--
2.53.0