FAILED: patch "[PATCH] tracing/user_events: Don't destroy fields when event removal" failed to apply to 6.1-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 6.1-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.1.y
git checkout FETCH_HEAD
git cherry-pick -x 2deb753127d7b7035e893955c5e91875e767d1f8
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026091633-hardening-washed-5fd8@gregkh' --subject-prefix 'PATCH 6.1.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 2deb753127d7b7035e893955c5e91875e767d1f8 Mon Sep 17 00:00:00 2001
From: Henry Martin <[email protected]>
Date: Fri, 4 Sep 2026 19:52:23 +0800
Subject: [PATCH] tracing/user_events: Don't destroy fields when event removal
fails
destroy_user_event() destroys the event's fields before attempting to remove the trace event call. If user_event_set_call_visible() fails, e.g. because the event is still enabled and trace_remove_event_call() returns -EBUSY, the event is left registered with an irreversibly destroyed field list. Any subsequent interaction with the event then operates on an empty field list while it is still fully visible in tracefs.
Move the field destruction after the call removal, and splice the field list back onto the event when the removal fails so the event remains in a consistent state.
kernel/trace/trace_events_user.c +20 -6
@@ -1122,10 +1122,9 @@ static void user_event_destroy_validators(struct user_event *user) } } -static void user_event_destroy_fields (struct user_event *user) +static void user_event_destroy_fields (struct list_head *head) {struct ftrace_event_field *field, *next; -struct list_head *head = &user->fields;list_for_each_entry_safe (field, next, head, link) {list_del (&field->link);
@@ -1502,17 +1501,32 @@ static int user_event_set_call_visible(struct user_event *user, bool visible)static int destroy_user_event (struct user_event *user) { +LIST_HEAD (fields);int ret =0 ;lockdep_assert_held (&event_mutex); -/* Must destroy fields before call removal */ -user_event_destroy_fields (user); +/* +* Detach the fields before removing the call. Removing the event +* frees the field list memory (trace_destroy_fields() is run on +* successful removal and kmem_cache_free()s the fields), but the +* fields here are allocated and owned by user_events. Destroy +* them separately once removal has succeeded. +*/ +list_splice_init (&user->fields, &fields); ret =user_event_set_call_visible (user, false); -if (ret) +if (ret) { +/* +* Removal failed and the event stays registered, recover +* the fields so it is left in a consistent state. +*/ +list_splice (&fields, &user->fields);return ret; + } + +user_event_destroy_fields (&fields);dyn_event_remove (&user->devent);hash_del (&user->node);
@@ -2212,7 +2226,7 @@ static int user_event_parse(struct user_event_group *group, char *name, put_user_lock:mutex_unlock (&event_mutex); put_user: -user_event_destroy_fields (user); +user_event_destroy_fields (&user->fields);user_event_destroy_validators (user);kfree (user->call.print_fmt);
Sasha Levin
maintainerPATCH 1/1 tracing/user_events: Don't destroy fields when event removal fails
From: Henry Martin <[email protected]>
[ Upstream commit 2deb753127d7b7035e893955c5e91875e767d1f8 ]
destroy_user_event() destroys the event's fields before attempting to remove the trace event call. If user_event_set_call_visible() fails, e.g. because the event is still enabled and trace_remove_event_call() returns -EBUSY, the event is left registered with an irreversibly destroyed field list. Any subsequent interaction with the event then operates on an empty field list while it is still fully visible in tracefs.
Move the field destruction after the call removal, and splice the field list back onto the event when the removal fails so the event remains in a consistent state.
--- kernel/trace/trace_events_user.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-)
kernel/trace/trace_events_user.c +20 -6
@@ -430,10 +430,9 @@ static void user_event_destroy_validators(struct user_event *user) } } -static void user_event_destroy_fields (struct user_event *user) +static void user_event_destroy_fields (struct list_head *head) {struct ftrace_event_field *field, *next; -struct list_head *head = &user->fields;list_for_each_entry_safe (field, next, head, link) {list_del (&field->link);
@@ -821,15 +820,30 @@ static int user_event_set_call_visible(struct user_event *user, bool visible)static int destroy_user_event (struct user_event *user) { +LIST_HEAD (fields);int ret =0 ; -/* Must destroy fields before call removal */ -user_event_destroy_fields (user); +/* +* Detach the fields before removing the call. Removing the event +* frees the field list memory (trace_destroy_fields() is run on +* successful removal and kmem_cache_free()s the fields), but the +* fields here are allocated and owned by user_events. Destroy +* them separately once removal has succeeded. +*/ +list_splice_init (&user->fields, &fields); ret =user_event_set_call_visible (user, false); -if (ret) +if (ret) { +/* +* Removal failed and the event stays registered, recover +* the fields so it is left in a consistent state. +*/ +list_splice (&fields, &user->fields);return ret; + } + +user_event_destroy_fields (&fields);dyn_event_remove (&user->devent);
@@ -1360,7 +1374,7 @@ static int user_event_parse(struct user_event_group *group, char *name, put_user_lock:mutex_unlock (&event_mutex); put_user: -user_event_destroy_fields (user); +user_event_destroy_fields (&user->fields);user_event_destroy_validators (user);kfree (user->call.print_fmt);kfree (user);
Signature · 1 line
2.53.0