| From 6f75118800acf77f8ad6afec61ca1b2349ade371 Mon Sep 17 00:00:00 2001 |
| From: Frank Rowand <frank.rowand@sony.com> |
| Date: Thu, 4 Oct 2018 20:32:04 -0700 |
| Subject: of: overlay: validate overlay properties #address-cells and #size-cells |
| |
| From: Frank Rowand <frank.rowand@sony.com> |
| |
| commit 6f75118800acf77f8ad6afec61ca1b2349ade371 upstream. |
| |
| If overlay properties #address-cells or #size-cells are already in |
| the live devicetree for any given node, then the values in the |
| overlay must match the values in the live tree. |
| |
| If the properties are already in the live tree then there is no |
| need to create a changeset entry to add them since they must |
| have the same value. This reduces the memory used by the |
| changeset and eliminates a possible memory leak. |
| |
| Tested-by: Alan Tull <atull@kernel.org> |
| Signed-off-by: Frank Rowand <frank.rowand@sony.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/of/overlay.c | 32 +++++++++++++++++++++++++++++--- |
| include/linux/of.h | 6 ++++++ |
| 2 files changed, 35 insertions(+), 3 deletions(-) |
| |
| --- a/drivers/of/overlay.c |
| +++ b/drivers/of/overlay.c |
| @@ -287,7 +287,12 @@ err_free_target_path: |
| * @target may be either in the live devicetree or in a new subtree that |
| * is contained in the changeset. |
| * |
| - * Some special properties are not updated (no error returned). |
| + * Some special properties are not added or updated (no error returned): |
| + * "name", "phandle", "linux,phandle". |
| + * |
| + * Properties "#address-cells" and "#size-cells" are not updated if they |
| + * are already in the live tree, but if present in the live tree, the values |
| + * in the overlay must match the values in the live tree. |
| * |
| * Update of property in symbols node is not allowed. |
| * |
| @@ -300,6 +305,7 @@ static int add_changeset_property(struct |
| { |
| struct property *new_prop = NULL, *prop; |
| int ret = 0; |
| + bool check_for_non_overlay_node = false; |
| |
| if (!of_prop_cmp(overlay_prop->name, "name") || |
| !of_prop_cmp(overlay_prop->name, "phandle") || |
| @@ -322,12 +328,32 @@ static int add_changeset_property(struct |
| if (!new_prop) |
| return -ENOMEM; |
| |
| - if (!prop) |
| + if (!prop) { |
| + check_for_non_overlay_node = true; |
| ret = of_changeset_add_property(&ovcs->cset, target->np, |
| new_prop); |
| - else |
| + } 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)) |
| + pr_err("WARNING: memory leak will occur if overlay removed, property: %pOF/%s\n", |
| + target->np, new_prop->name); |
| |
| if (ret) { |
| kfree(new_prop->name); |
| --- a/include/linux/of.h |
| +++ b/include/linux/of.h |
| @@ -968,6 +968,12 @@ static inline int of_cpu_node_to_id(stru |
| #define of_node_cmp(s1, s2) strcasecmp((s1), (s2)) |
| #endif |
| |
| +static inline int of_prop_val_eq(struct property *p1, struct property *p2) |
| +{ |
| + return p1->length == p2->length && |
| + !memcmp(p1->value, p2->value, (size_t)p1->length); |
| +} |
| + |
| #if defined(CONFIG_OF) && defined(CONFIG_NUMA) |
| extern int of_node_to_nid(struct device_node *np); |
| #else |