of: dynamic: Fix race in getting old property when updating property
authorRob Herring <robh@kernel.org>
Fri, 18 Aug 2023 20:40:59 +0000 (15:40 -0500)
committerRob Herring <robh@kernel.org>
Mon, 21 Aug 2023 22:09:57 +0000 (17:09 -0500)
__of_update_property() returns the existing property if there is one, but
that value is never added to the changeset. Updates work because the
existing property was also retrieved before in of_changeset_action(),
but that is racy as of_changeset_action() doesn't hold any locks. The
property could be changed before the changeset is applied.

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
Link: https://lore.kernel.org/r/20230801-dt-changeset-fixes-v3-4-5f0410e007dd@kernel.org
Signed-off-by: Rob Herring <robh@kernel.org>
drivers/of/dynamic.c

index b2b921b..38dc536 100644 (file)
@@ -564,7 +564,7 @@ static int __of_changeset_entry_notify(struct of_changeset_entry *ce,
 
 static int __of_changeset_entry_apply(struct of_changeset_entry *ce)
 {
-       struct property *old_prop, **propp;
+       struct property **propp;
        unsigned long flags;
        int ret = 0;
 
@@ -604,7 +604,7 @@ static int __of_changeset_entry_apply(struct of_changeset_entry *ce)
                        }
                }
 
-               ret = __of_update_property(ce->np, ce->prop, &old_prop);
+               ret = __of_update_property(ce->np, ce->prop, &ce->old_prop);
                break;
        default:
                ret = -EINVAL;
@@ -908,9 +908,6 @@ int of_changeset_action(struct of_changeset *ocs, unsigned long action,
        ce->np = of_node_get(np);
        ce->prop = prop;
 
-       if (action == OF_RECONFIG_UPDATE_PROPERTY && prop)
-               ce->old_prop = of_find_property(np, prop->name, NULL);
-
        /* add it to the list */
        list_add_tail(&ce->node, &ocs->entries);
        return 0;