From: Frank Rowand frank.rowand@sony.com
commit 637392a8506a3a7dd24ab9094a14f7522adb73b4 upstream.
No changeset entries are created for #address-cells and #size-cells properties, but the duplicated properties are never freed. This results in a memory leak which is detected by kmemleak:
unreferenced object 0x85887180 (size 64): backtrace: kmem_cache_alloc_trace+0x1fb/0x1fc __of_prop_dup+0x25/0x7c add_changeset_property+0x17f/0x370 build_changeset_next_level+0x29/0x20c of_overlay_fdt_apply+0x32b/0x6b4 ...
Fixes: 6f75118800ac ("of: overlay: validate overlay properties #address-cells and #size-cells") Reported-by: Vincent Whitchurch vincent.whitchurch@axis.com Signed-off-by: Frank Rowand frank.rowand@sony.com Tested-by: Vincent Whitchurch vincent.whitchurch@axis.com Signed-off-by: Rob Herring robh@kernel.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- drivers/of/overlay.c | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-)
--- a/drivers/of/overlay.c +++ b/drivers/of/overlay.c @@ -305,7 +305,6 @@ static int add_changeset_property(struct { struct property *new_prop = NULL, *prop; int ret = 0; - bool check_for_non_overlay_node = false;
if (target->in_livetree) if (!of_prop_cmp(overlay_prop->name, "name") || @@ -318,6 +317,25 @@ static int add_changeset_property(struct else prop = NULL;
+ if (prop) { + if (!of_prop_cmp(prop->name, "#address-cells")) { + if (!of_prop_val_eq(prop, overlay_prop)) { + pr_err("ERROR: changing value of #address-cells is not allowed in %pOF\n", + target->np); + ret = -EINVAL; + } + return ret; + + } else if (!of_prop_cmp(prop->name, "#size-cells")) { + if (!of_prop_val_eq(prop, overlay_prop)) { + pr_err("ERROR: changing value of #size-cells is not allowed in %pOF\n", + target->np); + ret = -EINVAL; + } + return ret; + } + } + if (is_symbols_prop) { if (prop) return -EINVAL; @@ -330,33 +348,18 @@ static int add_changeset_property(struct return -ENOMEM;
if (!prop) { - check_for_non_overlay_node = true; if (!target->in_livetree) { new_prop->next = target->np->deadprops; target->np->deadprops = new_prop; } ret = of_changeset_add_property(&ovcs->cset, target->np, new_prop); - } else if (!of_prop_cmp(prop->name, "#address-cells")) { - if (!of_prop_val_eq(prop, new_prop)) { - pr_err("ERROR: changing value of #address-cells is not allowed in %pOF\n", - target->np); - ret = -EINVAL; - } - } else if (!of_prop_cmp(prop->name, "#size-cells")) { - if (!of_prop_val_eq(prop, new_prop)) { - pr_err("ERROR: changing value of #size-cells is not allowed in %pOF\n", - target->np); - ret = -EINVAL; - } } else { - check_for_non_overlay_node = true; ret = of_changeset_update_property(&ovcs->cset, target->np, new_prop); }
- if (check_for_non_overlay_node && - !of_node_check_flag(target->np, OF_OVERLAY)) + if (!of_node_check_flag(target->np, OF_OVERLAY)) pr_err("WARNING: memory leak will occur if overlay removed, property: %pOF/%s\n", target->np, new_prop->name);