The ofnode_to_offset() may return -1 , which is not a valid value and is not accepted by modern libfdt 1.7.2. Check the return value from ofnode_to_offset() and exit early in case it is not a valid offset.
Signed-off-by: Marek Vasut <[email protected]> --- Cc: Adriano Cordova <[email protected]> Cc: Andrew Goodbody <[email protected]> Cc: Christian Marangi <[email protected]> Cc: Heinrich Schuchardt <[email protected]> Cc: Ilias Apalodimas <[email protected]> Cc: Patrice Chotard <[email protected]> Cc: Sam Edwards <[email protected]> Cc: Simon Glass <[email protected]> Cc: Tom Rini <[email protected]> Cc: [email protected] --- drivers/core/ofnode.c | 384 +++++++++++++++++++++++++++++++----------- 1 file changed, 284 insertions(+), 100 deletions(-) diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index 071d998a0a5..55c2b3a10bb 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -335,7 +335,7 @@ bool ofnode_name_eq_unit(ofnode node, const char *name) int ofnode_read_u8(ofnode node, const char *propname, u8 *outp) { const u8 *cell; - int len; + int len, off; assert(ofnode_valid(node)); log_debug("%s: %s: ", __func__, propname); @@ -343,8 +343,13 @@ int ofnode_read_u8(ofnode node, const char *propname, u8 *outp) if (ofnode_is_np(node)) return of_read_u8(ofnode_to_np(node), propname, outp); - cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname, - &len); + off = ofnode_to_offset(node); + if (off < 0) { + log_debug("(not valid)\n"); + return -EINVAL; + } + + cell = fdt_getprop(gd->fdt_blob, off, propname, &len); if (!cell || len < sizeof(*cell)) { log_debug("(not found)\n"); return -EINVAL; @@ -366,7 +371,7 @@ u8 ofnode_read_u8_default(ofnode node, const char *propname, u8 def) int ofnode_read_u16(ofnode node, const char *propname, u16 *outp) { const fdt16_t *cell; - int len; + int len, off; assert(ofnode_valid(node)); log_debug("%s: %s: ", __func__, propname); @@ -374,8 +379,13 @@ int ofnode_read_u16(ofnode node, const char *propname, u16 *outp) if (ofnode_is_np(node)) return of_read_u16(ofnode_to_np(node), propname, outp); - cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname, - &len); + off = ofnode_to_offset(node); + if (off < 0) { + log_debug("(not valid)\n"); + return -EINVAL; + } + + cell = fdt_getprop(gd->fdt_blob, off, propname, &len); if (!cell || len < sizeof(*cell)) { log_debug("(not found)\n"); return -EINVAL; @@ -411,7 +421,7 @@ int ofnode_read_u32_index(ofnode node, const char *propname, int index, u32 *outp) { const fdt32_t *cell; - int len; + int len, off; assert(ofnode_valid(node)); log_debug("%s: %s: ", __func__, propname); @@ -420,8 +430,13 @@ int ofnode_read_u32_index(ofnode node, const char *propname, int index, return of_read_u32_index(ofnode_to_np(node), propname, index, outp); - cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node), - propname, &len); + off = ofnode_to_offset(node); + if (off < 0) { + log_debug("(not valid)\n"); + return -EINVAL; + } + + cell = fdt_getprop(ofnode_to_fdt(node), off, propname, &len); if (!cell) { log_debug("(not found)\n"); return -EINVAL; @@ -442,7 +457,7 @@ int ofnode_read_u64_index(ofnode node, const char *propname, int index, u64 *outp) { const fdt64_t *cell; - int len; + int len, off; assert(ofnode_valid(node)); @@ -450,8 +465,13 @@ int ofnode_read_u64_index(ofnode node, const char *propname, int index, return of_read_u64_index(ofnode_to_np(node), propname, index, outp); - cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node), - propname, &len); + off = ofnode_to_offset(node); + if (off < 0) { + log_debug("(not valid)\n"); + return -EINVAL; + } + + cell = fdt_getprop(ofnode_to_fdt(node), off, propname, &len); if (!cell) { log_debug("(not found)\n"); return -EINVAL; @@ -488,7 +508,7 @@ int ofnode_read_s32_default(ofnode node, const char *propname, s32 def) int ofnode_read_u64(ofnode node, const char *propname, u64 *outp) { const unaligned_fdt64_t *cell; - int len; + int len, off; assert(ofnode_valid(node)); log_debug("%s: %s: ", __func__, propname); @@ -496,8 +516,13 @@ int ofnode_read_u64(ofnode node, const char *propname, u64 *outp) if (ofnode_is_np(node)) return of_read_u64(ofnode_to_np(node), propname, outp); - cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node), - propname, &len); + off = ofnode_to_offset(node); + if (off < 0) { + log_debug("(not valid)\n"); + return -EINVAL; + } + + cell = fdt_getprop(ofnode_to_fdt(node), off, propname, &len); if (!cell || len < sizeof(*cell)) { log_debug("(not found)\n"); return -EINVAL; @@ -534,7 +559,7 @@ bool ofnode_read_bool(ofnode node, const char *propname) const void *ofnode_read_prop(ofnode node, const char *propname, int *sizep) { const char *val = NULL; - int len; + int len, off; assert(ofnode_valid(node)); log_debug("%s: %s: ", __func__, propname); @@ -548,8 +573,13 @@ const void *ofnode_read_prop(ofnode node, const char *propname, int *sizep) len = prop->length; } } else { - val = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node), - propname, &len); + off = ofnode_to_offset(node); + if (off < 0) { + log_debug("<not valid>\n"); + return NULL; + } + + val = fdt_getprop(ofnode_to_fdt(node), off, propname, &len); } if (!val) { log_debug("<not found>\n"); @@ -602,8 +632,13 @@ ofnode ofnode_find_subnode(ofnode node, const char *subnode_name) subnode = ofnode_find_subnode_unit(node, subnode_name); } else { /* special case to avoid code-size increase */ - int ooffset = fdt_subnode_offset(ofnode_to_fdt(node), - ofnode_to_offset(node), subnode_name); + int ooffset, off; + + off = ofnode_to_offset(node); + if (off < 0) + return ofnode_null(); + + ooffset = fdt_subnode_offset(ofnode_to_fdt(node), off, subnode_name); subnode = noffset_to_ofnode(node, ooffset); } log_debug("%s\n", ofnode_valid(subnode) ? @@ -642,11 +677,14 @@ int ofnode_read_u32_array(ofnode node, const char *propname, return of_read_u32_array(ofnode_to_np(node), propname, out_values, sz); } else { - int ret; + int ret, off; + + off = ofnode_to_offset(node); + if (off < 0) + return -EINVAL; - ret = fdtdec_get_int_array(ofnode_to_fdt(node), - ofnode_to_offset(node), propname, - out_values, sz); + ret = fdtdec_get_int_array(ofnode_to_fdt(node), off, + propname, out_values, sz); /* get the error right, but space is more important in SPL */ if (!IS_ENABLED(CONFIG_XPL_BUILD)) { @@ -665,48 +703,71 @@ bool ofnode_is_enabled(ofnode node) if (ofnode_is_np(node)) { return of_device_is_available(ofnode_to_np(node)); } else { - return fdtdec_get_is_enabled(ofnode_to_fdt(node), - ofnode_to_offset(node)); + int off = ofnode_to_offset(node); + + if (off < 0) + return false; + + return fdtdec_get_is_enabled(ofnode_to_fdt(node), off); } } ofnode ofnode_first_subnode(ofnode node) { + int off; + assert(ofnode_valid(node)); if (ofnode_is_np(node)) return np_to_ofnode(node.np->child); + off = ofnode_to_offset(node); + if (off < 0) + return ofnode_null(); + return noffset_to_ofnode(node, - fdt_first_subnode(ofnode_to_fdt(node), ofnode_to_offset(node))); + fdt_first_subnode(ofnode_to_fdt(node), off)); } ofnode ofnode_next_subnode(ofnode node) { + int off; + assert(ofnode_valid(node)); if (ofnode_is_np(node)) return np_to_ofnode(node.np->sibling); + off = ofnode_to_offset(node); + if (off < 0) + return ofnode_null(); + return noffset_to_ofnode(node, - fdt_next_subnode(ofnode_to_fdt(node), ofnode_to_offset(node))); + fdt_next_subnode(ofnode_to_fdt(node), off)); } #endif /* !DM_INLINE_OFNODE */ ofnode ofnode_get_parent(ofnode node) { ofnode parent; + int off; assert(ofnode_valid(node)); - if (ofnode_is_np(node)) + if (ofnode_is_np(node)) { parent = np_to_ofnode(of_get_parent(ofnode_to_np(node))); - else - parent.of_offset = fdt_parent_offset(ofnode_to_fdt(node), - ofnode_to_offset(node)); + } else { + off = ofnode_to_offset(node); + if (off < 0) + return ofnode_null(); + + parent.of_offset = fdt_parent_offset(ofnode_to_fdt(node), off); + } return parent; } const char *ofnode_get_name(ofnode node) { + int off; + if (!ofnode_valid(node)) { dm_warn("%s node not valid\n", __func__); return NULL; @@ -715,7 +776,11 @@ const char *ofnode_get_name(ofnode node) if (ofnode_is_np(node)) return node.np->name; - return fdt_get_name(ofnode_to_fdt(node), ofnode_to_offset(node), NULL); + off = ofnode_to_offset(node); + if (off < 0) + return NULL; + + return fdt_get_name(ofnode_to_fdt(node), off, NULL); } int ofnode_get_path(ofnode node, char *buf, int buflen) @@ -730,10 +795,13 @@ int ofnode_get_path(ofnode node, char *buf, int buflen) return 0; } else { - int res; + int off, res; - res = fdt_get_path(ofnode_to_fdt(node), ofnode_to_offset(node), buf, - buflen); + off = ofnode_to_offset(node); + if (off < 0) + return -EINVAL; + + res = fdt_get_path(ofnode_to_fdt(node), off, buf, buflen); if (!res) return res; else if (res == -FDT_ERR_NOSPACE) @@ -773,7 +841,7 @@ ofnode oftree_get_by_phandle(oftree tree, uint phandle) static fdt_addr_t __ofnode_get_addr_size_index(ofnode node, int index, fdt_size_t *size, bool translate) { - int na, ns; + int na, ns, off; if (size) *size = FDT_SIZE_T_NONE; @@ -803,8 +871,13 @@ static fdt_addr_t __ofnode_get_addr_size_index(ofnode node, int index, ofnode parent = ofnode_get_parent(node); na = ofnode_read_simple_addr_cells(parent); ns = ofnode_read_simple_size_cells(parent); + + off = ofnode_to_offset(node); + if (off < 0) + return FDT_ADDR_T_NONE; + return fdtdec_get_addr_size_fixed(ofnode_to_fdt(node), - ofnode_to_offset(node), "reg", + off, "reg", index, na, ns, size, translate); } @@ -849,10 +922,14 @@ int ofnode_stringlist_search(ofnode node, const char *property, return of_property_match_string(ofnode_to_np(node), property, string); } else { - int ret; + int ret, off; + + off = ofnode_to_offset(node); + if (off < 0) + return -EINVAL; ret = fdt_stringlist_search(ofnode_to_fdt(node), - ofnode_to_offset(node), property, + off, property, string); if (ret == -FDT_ERR_NOTFOUND) return -ENODATA; @@ -870,10 +947,13 @@ int ofnode_read_string_index(ofnode node, const char *property, int index, return of_property_read_string_index(ofnode_to_np(node), property, index, outp); } else { - int len; + int len, off; + + off = ofnode_to_offset(node); + if (off < 0) + return -EINVAL; - *outp = fdt_stringlist_get(ofnode_to_fdt(node), - ofnode_to_offset(node), + *outp = fdt_stringlist_get(ofnode_to_fdt(node), off, property, index, &len); if (len < 0) return -EINVAL; @@ -883,11 +963,17 @@ int ofnode_read_string_index(ofnode node, const char *property, int index, int ofnode_read_string_count(ofnode node, const char *property) { + int off; + if (ofnode_is_np(node)) { return of_property_count_strings(ofnode_to_np(node), property); } else { + off = ofnode_to_offset(node); + if (off < 0) + return -EINVAL; + return fdt_stringlist_count(ofnode_to_fdt(node), - ofnode_to_offset(node), property); + off, property); } } @@ -933,10 +1019,13 @@ ofnode ofnode_parse_phandle(ofnode node, const char *phandle_name, phandle = np_to_ofnode(np); } else { struct fdtdec_phandle_args args; + int off = ofnode_to_offset(node); + + if (off < 0) + return ofnode_null(); if (fdtdec_parse_phandle_with_args(ofnode_to_fdt(node), - ofnode_to_offset(node), - phandle_name, NULL, + off, phandle_name, NULL, 0, index, &args)) return ofnode_null(); @@ -962,10 +1051,13 @@ ofnode oftree_parse_phandle(oftree tree, ofnode node, const char *phandle_name, phandle = np_to_ofnode(np); } else { struct fdtdec_phandle_args args; + int off = ofnode_to_offset(node); + + if (off < 0) + return ofnode_null(); if (fdtdec_parse_phandle_with_args(tree.fdt, - ofnode_to_offset(node), - phandle_name, NULL, + off, phandle_name, NULL, 0, index, &args)) return ofnode_null(); @@ -1011,11 +1103,14 @@ int ofnode_parse_phandle_with_args(ofnode node, const char *list_name, ofnode_from_of_phandle_args(&args, out_args); } else { struct fdtdec_phandle_args args; + int off = ofnode_to_offset(node); int ret; + if (off < 0) + return -EINVAL; + ret = fdtdec_parse_phandle_with_args(ofnode_to_fdt(node), - ofnode_to_offset(node), - list_name, cells_name, + off, list_name, cells_name, cell_count, index, &args); if (ret) return ret; @@ -1044,11 +1139,14 @@ int oftree_parse_phandle_with_args(oftree tree, ofnode node, const char *list_na ofnode_from_of_phandle_args(&args, out_args); } else { struct fdtdec_phandle_args args; + int off = ofnode_to_offset(node); int ret; + if (off < 0) + return -EINVAL; + ret = fdtdec_parse_phandle_with_args(tree.fdt, - ofnode_to_offset(node), - list_name, cells_name, + off, list_name, cells_name, cell_count, index, &args); if (ret) return ret; @@ -1061,25 +1159,37 @@ int oftree_parse_phandle_with_args(oftree tree, ofnode node, const char *list_na int ofnode_count_phandle_with_args(ofnode node, const char *list_name, const char *cells_name, int cell_count) { - if (ofnode_is_np(node)) + if (ofnode_is_np(node)) { return of_count_phandle_with_args(ofnode_to_np(node), list_name, cells_name, cell_count); - else + } else { + int off = ofnode_to_offset(node); + + if (off < 0) + return -EINVAL; + return fdtdec_parse_phandle_with_args(ofnode_to_fdt(node), - ofnode_to_offset(node), list_name, cells_name, + off, list_name, cells_name, cell_count, -1, NULL); + } } int oftree_count_phandle_with_args(oftree tree, ofnode node, const char *list_name, const char *cells_name, int cell_count) { - if (ofnode_is_np(node)) + if (ofnode_is_np(node)) { return of_root_count_phandle_with_args(tree.np, ofnode_to_np(node), list_name, cells_name, cell_count); - else + } else { + int off = ofnode_to_offset(node); + + if (off < 0) + return -EINVAL; + return fdtdec_parse_phandle_with_args(tree.fdt, - ofnode_to_offset(node), list_name, cells_name, + off, list_name, cells_name, cell_count, -1, NULL); + } } ofnode ofnode_path(const char *path) @@ -1326,11 +1436,16 @@ int ofnode_decode_panel_timing(ofnode parent, const void *ofnode_get_property(ofnode node, const char *propname, int *lenp) { - if (ofnode_is_np(node)) + if (ofnode_is_np(node)) { return of_get_property(ofnode_to_np(node), propname, lenp); - else - return fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node), - propname, lenp); + } else { + int off = ofnode_to_offset(node); + + if (off < 0) + return NULL; + + return fdt_getprop(ofnode_to_fdt(node), off, propname, lenp); + } } bool ofnode_has_property(ofnode node, const char *propname) @@ -1350,9 +1465,13 @@ int ofnode_first_property(ofnode node, struct ofprop *prop) if (!prop->prop) return -FDT_ERR_NOTFOUND; } else { + int off = ofnode_to_offset(prop->node); + + if (off < 0) + return -EINVAL; + prop->offset = - fdt_first_property_offset(ofnode_to_fdt(node), - ofnode_to_offset(prop->node)); + fdt_first_property_offset(ofnode_to_fdt(node), off); if (prop->offset < 0) return prop->offset; } @@ -1410,9 +1529,13 @@ fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property, else return of_read_number(prop, na); } else { + int off = ofnode_to_offset(node); + + if (off < 0) + return FDT_ADDR_T_NONE; + return fdtdec_get_addr_size(ofnode_to_fdt(node), - ofnode_to_offset(node), property, - sizep); + off, property, sizep); } } @@ -1429,8 +1552,13 @@ const uint8_t *ofnode_read_u8_array_ptr(ofnode node, const char *propname, return (uint8_t *)prop; } else { + int off = ofnode_to_offset(node); + + if (off < 0) + return NULL; + return fdtdec_locate_byte_array(ofnode_to_fdt(node), - ofnode_to_offset(node), propname, sz); + off, propname, sz); } } @@ -1570,8 +1698,12 @@ int ofnode_read_addr_cells(ofnode node) if (ofnode_is_np(node)) { return of_n_addr_cells(ofnode_to_np(node)); } else { - int parent = fdt_parent_offset(ofnode_to_fdt(node), - ofnode_to_offset(node)); + int parent, off = ofnode_to_offset(node); + + if (off < 0) + return -EINVAL; + + parent = fdt_parent_offset(ofnode_to_fdt(node), off); return fdt_address_cells(ofnode_to_fdt(node), parent); } @@ -1582,8 +1714,12 @@ int ofnode_read_size_cells(ofnode node) if (ofnode_is_np(node)) { return of_n_size_cells(ofnode_to_np(node)); } else { - int parent = fdt_parent_offset(ofnode_to_fdt(node), - ofnode_to_offset(node)); + int parent, off = ofnode_to_offset(node); + + if (off < 0) + return -EINVAL; + + parent = fdt_parent_offset(ofnode_to_fdt(node), off); return fdt_size_cells(ofnode_to_fdt(node), parent); } @@ -1591,20 +1727,30 @@ int ofnode_read_size_cells(ofnode node) int ofnode_read_simple_addr_cells(ofnode node) { - if (ofnode_is_np(node)) + if (ofnode_is_np(node)) { return of_simple_addr_cells(ofnode_to_np(node)); - else - return fdt_address_cells(ofnode_to_fdt(node), - ofnode_to_offset(node)); + } else { + int off = ofnode_to_offset(node); + + if (off < 0) + return -EINVAL; + + return fdt_address_cells(ofnode_to_fdt(node), off); + } } int ofnode_read_simple_size_cells(ofnode node) { - if (ofnode_is_np(node)) + if (ofnode_is_np(node)) { return of_simple_size_cells(ofnode_to_np(node)); - else - return fdt_size_cells(ofnode_to_fdt(node), - ofnode_to_offset(node)); + } else { + int off = ofnode_to_offset(node); + + if (off < 0) + return -EINVAL; + + return fdt_size_cells(ofnode_to_fdt(node), off); + } } bool ofnode_pre_reloc(ofnode node) @@ -1639,10 +1785,13 @@ int ofnode_read_resource(ofnode node, uint index, struct resource *res) return of_address_to_resource(ofnode_to_np(node), index, res); } else { struct fdt_resource fres; + int off = ofnode_to_offset(node); int ret; - ret = fdt_get_resource(ofnode_to_fdt(node), - ofnode_to_offset(node), + if (off < 0) + return -EINVAL; + + ret = fdt_get_resource(ofnode_to_fdt(node), off, "reg", index, &fres); if (ret < 0) return -EINVAL; @@ -1668,41 +1817,61 @@ int ofnode_read_resource_byname(ofnode node, const char *name, u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr) { - if (ofnode_is_np(node)) + if (ofnode_is_np(node)) { return of_translate_address(ofnode_to_np(node), in_addr); - else - return fdt_translate_address(ofnode_to_fdt(node), - ofnode_to_offset(node), in_addr); + } else { + int off = ofnode_to_offset(node); + + if (off < 0) + return OF_BAD_ADDR; + + return fdt_translate_address(ofnode_to_fdt(node), off, in_addr); + } } u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr) { - if (ofnode_is_np(node)) + if (ofnode_is_np(node)) { return of_translate_dma_address(ofnode_to_np(node), in_addr); - else - return fdt_translate_dma_address(ofnode_to_fdt(node), - ofnode_to_offset(node), in_addr); + } else { + int off = ofnode_to_offset(node); + + if (off < 0) + return OF_BAD_ADDR; + + return fdt_translate_dma_address(ofnode_to_fdt(node), off, in_addr); + } } int ofnode_get_dma_range(ofnode node, phys_addr_t *cpu, dma_addr_t *bus, u64 *size) { - if (ofnode_is_np(node)) + if (ofnode_is_np(node)) { return of_get_dma_range(ofnode_to_np(node), cpu, bus, size); - else - return fdt_get_dma_range(ofnode_to_fdt(node), - ofnode_to_offset(node), + } else { + int off = ofnode_to_offset(node); + + if (off < 0) + return -EINVAL; + + return fdt_get_dma_range(ofnode_to_fdt(node), off, cpu, bus, size); + } } int ofnode_device_is_compatible(ofnode node, const char *compat) { - if (ofnode_is_np(node)) + if (ofnode_is_np(node)) { return of_device_is_compatible(ofnode_to_np(node), compat, NULL, NULL); - else - return !fdt_node_check_compatible(ofnode_to_fdt(node), - ofnode_to_offset(node), + } else { + int off = ofnode_to_offset(node); + + if (off < 0) + return 0; + + return !fdt_node_check_compatible(ofnode_to_fdt(node), off, compat); + } } ofnode ofnode_by_compatible(ofnode from, const char *compat) @@ -1753,7 +1922,12 @@ int ofnode_write_prop(ofnode node, const char *propname, const void *value, free(newval); return ret; } else { - ret = fdt_setprop(ofnode_to_fdt(node), ofnode_to_offset(node), + int off = ofnode_to_offset(node); + + if (off < 0) + return -EINVAL; + + ret = fdt_setprop(ofnode_to_fdt(node), off, propname, value, len); if (ret) return ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EINVAL; @@ -1821,8 +1995,12 @@ int ofnode_delete_prop(ofnode node, const char *propname) return of_remove_property(ofnode_to_np(node), prop); return 0; } else { - return fdt_delprop(ofnode_to_fdt(node), ofnode_to_offset(node), - propname); + int off = ofnode_to_offset(node); + + if (off < 0) + return -EINVAL; + + return fdt_delprop(ofnode_to_fdt(node), off, propname); } } @@ -2040,6 +2218,9 @@ int ofnode_add_subnode(ofnode node, const char *name, ofnode *subnodep) int poffset = ofnode_to_offset(node); int offset; + if (poffset < 0) + return -FDT_ERR_NOTFOUND; + offset = fdt_add_subnode(fdt, poffset, name); if (offset == -FDT_ERR_EXISTS) { offset = fdt_subnode_offset(fdt, poffset, name); @@ -2067,6 +2248,9 @@ int ofnode_delete(ofnode *nodep) void *fdt = ofnode_to_fdt(node); int offset = ofnode_to_offset(node); + if (offset < 0) + return -EINVAL; + ret = fdt_del_node(fdt, offset); if (ret) ret = -EFAULT; -- 2.51.0

