FAILED: patch "[PATCH] ftrace: Take trace_array reference before accessing its" failed to apply to 6.12-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 6.12-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.12.y
git checkout FETCH_HEAD
git cherry-pick -x 9100191e5acb2e5ea2313f436667bb5fce129f47
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026090804-math-renewal-5eb6@gregkh' --subject-prefix 'PATCH 6.12.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 9100191e5acb2e5ea2313f436667bb5fce129f47 Mon Sep 17 00:00:00 2001
From: Steven Rostedt <[email protected]>
Date: Fri, 28 Aug 2026 22:39:01 -0400
Subject: [PATCH] ftrace: Take trace_array reference before accessing its
ftrace_ops
The trace instance files set_ftrace_filter and set_ftrace_notrace was updated to work with specific trace instances (trace_arrays). The issue is that when these files are opened, there is a small race window where it will use the ftrace_ops from the inode->private pointer to get a reference to the trace_array and then take its reference. The problem is that the ftrace_ops itself could be freed. If the rmdir on the instance happens at the same time the set_ftrace_filter file is opened, the rmdir could have also freed the ftrace_ops and referencing it will cause a use-after-free bug and crash the kernel.
Instead, pass in the trace_array as the file private data (NULL for the top level instance), and then pass both the trace_array and the ftrace_ops to the ftrace_regex_open() function. If the trace_array is NULL, then it just uses the ftrace_ops without the need to take its reference (like normal). If the ftrace_ops is NULL, that is only the case for the top level instance and the global_ops can be used.
This allows the trace_array to have its reference incremented before touching the ftrace_ops that could also be freed when the instance is.
include/linux/ftrace.h +3 -2
@@ -866,8 +866,9 @@ unsigned long ftrace_get_addr_new(struct dyn_ftrace *rec);unsigned long ftrace_get_addr_curr (struct dyn_ftrace *rec);extern ftrace_func_t ftrace_trace_function; +struct trace_array ; -int ftrace_regex_open (struct ftrace_ops *ops,int flag, +int ftrace_regex_open (struct trace_array *tr,struct ftrace_ops *ops,int flag,struct inode *inode,struct file *file);ssize_t ftrace_filter_write (struct file *file,const char __user *ubuf,size_t cnt,loff_t *ppos);
@@ -1077,7 +1078,7 @@ static inline unsigned long ftrace_location(unsigned long ip)* have them defined when ftrace is not enabled, but these * functions may still be called. Use a macro instead of inline. */ -#define ftrace_regex_open (ops, flag, inod, file) ({ -ENODEV; }) +#define ftrace_regex_open (tr, ops, flag, inode, file) ({ -ENODEV; })#define ftrace_set_early_filter (ops, buf, enable) do { } while (0)#define ftrace_set_filter_ip (ops, ip, remove, reset) ({ -ENODEV; })#define ftrace_set_filter_ips (ops, ips, cnt, remove, reset) ({ -ENODEV; })
kernel/trace/ftrace.c +37 -20
120 lines not on this page · raw message
kernel/trace/trace.h +3 -2
@@ -1340,7 +1340,7 @@ extern void clear_ftrace_function_probes(struct trace_array *tr);int register_ftrace_command (struct ftrace_func_command *cmd);int unregister_ftrace_command (struct ftrace_func_command *cmd); -void ftrace_create_filter_files (struct ftrace_ops *ops, +void ftrace_create_filter_files (struct trace_array *tr,struct dentry *parent);void ftrace_destroy_filter_files (struct ftrace_ops *ops);
@@ -1363,11 +1363,12 @@ static inline void clear_ftrace_function_probes(struct trace_array *tr) { } +static inline void ftrace_create_filter_files (struct trace_array *tr, +struct dentry *parent) { }/* * The ops parameter passed in is usually undefined. * This must be a macro. */ -#define ftrace_create_filter_files (ops, parent) do { } while (0)#define ftrace_destroy_filter_files (ops) do { } while (0)#endif /* CONFIG_FUNCTION_TRACER && CONFIG_DYNAMIC_FTRACE */
kernel/trace/trace_functions.c +1 -1
@@ -101,7 +101,7 @@ int ftrace_create_function_files(struct trace_array *tr,return ret; } -ftrace_create_filter_files (tr->ops, parent); +ftrace_create_filter_files (tr, parent);return 0 ; }
kernel/trace/trace_stack.c +1 -1
@@ -499,7 +499,7 @@ stack_trace_filter_open(struct inode *inode, struct file *file)struct ftrace_ops *ops = inode->i_private;/* Checks for tracefs lockdown */ -return ftrace_regex_open (ops,FTRACE_ITER_FILTER , +return ftrace_regex_open (NULL , ops,FTRACE_ITER_FILTER , inode, file); }
Sasha Levin
maintainerPATCH 1/1 ftrace: Take trace_array reference before accessing its ftrace_ops
From: Steven Rostedt <[email protected]>
[ Upstream commit 9100191e5acb2e5ea2313f436667bb5fce129f47 ]
The trace instance files set_ftrace_filter and set_ftrace_notrace was updated to work with specific trace instances (trace_arrays). The issue is that when these files are opened, there is a small race window where it will use the ftrace_ops from the inode->private pointer to get a reference to the trace_array and then take its reference. The problem is that the ftrace_ops itself could be freed. If the rmdir on the instance happens at the same time the set_ftrace_filter file is opened, the rmdir could have also freed the ftrace_ops and referencing it will cause a use-after-free bug and crash the kernel.
Instead, pass in the trace_array as the file private data (NULL for the top level instance), and then pass both the trace_array and the ftrace_ops to the ftrace_regex_open() function. If the trace_array is NULL, then it just uses the ftrace_ops without the need to take its reference (like normal). If the ftrace_ops is NULL, that is only the case for the top level instance and the global_ops can be used.
This allows the trace_array to have its reference incremented before touching the ftrace_ops that could also be freed when the instance is.
--- include/linux/ftrace.h | 5 +-- kernel/trace/ftrace.c | 57 ++++++++++++++++++++++------------ kernel/trace/trace.h | 4 +-- kernel/trace/trace_functions.c | 2 +- kernel/trace/trace_stack.c | 2 +- 5 files changed, 44 insertions(+), 26 deletions(-)
include/linux/ftrace.h +3 -2
@@ -759,8 +759,9 @@ unsigned long ftrace_get_addr_new(struct dyn_ftrace *rec);unsigned long ftrace_get_addr_curr (struct dyn_ftrace *rec);extern ftrace_func_t ftrace_trace_function; +struct trace_array ; -int ftrace_regex_open (struct ftrace_ops *ops,int flag, +int ftrace_regex_open (struct trace_array *tr,struct ftrace_ops *ops,int flag,struct inode *inode,struct file *file);ssize_t ftrace_filter_write (struct file *file,const char __user *ubuf,size_t cnt,loff_t *ppos);
@@ -970,7 +971,7 @@ static inline unsigned long ftrace_location(unsigned long ip)* have them defined when ftrace is not enabled, but these * functions may still be called. Use a macro instead of inline. */ -#define ftrace_regex_open (ops, flag, inod, file) ({ -ENODEV; }) +#define ftrace_regex_open (tr, ops, flag, inode, file) ({ -ENODEV; })#define ftrace_set_early_filter (ops, buf, enable) do { } while (0)#define ftrace_set_filter_ip (ops, ip, remove, reset) ({ -ENODEV; })#define ftrace_set_filter_ips (ops, ips, cnt, remove, reset) ({ -ENODEV; })
kernel/trace/ftrace.c +37 -20
120 lines not on this page · raw message
kernel/trace/trace.h +2 -2
@@ -1191,7 +1191,7 @@ extern void clear_ftrace_function_probes(struct trace_array *tr);int register_ftrace_command (struct ftrace_func_command *cmd);int unregister_ftrace_command (struct ftrace_func_command *cmd); -void ftrace_create_filter_files (struct ftrace_ops *ops, +void ftrace_create_filter_files (struct trace_array *tr,struct dentry *parent);void ftrace_destroy_filter_files (struct ftrace_ops *ops);
@@ -1214,11 +1214,11 @@ static inline void clear_ftrace_function_probes(struct trace_array *tr) { } +#define ftrace_create_filter_files (tr, parent) do { } while (0)/* * The ops parameter passed in is usually undefined. * This must be a macro. */ -#define ftrace_create_filter_files (ops, parent) do { } while (0)#define ftrace_destroy_filter_files (ops) do { } while (0)#endif /* CONFIG_FUNCTION_TRACER && CONFIG_DYNAMIC_FTRACE */
kernel/trace/trace_functions.c +1 -1
@@ -97,7 +97,7 @@ int ftrace_create_function_files(struct trace_array *tr,return ret; } -ftrace_create_filter_files (tr->ops, parent); +ftrace_create_filter_files (tr, parent);return 0 ; }
kernel/trace/trace_stack.c +1 -1
@@ -499,7 +499,7 @@ stack_trace_filter_open(struct inode *inode, struct file *file)struct ftrace_ops *ops = inode->i_private;/* Checks for tracefs lockdown */ -return ftrace_regex_open (ops,FTRACE_ITER_FILTER , +return ftrace_regex_open (NULL , ops,FTRACE_ITER_FILTER , inode, file); }
Signature · 1 line
2.53.0