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

Reply via email to