]> git.ipfire.org Git - people/arne_f/kernel.git/commitdiff
of: overlay: validate overlay properties #address-cells and #size-cells
authorFrank Rowand <frank.rowand@sony.com>
Fri, 5 Oct 2018 03:32:04 +0000 (20:32 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 9 Jun 2019 07:17:24 +0000 (09:17 +0200)
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
include/linux/of.h

index 9808aae4621ad4ba4cbf69c3125066c9af3d6b82..e6d4138b02a35e147369a4db20d38cec307b6d0d 100644 (file)
@@ -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 overlay_changeset *ovcs,
 {
        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 overlay_changeset *ovcs,
        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);
index f2c80cc4641dc5bc390593bd55119fb0fbb6b776..d5a863c1ee390f6482669a1adc7bb4627bfe934d 100644 (file)
@@ -968,6 +968,12 @@ static inline int of_cpu_node_to_id(struct device_node *np)
 #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