[PATCH v6 08/10] of/overlay: return ERR_PTR from dup_and_fixup_symbol_prop()
Abdurrahman Hussain <[email protected]>
| Newsgroups | gmane.linux.kernel,gmane.linux.drivers.devicetree |
|---|---|
| Message-ID | <[email protected]> |
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 <[email protected]> --- 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 89a9fe6d6e78..99cea094943d 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] == '/' && path_tail_len) @@ -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