mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Steven Rostedt <rostedt@goodmis.org>
To: Linus Torvalds <torvalds@linux-foundation.org>
Cc: LKML <linux-kernel@vger.kernel.org>,
	David Carlier <devnexen@gmail.com>,
	Fuad Tabba <fuad.tabba@linux.dev>,
	Jackie Liu <liuyun01@kylinos.cn>,
	"Masami Hiramatsu (Google)" <mhiramat@kernel.org>,
	Tengda Wu <wutengda@huaweicloud.com>,
	Usama Arif <usama.arif@linux.dev>,
	deepakraog <gaikwad.dcg@gmail.com>,
	Mathieu Desnoyers <mathieu.desnoyers@efficios.com>,
	Andrew Morton <akpm@linux-foundation.org>
Subject: [GIT PULL] tracing: Fixes for 7.2
Date: Sun, 26 Jul 2026 08:54:13 -0400	[thread overview]
Message-ID: <20260726085413.0df95907@gandalf.local.home> (raw)


Linus,

tracing fix for 7.2:

- Move rb_desc->nr_page_va before updating dynamic array

  The rb_descr->page_va is a dynamic array counted by nr_page_va. But the
  updating of the page_va[] is done before the nr_page_va is incremented
  causing a build with CONFIG_UBSAN_BOUNDS to flag it as an overflow.

  Move the increment of the counted by value before the array element is
  updated.

- Propagate errors from remote event bulk updates

  The return value of trace_remote_enable_event() was not being checked by
  remote_events_dir_enable_write() where it would silently fail. Have it
  check the return value and propagate that back up to user space.

- Fix resource leak on mmiotrace trace_pipe close

  The mmiotrace tracer was created in 2008 before the trace_pipe had a close
  callback to allow tracers to do clean up from trace_pipe open. The
  trace_pipe close cleanup callback was added in 2009 but the mmiotrace
  tracer was not updated. It had a hack to do the cleanup in the read call,
  where it may leak if user space did not read the entire buffer.

  Add a callback to mmiotrace trace_pipe close do to the cleanup properly.

- Fix a possible NULL pointer dereference in the mmiotrace tracer

  If the mmio_pipe_open() fails to find a PCI device, it will set the
  hiter->dev pointer to NULL. The read function will blindly dereference
  that pointer. Fix the read call to check to see if that pointer is
  populated before dereferencing it.

- Fix union collision of module and refcnt for dynamic events

  In 'struct trace_event_call', the 'module' pointer and the 'refcnt' atomic
  variable share the same memory space in a union. The filter on module
  logic only checked if the 'module' was set to determine if the event
  belonged to the module. As dynamic events are always builtin, it doesn't
  need the 'module' field of the structure and used a refcount. But the
  module filtering logic would then mistaken these dynamic events as a
  module and call module_name(event->module) on it.

  Add a check to see if the event is a dynamic event and if so, do not check
  it for being part of the given module.

- Reset the top level buffer in selftests before running instances

  The ftracetest selftest initializes each instance before executing the
  tests. But it does not reset the top level buffer. Dynamic events are only
  added and removed by the top level so any left over dynamic events will
  not be removed by the reset in the instances.

  Left over dynamic events can cause the tests to incorrectly fail. Reset
  the top level buffer before running the instances.

- Make the context_switch counter 64 bit

  The code to read user space for a system call trace event or for a
  trace_marker will disable migration, enable preemption, read user space
  into a per CPU buffer, disable preemption and enable migration again.
  It checks if the per CPU context switch counter to see if it changed, and
  if it did not, it would know that the per CPU buffer was not touched by
  another task.

  But the save counter was 32 bit and it would compare it to the 64 bit
  context_switch variable. A long running system could have the
  context_switch variable greater that 1<<32 in which case the compare will
  always fail. The compare will promote the 32 bit int saved value to 64 bit
  and compare it to the full 64 bit counter. Since the top 32 bits of the
  saved value was zero, it would never match.

- Fix a use-after-free of the event_enable trigger

  The event_enable trigger allows for enabling one event when another event
  is triggered. When the trigger is removed, it must go through a
  synchronization phase to make sure it is not triggered again. The trigger
  itself is delayed by the "bulk delay" logic that was recently added.
  But the code that frees the event_enable data used to rely on the trigger
  code to do the synchronization. Now that the code uses the call RCU
  functions (and a workqueue), that delay no longer is there.

  Add a callback private_data_free() function that allows triggers to clean
  up data after the synchronization phase has completed.

- Move the module_ref counter into the delay callback

  Since an event of the event_enable trigger can enable an event for a
  module, it ups the module ref count for that event's module. This prevents
  the event from trying to enable an event that no longer exists and cause a
  use-after-free bug.

  The ref counter was set back down when the trigger was removed but not
  after thy synchronization phase. This could lead to the module data being
  accessed after module was unloaded.

  Move the module ref decrement into the private_data_free() callback of the
  event_enable trigger.

- Add mutex to protect parser in ftrace filtering

  The set_ftrace_filter file uses a parsing descriptor that is allocated at
  open and modified by writes. If multiple threads were to write to the
  descriptor at the same time, it can corrupt the parser.

  Add a mutex around the modifications of the parser descriptor.

- Fix possible corruption in perf syscall tracing

  The perf system call trace events can now read user space. To do so, the
  reads of user space enable preemption and disables it again. During this
  time that preemption is enabled, the task can migrate. The perf event list
  head is assigned via a per CPU pointer. It is done before the user space
  part is called. If the user space reading migrates the task to another
  CPU, then the head pointer is no longer valid.

  Re-assign the head pointer after the reading of user space to keep it
  using the correct data.


Please pull the latest trace-v7.2-rc4 tree, which can be found at:


  git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace.git
trace-v7.2-rc4

Tag SHA1: f221045250d3bf4a92b8a45daf0e713a3f2e5ad4
Head SHA1: 2c2b322acdcc78575b8d6afa64a085cf92e03c12


David Carlier (1):
      tracing: Fix use-after-free freeing trigger private data

Fuad Tabba (1):
      tracing/remotes: Fix page_va[] access before counter update in trace_remote_alloc_buffer()

Jackie Liu (1):
      tracing: Propagate errors from remote event bulk updates

Masami Hiramatsu (Google) (2):
      tracing: Fix union collision of module and refcnt for dynamic events
      selftests/ftrace: Reset triggers at top level before instance loop

Steven Rostedt (3):
      tracing: Fix mmiotrace possible NULL dereferencing of hiter->dev
      tracing: Delay module ref count for "enable_event" trigger
      tracing: perf: Fix stale head for perf syscall tracing

Tengda Wu (1):
      ftrace: Add global mutex to serialize trace_parser access

Usama Arif (1):
      tracing: Fix context switch counter truncation

deepakraog (1):
      tracing: Fix resource leak on mmiotrace trace_pipe close

----
 kernel/trace/ftrace.c                     | 13 +++++++++++++
 kernel/trace/trace.c                      |  2 +-
 kernel/trace/trace.h                      |  1 +
 kernel/trace/trace_events.c               |  4 +++-
 kernel/trace/trace_events_hist.c          |  2 ++
 kernel/trace/trace_events_trigger.c       | 22 ++++++++++++++++++----
 kernel/trace/trace_mmiotrace.c            |  4 ++--
 kernel/trace/trace_remote.c               | 16 +++++++++++++---
 kernel/trace/trace_syscalls.c             |  5 +++++
 tools/testing/selftests/ftrace/ftracetest |  1 +
 10 files changed, 59 insertions(+), 11 deletions(-)
---------------------------
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index f93e34dd2328..6c47a94f5924 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -1097,6 +1097,12 @@ struct ftrace_ops global_ops = {
 					  FTRACE_OPS_FL_PID,
 };
 
+/*
+ * parser_lock - Protects trace_parser state against concurrent operations.
+ * Held across trace_get_user() and subsequent buffer parsing to prevent races.
+ */
+static DEFINE_MUTEX(parser_lock);
+
 /*
  * Used by the stack unwinder to know about dynamic ftrace trampolines.
  */
@@ -5842,6 +5848,8 @@ ftrace_regex_write(struct file *file, const char __user *ubuf,
 	/* iter->hash is a local copy, so we don't need regex_lock */
 
 	parser = &iter->parser;
+
+	guard(mutex)(&parser_lock);
 	read = trace_get_user(parser, ubuf, cnt, ppos);
 
 	if (read >= 0 && trace_parser_loaded(parser) &&
@@ -6984,12 +6992,14 @@ int ftrace_regex_release(struct inode *inode, struct file *file)
 		iter = file->private_data;
 
 	parser = &iter->parser;
+	mutex_lock(&parser_lock);
 	if (trace_parser_loaded(parser)) {
 		int enable = !(iter->flags & FTRACE_ITER_NOTRACE);
 
 		ftrace_process_regex(iter, parser->buffer,
 				     parser->idx, enable);
 	}
+	mutex_unlock(&parser_lock);
 
 	trace_parser_put(parser);
 
@@ -7321,10 +7331,12 @@ ftrace_graph_release(struct inode *inode, struct file *file)
 
 		parser = &fgd->parser;
 
+		mutex_lock(&parser_lock);
 		if (trace_parser_loaded((parser))) {
 			ret = ftrace_graph_set_hash(fgd->new_hash,
 						    parser->buffer);
 		}
+		mutex_unlock(&parser_lock);
 
 		trace_parser_put(parser);
 
@@ -7437,6 +7449,7 @@ ftrace_graph_write(struct file *file, const char __user *ubuf,
 
 	parser = &fgd->parser;
 
+	guard(mutex)(&parser_lock);
 	read = trace_get_user(parser, ubuf, cnt, ppos);
 
 	if (read >= 0 && trace_parser_loaded(parser) &&
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 18710c190c92..01a5e87af299 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -6187,7 +6187,7 @@ char *trace_user_fault_read(struct trace_user_buf_info *tinfo,
 {
 	int cpu = smp_processor_id();
 	char *buffer = per_cpu_ptr(tinfo->tbuf, cpu)->buf;
-	unsigned int cnt;
+	unsigned long long cnt;
 	int trys = 0;
 	int ret;
 
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 80fe152af1dd..bf77331f56a4 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -1941,6 +1941,7 @@ struct event_trigger_data {
 	struct list_head		named_list;
 	struct event_trigger_data	*named_data;
 	struct llist_node		llist;
+	void				(*private_data_free)(struct event_trigger_data *data);
 };
 
 /* Avoid typos */
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index c46e623e7e0d..956692856fa8 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -1350,7 +1350,9 @@ __ftrace_set_clr_event_nolock(struct trace_array *tr, const char *match,
 		call = file->event_call;
 
 		/* If a module is specified, skip events that are not that module */
-		if (module && (!call->module || strcmp(module_name(call->module), module)))
+		if (module &&
+		    ((call->flags & TRACE_EVENT_FL_DYNAMIC) ||
+		     !call->module || strcmp(module_name(call->module), module)))
 			continue;
 
 		name = trace_event_name(call);
diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c
index 82ce492ab268..58d28cd1afa3 100644
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -6349,6 +6349,7 @@ static void event_hist_trigger_free(struct event_trigger_data *data)
 
 		trigger_data_free(data);
 
+		tracepoint_synchronize_unregister();
 		remove_hist_vars(hist_data);
 
 		unregister_field_var_hists(hist_data);
@@ -6388,6 +6389,7 @@ static void event_hist_trigger_named_free(struct event_trigger_data *data)
 
 		del_named_trigger(data);
 		trigger_data_free(data);
+		tracepoint_synchronize_unregister();
 		kfree(cmd_ops);
 	}
 }
diff --git a/kernel/trace/trace_events_trigger.c b/kernel/trace/trace_events_trigger.c
index 655db2e82513..ad83419cb420 100644
--- a/kernel/trace/trace_events_trigger.c
+++ b/kernel/trace/trace_events_trigger.c
@@ -38,6 +38,13 @@ static void trigger_create_kthread_locked(void)
 	}
 }
 
+static void trigger_data_free_one(struct event_trigger_data *data)
+{
+	if (data->private_data_free)
+		data->private_data_free(data);
+	kfree(data);
+}
+
 static void trigger_data_free_queued_locked(void)
 {
 	struct event_trigger_data *data, *tmp;
@@ -52,7 +59,7 @@ static void trigger_data_free_queued_locked(void)
 	tracepoint_synchronize_unregister();
 
 	llist_for_each_entry_safe(data, tmp, llnodes, llist)
-		kfree(data);
+		trigger_data_free_one(data);
 }
 
 /* Bulk garbage collection of event_trigger_data elements */
@@ -75,7 +82,7 @@ static int trigger_kthread_fn(void *ignore)
 		tracepoint_synchronize_unregister();
 
 		llist_for_each_entry_safe(data, tmp, llnodes, llist)
-			kfree(data);
+			trigger_data_free_one(data);
 	}
 
 	return 0;
@@ -1717,6 +1724,14 @@ int event_enable_trigger_print(struct seq_file *m,
 	return 0;
 }
 
+static void enable_trigger_private_data_free(struct event_trigger_data *data)
+{
+	struct enable_trigger_data *enable_data = data->private_data;
+
+	trace_event_put_ref(enable_data->file->event_call);
+	kfree(enable_data);
+}
+
 void event_enable_trigger_free(struct event_trigger_data *data)
 {
 	struct enable_trigger_data *enable_data = data->private_data;
@@ -1728,9 +1743,8 @@ void event_enable_trigger_free(struct event_trigger_data *data)
 	if (!data->ref) {
 		/* Remove the SOFT_MODE flag */
 		trace_event_enable_disable(enable_data->file, 0, 1);
-		trace_event_put_ref(enable_data->file->event_call);
+		data->private_data_free = enable_trigger_private_data_free;
 		trigger_data_free(data);
-		kfree(enable_data);
 	}
 }
 
diff --git a/kernel/trace/trace_mmiotrace.c b/kernel/trace/trace_mmiotrace.c
index 226cf66e0d68..b88b8d9923ad 100644
--- a/kernel/trace/trace_mmiotrace.c
+++ b/kernel/trace/trace_mmiotrace.c
@@ -109,7 +109,6 @@ static void mmio_pipe_open(struct trace_iterator *iter)
 	iter->private = hiter;
 }
 
-/* XXX: This is not called when the pipe is closed! */
 static void mmio_close(struct trace_iterator *iter)
 {
 	struct header_iter *hiter = iter->private;
@@ -146,7 +145,7 @@ static ssize_t mmio_read(struct trace_iterator *iter, struct file *filp,
 		goto print_out;
 	}
 
-	if (!hiter)
+	if (!hiter || !hiter->dev)
 		return 0;
 
 	mmio_print_pcidev(s, hiter->dev);
@@ -279,6 +278,7 @@ static struct tracer mmio_tracer __read_mostly =
 	.start		= mmio_trace_start,
 	.pipe_open	= mmio_pipe_open,
 	.close		= mmio_close,
+	.pipe_close	= mmio_close,
 	.read		= mmio_read,
 	.print_line	= mmio_print_line,
 	.noboot		= true,
diff --git a/kernel/trace/trace_remote.c b/kernel/trace/trace_remote.c
index 0f6ef5c36d84..e6724f947170 100644
--- a/kernel/trace/trace_remote.c
+++ b/kernel/trace/trace_remote.c
@@ -1004,11 +1004,10 @@ int trace_remote_alloc_buffer(struct trace_buffer_desc *desc, size_t desc_size,
 		desc->nr_cpus++;
 
 		for (id = 0; id < nr_pages; id++) {
+			rb_desc->nr_page_va++;
 			rb_desc->page_va[id] = (unsigned long)__get_free_page(GFP_KERNEL);
 			if (!rb_desc->page_va[id])
 				goto err;
-
-			rb_desc->nr_page_va++;
 		}
 		rb_desc = __next_ring_buffer_desc(rb_desc);
 	}
@@ -1150,10 +1149,21 @@ static ssize_t remote_events_dir_enable_write(struct file *filp, const char __us
 
 	for (i = 0; i < remote->nr_events; i++) {
 		struct remote_event *evt = &remote->events[i];
+		int eret;
 
-		trace_remote_enable_event(remote, evt, enable);
+		eret = trace_remote_enable_event(remote, evt, enable);
+		/*
+		 * Save the first error and return that. Some events
+		 * may still have been enabled, but let the user
+		 * know that something went wrong.
+		 */
+		if (!ret && eret)
+			ret = eret;
 	}
 
+	if (ret)
+		return ret;
+
 	return count;
 }
 
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c
index e98ee7e1e66f..8a4f3c75e39f 100644
--- a/kernel/trace/trace_syscalls.c
+++ b/kernel/trace/trace_syscalls.c
@@ -1451,6 +1451,11 @@ static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id)
 		if (syscall_get_data(sys_data, args, &user_ptr,
 				     &size, user_sizes, &uargs, buf_size) < 0)
 			return;
+
+		/* The above may have caused a migration */
+		head = this_cpu_ptr(sys_data->enter_event->perf_events);
+		if (hlist_empty(head))
+			return;
 	}
 
 	/* get the size after alignment with the u32 buffer size field */
diff --git a/tools/testing/selftests/ftrace/ftracetest b/tools/testing/selftests/ftrace/ftracetest
index 0a56bf209f6c..8ad2c385407e 100755
--- a/tools/testing/selftests/ftrace/ftracetest
+++ b/tools/testing/selftests/ftrace/ftracetest
@@ -503,6 +503,7 @@ for t in $TEST_CASES; do
 done
 
 # Test on instance loop
+(cd $TRACING_DIR; initialize_system)
 INSTANCE=" (instance) "
 for t in $TEST_CASES; do
   test_on_instance $t || continue

             reply	other threads:[~2026-07-26 12:53 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-26 12:54 Steven Rostedt [this message]
2026-07-26 20:00 ` pr-tracker-bot
  -- strict thread matches above, loose matches on Subject: below --
2026-08-09 15:32 Steven Rostedt
2026-08-09 15:49 ` pr-tracker-bot
2026-07-12 16:29 Steven Rostedt
2026-07-12 19:13 ` pr-tracker-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260726085413.0df95907@gandalf.local.home \
    --to=rostedt@goodmis.org \
    --cc=akpm@linux-foundation.org \
    --cc=devnexen@gmail.com \
    --cc=fuad.tabba@linux.dev \
    --cc=gaikwad.dcg@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=liuyun01@kylinos.cn \
    --cc=mathieu.desnoyers@efficios.com \
    --cc=mhiramat@kernel.org \
    --cc=torvalds@linux-foundation.org \
    --cc=usama.arif@linux.dev \
    --cc=wutengda@huaweicloud.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®