| From e2f918c8aae0d3c9cc4ab2ef57a77537242d4943 Mon Sep 17 00:00:00 2001 |
| From: Frank Rowand <frank.rowand@sony.com> |
| Date: Thu, 21 Nov 2019 13:16:56 -0600 |
| Subject: [PATCH] of: overlay: add_changeset_property() memory leak |
| |
| 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: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c |
| index c423e94baf0f..9617b7df7c4d 100644 |
| --- a/drivers/of/overlay.c |
| +++ b/drivers/of/overlay.c |
| @@ -305,7 +305,6 @@ static int add_changeset_property(struct overlay_changeset *ovcs, |
| { |
| 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 overlay_changeset *ovcs, |
| 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 overlay_changeset *ovcs, |
| 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); |
| |
| -- |
| 2.7.4 |
| |