[PATCH v5 7/9] of/overlay: return ERR_PTR from dup_and_fixup_symbol_prop()

From: Abdurrahman Hussain

Date: Wed Jul 22 2026 - 23:23:08 EST


dup_and_fixup_symbol_prop() returns NULL for malformed values, for
values that are not paths into one of the overlay's fragments, and
for allocation failures. The caller reports all of them as -ENOMEM,
so a structural problem in /__symbols__ is diagnosed as memory
exhaustion.

A later patch reuses the helper for /aliases values and must handle
the three cases differently: copy verbatim, warn, or fail the apply.
Return ERR_PTR(-EINVAL), ERR_PTR(-ENODEV) and ERR_PTR(-ENOMEM)
respectively and propagate the errno in the /__symbols__ caller.

Also verify that the value descends through the matched fragment's
__overlay__ node before cutting the prefix. Only the first path
component was resolved, so an absolute live-tree value sharing its
first component with a fragment name was sliced at the prefix length
and rewritten to garbage. A prefix mismatch returns -ENODEV.

Assisted-by: Claude:claude-fable-5 [Claude Code]
Signed-off-by: Abdurrahman Hussain <abdurrahman@xxxxxxxxxx>
---
drivers/of/overlay.c | 35 ++++++++++++++++++++++++++---------
1 file changed, 26 insertions(+), 9 deletions(-)

diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
index c6962e9948cc..1a2df83fbd8d 100644
--- a/drivers/of/overlay.c
+++ b/drivers/of/overlay.c
@@ -206,6 +206,10 @@ static void overlay_fw_devlink_refresh(struct overlay_changeset *ovcs)
* The duplicated property value will be modified by replacing the
* "/fragment_name/__overlay/" portion of the value with the target
* path from the fragment node.
+ *
+ * Return: the fixed-up property, or ERR_PTR: -EINVAL if @prop's value
+ * is not a valid non-empty C string, -ENODEV if it is not a path into
+ * one of @ovcs's fragments, -ENOMEM on allocation failure.
*/
static struct property *dup_and_fixup_symbol_prop(
struct overlay_changeset *ovcs, const struct property *prop)
@@ -217,6 +221,8 @@ static struct property *dup_and_fixup_symbol_prop(
const char *path;
const char *path_tail;
const char *target_path;
+ char *overlay_name;
+ bool mismatch;
int k;
int overlay_name_len;
int path_len;
@@ -224,14 +230,14 @@ static struct property *dup_and_fixup_symbol_prop(
int target_path_len;

if (!prop->value)
- return NULL;
+ return ERR_PTR(-EINVAL);
if (strnlen(prop->value, prop->length) >= prop->length)
- return NULL;
+ return ERR_PTR(-EINVAL);
path = prop->value;
path_len = strlen(path);

if (path_len < 1)
- return NULL;
+ return ERR_PTR(-EINVAL);
fragment_node = __of_find_node_by_path(ovcs->overlay_root, path + 1);
overlay_node = __of_find_node_by_path(fragment_node, "__overlay__/");
of_node_put(fragment_node);
@@ -243,18 +249,27 @@ static struct property *dup_and_fixup_symbol_prop(
break;
}
if (k >= ovcs->count)
- return NULL;
+ return ERR_PTR(-ENODEV);
+
+ overlay_name = kasprintf(GFP_KERNEL, "%pOF", fragment->overlay);
+ if (!overlay_name)
+ return ERR_PTR(-ENOMEM);
+ overlay_name_len = strlen(overlay_name);

- overlay_name_len = snprintf(NULL, 0, "%pOF", fragment->overlay);
+ /* @path must descend through this fragment's __overlay__ node */
+ mismatch = overlay_name_len > path_len ||
+ strncmp(path, overlay_name, overlay_name_len) != 0 ||
+ (path[overlay_name_len] != '/' && path[overlay_name_len]);
+ kfree(overlay_name);
+ if (mismatch)
+ return ERR_PTR(-ENODEV);

- if (overlay_name_len > path_len)
- return NULL;
path_tail = path + overlay_name_len;
path_tail_len = strlen(path_tail);

target_path = kasprintf(GFP_KERNEL, "%pOF", fragment->target);
if (!target_path)
- return NULL;
+ return ERR_PTR(-ENOMEM);
target_path_len = strlen(target_path);
/* a root target renders as "/"; drop it to avoid "//" results */
if (target_path_len == 1 && target_path[0] == '/')
@@ -284,7 +299,7 @@ static struct property *dup_and_fixup_symbol_prop(
err_free_target_path:
kfree(target_path);

- return NULL;
+ return ERR_PTR(-ENOMEM);
}

/**
@@ -353,6 +368,8 @@ static int add_changeset_property(struct overlay_changeset *ovcs,
if (prop)
return -EINVAL;
new_prop = dup_and_fixup_symbol_prop(ovcs, overlay_prop);
+ if (IS_ERR(new_prop))
+ return PTR_ERR(new_prop);
} else {
new_prop = __of_prop_dup(overlay_prop, GFP_KERNEL);
}

--
2.54.0