From nobody Tue Sep 29 09:47:00 2026 Received: from fout-a5-smtp.messagingengine.com (fout-a5-smtp.messagingengine.com [103.168.172.148]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A8FBA1DF26E for ; Sun, 9 Aug 2026 15:32:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.148 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786289572; cv=none; b=kmDhqPtya0tiPND98mIbl7+wUhnfDYhBbSwYqABKHbdALGZ3uWwSfqwetmgJT7Byj3wJQ3wP2o/XFwstJ3aIyxnOJnrD+3TU7WH+rDv11SnWrmQD6Pah+6tZcRC2jVeauUB5smxVwMIMUlPbkkSXQRoNJQ07O9PinL2fxa6kJDw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786289572; c=relaxed/simple; bh=7kC/JQBDQzjrHuVpskBOtAjRtKXjePQD52QU1i6b46U=; h=Date:From:To:Cc:Subject:Message-ID:MIME-Version:Content-Type; b=ouqrz2KFsNbeysi4pNrTWEEFAkzzJNAE8Abk1hMEyuEhjSxkK3XPKeJ9IWCs4BPm4O6oLRrNNtj1AfsSC4NM7ELiaK6LXeyon7Nq2J+qj6+dJ9BTfBNKzePQzwrxX0dbZMjk9u6vQAN8R7NyzblGMK3F57y4668aTIiwZcl0HQ4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rostedt.org; spf=pass smtp.mailfrom=rostedt.org; dkim=pass (2048-bit key) header.d=rostedt.org header.i=@rostedt.org header.b=2kbvuRfn; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=Xf5rSI06; arc=none smtp.client-ip=103.168.172.148 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rostedt.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rostedt.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=rostedt.org header.i=@rostedt.org header.b="2kbvuRfn"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="Xf5rSI06" Received: from phl-compute-08.internal (phl-compute-08.internal [10.202.2.48]) by mailfout.phl.internal (Postfix) with ESMTP id A54D7EC0011; Sun, 9 Aug 2026 11:32:48 -0400 (EDT) Received: from phl-frontend-03 ([10.202.2.162]) by phl-compute-08.internal (MEProxy); Sun, 09 Aug 2026 11:32:48 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rostedt.org; h= cc:cc:content-transfer-encoding:content-type:content-type:date :date:from:from:in-reply-to:message-id:mime-version:reply-to :subject:subject:to:to; s=fm1; t=1786289568; x=1786375968; bh=AE Ho8ru2fbfA4cUjNPCgcPgaRLytkmTWd0EaljPQJvY=; b=2kbvuRfn7VMsHywfgb GX0VCwip3YW5Jf6jRjD+SFcB5mDNSPQUDkIXDeA8MkM1DTaaSb5hvsqI0EHQARSX Fvpyh9w2VAVUZZ7d9eLn1vAroWG2UdJsTEAXYmwvukDSFyJhkjpw2gS5M9W0Ma/k 5N+0w3h82unUYXSdhrwpM9ka0I1T2e9GQz46XUYfGNOqlPqWp3DJqHCYllbzWQSs LSTT6Z6Arjtk6dTLYDCHf95HILtwQohJYgy+bByaLgJYBBb8T7HbY/Zx3YxnVktA jbufDMDbfx/UezCWpNuLVySfYONd7CJ+bQ2Yukt+iSGnQ/+yqGSh+R5ENmbt95Ir 34EQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:message-id:mime-version:reply-to:subject :subject:to:to:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm3; t=1786289568; x=1786375968; bh=AEHo8ru2fbfA4cUjNPCgcPgaRLyt kmTWd0EaljPQJvY=; b=Xf5rSI06BiQC0FGYHjDPmVuekXEXbnhE+YTileRvUJ6+ cplM++eLfRe1B0I0YfF4a2yYY5fFClStfaX2k946CpPVmk2YEZWqBubAexby8gKz 9fWRomCEc5jKvWBPgRfwuWvU8BwPrMCaf8dIZboZYr/Kli8zd4rC0Xrt16buXsyr XmLpXdhCNxirD9HTX75pkIUU4e+yh5gvksRRbBaPgz+NgzCElAxXp+sxEDt3fY2r 28F2NMgs86pv5l9xj1U18kouEOBcnWOgYcgAri5/vx9AXMVMAUmFUhAw7i0UQEhA qM9IEsMmHqhjQc8ovfEOiC4cbkZv3KhYYMxPByVY+g== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: dmFkZTEURSTrZkXYsOzxQM7QNr5Y79PQ7bGuh83V45smPRNn4LtE6cXZh3S56A2HL3R4wM dghWgBx9QELXKRMUsV239saDyMqDIYk5ynpEzuztzZnuzLKnYS+oPoeqR5i0QVfm3jSt4i tGHOJFHZMDdzWuEvreivE8vpDbxUyiJY8O6lUzpSYFicPTRUKxOP9wlp7IpSjRDXL+WQrD /CWM0kOqU5qiibVnIa4Rur6Iq8fZB+O65CXW+RpJNFkpB8gHZWKRcn7z5EQdQ5MQTe7qBn UMhfZuTV0GXjh6LyRMk2CO31SOktk3iV0TJOysF1fXqeJOIZbNUEfgbkixHkkT2VFpMpWL zT80S8tflSKDLAahD9TRnrcKmJEkiYSbJeZnKqpBs1rRvwfV3klba3Dnz2A3pdx1DgcXpm MRnqfGK0mzwPvjVRbaDe8KV+PjN4tAOkySZzZZzDd72kMOFIf/TJetlBbmRBK49n5y8kAi gS645Ik3/DbHvCNrMXtnWG+5zHVVjgw+FFWGo55h/YzJ4nuVwNm++fYjg4Pfqqp60WFOi+ noBUm5lwIJlWuiELaz1J4QBgQewAT1G3lupBvI7Nu+nzXHgrhZVbxN8feDLOWVivp0V7h8 nZ1acblIvVuIO8VdhcsbbCvIxJs4Sp2iLDzSWT708q8SfKm8dkUi+HF7HE0w X-ME-Proxy: Feedback-ID: id06e481b:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Sun, 9 Aug 2026 11:32:46 -0400 (EDT) Date: Sun, 9 Aug 2026 11:32:54 -0400 From: Steven Rostedt To: Linus Torvalds Cc: LKML , Masami Hiramatsu , Mathieu Desnoyers , Andrew Morton , Hui Su , Josh Poimboeuf , Leon Hwang , Shuangpeng Bai , Tengda Wu , Vincent Donnefort Subject: [GIT PULL] tracing: Fixes for 7.2 Message-ID: <20260809113254.1f449edb@gandalf.local.home> X-Mailer: Claws Mail 3.20.0git84 (GTK+ 2.24.33; x86_64-pc-linux-gnu) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Linus, tracing fixes for 7.2: - Fix use-after-free in eventfs_remove_rec() The freeing of the eventfs_inode children used list_for_each_entry() where the child is freed via srcu, but there's still a chance that it gets free= d. It should be using list_for_each_entry_safe(). - Fix eventfs_inode SRCU use of list in freeing The iterator uses an SRCU protected list walk on the eventfs inodes. The eventfs inode uses its "list" field in a union with the RCU list head. When the inode gets added to the SRCU list it immediately corrupts the list pointer and can cause an issue with the iterator. Move the RCU list head to be shared with the children list head which allows the iterator to check the parent inode if is freed before referencing the child. Have the iterator check the parent "is_freed" field and break out if it is set. Also add memory barriers to make sure the ordering is correct. - Fix various RCU synchronization issues with direct_functions Updates to direct_functions have some missing RCU protection and synchronization. Restructure the code a bit to make sure updates to the direct_functions are protected. - Remove an unneeded comma from a scope_guard() There's a spurious comma in a scope_guard(). Remove it. - Fix race in per CPU buffer swap in the ring buffer When a per CPU buffer swap happens, it must make sure that it doesn't occur while a writer is active. Instead it returns an -EBUSY. But there's a small race window when a writer moves from one sub-buffer to the next that it resets the "committing" counter. If a swap happens at that moment, the buffer used for the commit of an event will not match the buffer the event is actually on. Instead of using the "committing" counter, use the recursive detection counter that does not get reset when the writer crosses sub-buffers. - Fix off-by-one in ftrace_free_mem() The function ftrace_free_mem() gets an "end_ptr" as a parameter that is exclusive to the rang to be freed. But its value is used to search for the records that expects an inclusive value. Subtract one from the parameter to convert it to an inclusive range. - Disable resizing of the ring buffer for persistent buffers Resizing the persistent buffer has undefined behavior. Prevent it from being resized. - Disable changing ring buffer subbuf order when resizing is disabled The ring buffer subbuffer order can not be changed during resizing. Use that instead of just checking if the buffer is mapped as mapped buffers also have resizing disabled. - Initialize subbuf_order of reader pages when they are created In rb_allocate_cpu_buffer() the bpage->order is not updated to the current subbuf_order leaving it as zero. This value is used when the page is free= d. - Fix test_ringbuffer() to test for ERR_PTR before calling kthread_stop() The rb_threads[] array is assigned the output of kthread_run_on_cpu() which could return an ERR_PTR. At the end of the test, all threads in the array are cleaned up by kthread_stop() passing in the value in the array if it isn't zero. But if the array contains an ERR_PTR, kthread_stop() will not be able to handle it properly. Please pull the latest trace-v7.2-rc6 tree, which can be found at: git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace.git trace-v7.2-rc6 Tag SHA1: 45eb4670a102b91101fcd1e3cf1fd33bbca79ab9 Head SHA1: 91542863abade2fd4f2b361991f5386ad9d19c8c Hui Su (1): ring-buffer: Fix crash passing ERR_PTR to kthread_stop() Josh Poimboeuf (1): ftrace: Fix off-by-one fentry site disable in ftrace_free_mem() Leon Hwang (4): ftrace: Protect direct_functions in ftrace_find_rec_direct ftrace: Protect direct_functions in update_ftrace_direct_del ftrace: Protect direct_functions in update_ftrace_direct_mod ftrace: Drop extra comma in trace_buffered_event_enable Shuangpeng Bai (1): eventfs: Fix use-after-free in eventfs_remove_rec() Steven Rostedt (1): eventfs: Use children field for rcu head and add memory barriers Tengda Wu (1): ring-buffer: Use current_context for safe per-CPU buffer swap Vincent Donnefort (3): ring-buffer: Prevent resizing of persistent ring buffer ring-buffer: Prevent subbuf order change when resizing is disabled ring-buffer: Initialise reader page order in rb_allocate_cpu_buffer() ---- fs/tracefs/event_inode.c | 28 ++++++++++++++++++++++++++-- fs/tracefs/internal.h | 4 ++-- kernel/trace/ftrace.c | 33 +++++++++++++++++++++++---------- kernel/trace/ring_buffer.c | 15 +++++++++------ kernel/trace/trace.c | 2 +- 5 files changed, 61 insertions(+), 21 deletions(-) --------------------------- diff --git a/fs/tracefs/event_inode.c b/fs/tracefs/event_inode.c index 39c7a34531e8..a52458435327 100644 --- a/fs/tracefs/event_inode.c +++ b/fs/tracefs/event_inode.c @@ -124,7 +124,17 @@ static inline void put_ei(struct eventfs_inode *ei) static inline void free_ei(struct eventfs_inode *ei) { if (ei) { + /* The ei should have no children if it is being freed. */ + WARN_ON_ONCE(!list_empty(&ei->children)); ei->is_freed =3D 1; + /* + * The SRCU iteration has a smp_rmb() to make sure it + * sees a child (that may have already been freed) + * before it reads is_free. If is_free is set, it must + * not use the child it acquired from ei->children, as + * the list may be used for SRCU. + */ + smp_wmb(); put_ei(ei); } } @@ -627,6 +637,20 @@ static int eventfs_iterate(struct file *file, struct d= ir_context *ctx) list_for_each_entry_srcu(ei_child, &ei->children, list, srcu_read_lock_held(&eventfs_srcu)) { =20 + /* + * If the ei is being freed, then the ei->children may be + * being used as the rcu list, which means the next element + * may be garbage. The ei->is_free is set before switching + * the ei->children over to ei->rcu. The read memory barrier + * here makes sure the ei_child is read before is_free is + * updated. + * + * Matches the smp_wmb() in free_ei() + */ + smp_rmb(); + if (ei->is_freed) + return -EINVAL; + if (c > 0) { c--; continue; @@ -822,7 +846,7 @@ struct eventfs_inode *eventfs_create_events_dir(const c= har *name, struct dentry */ static void eventfs_remove_rec(struct eventfs_inode *ei, int level) { - struct eventfs_inode *ei_child; + struct eventfs_inode *ei_child, *tmp; =20 /* * Check recursion depth. It should never be greater than 3: @@ -835,7 +859,7 @@ static void eventfs_remove_rec(struct eventfs_inode *ei= , int level) return; =20 /* search for nested folders or files */ - list_for_each_entry(ei_child, &ei->children, list) + list_for_each_entry_safe(ei_child, tmp, &ei->children, list) eventfs_remove_rec(ei_child, level + 1); =20 list_del_rcu(&ei->list); diff --git a/fs/tracefs/internal.h b/fs/tracefs/internal.h index a4a7f8431aff..c61481d04c8e 100644 --- a/fs/tracefs/internal.h +++ b/fs/tracefs/internal.h @@ -46,11 +46,11 @@ struct eventfs_attr { * @ino: The saved inode number */ struct eventfs_inode { + struct list_head list; union { - struct list_head list; + struct list_head children; struct rcu_head rcu; }; - struct list_head children; const struct eventfs_entry *entries; const char *name; struct eventfs_attr *entry_attrs; diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 6c47a94f5924..7c50f8ae5a0c 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -2645,7 +2645,8 @@ unsigned long ftrace_find_rec_direct(unsigned long ip) { struct ftrace_func_entry *entry; =20 - entry =3D __ftrace_lookup_ip(direct_functions, ip); + guard(preempt_notrace)(); + entry =3D __ftrace_lookup_ip(rcu_dereference_sched(direct_functions), ip); if (!entry) return 0; =20 @@ -6511,6 +6512,7 @@ int update_ftrace_direct_del(struct ftrace_ops *ops, = struct ftrace_hash *hash) struct ftrace_hash *new_direct_functions; struct ftrace_hash *new_filter_hash =3D NULL; struct ftrace_hash *old_filter_hash; + struct ftrace_hash *direct_hash; struct ftrace_func_entry *entry; struct ftrace_func_entry *del; unsigned long size; @@ -6522,11 +6524,13 @@ int update_ftrace_direct_del(struct ftrace_ops *ops= , struct ftrace_hash *hash) return -EINVAL; if (!(ops->flags & FTRACE_OPS_FL_ENABLED)) return -EINVAL; - if (direct_functions =3D=3D EMPTY_HASH) - return -EINVAL; =20 mutex_lock(&direct_mutex); =20 + direct_hash =3D rcu_dereference_protected(direct_functions, lockdep_is_he= ld(&direct_mutex)); + if (direct_hash =3D=3D EMPTY_HASH) + goto out_unlock; + old_filter_hash =3D ops->func_hash ? ops->func_hash->filter_hash : NULL; =20 if (!hash_count(old_filter_hash)) @@ -6536,7 +6540,7 @@ int update_ftrace_direct_del(struct ftrace_ops *ops, = struct ftrace_hash *hash) size =3D 1 << hash->size_bits; for (int i =3D 0; i < size; i++) { hlist_for_each_entry(entry, &hash->buckets[i], hlist) { - del =3D __ftrace_lookup_ip(direct_functions, entry->ip); + del =3D __ftrace_lookup_ip(direct_hash, entry->ip); if (!del || del->direct !=3D entry->direct) goto out_unlock; } @@ -6547,7 +6551,7 @@ int update_ftrace_direct_del(struct ftrace_ops *ops, = struct ftrace_hash *hash) if (!new_filter_hash) goto out_unlock; =20 - new_direct_functions =3D hash_sub(direct_functions, hash); + new_direct_functions =3D hash_sub(direct_hash, hash); if (!new_direct_functions) goto out_unlock; =20 @@ -6574,7 +6578,7 @@ int update_ftrace_direct_del(struct ftrace_ops *ops, = struct ftrace_hash *hash) /* free the new_direct_functions */ old_direct_functions =3D new_direct_functions; } else { - old_direct_functions =3D direct_functions; + old_direct_functions =3D direct_hash; rcu_assign_pointer(direct_functions, new_direct_functions); } =20 @@ -6613,6 +6617,7 @@ int update_ftrace_direct_mod(struct ftrace_ops *ops, = struct ftrace_hash *hash, b .func =3D ftrace_stub, .flags =3D FTRACE_OPS_FL_STUB, }; + struct ftrace_hash *direct_hash; struct ftrace_hash *orig_hash; unsigned long size, i; int err =3D -EINVAL; @@ -6623,8 +6628,6 @@ int update_ftrace_direct_mod(struct ftrace_ops *ops, = struct ftrace_hash *hash, b return -EINVAL; if (!(ops->flags & FTRACE_OPS_FL_ENABLED)) return -EINVAL; - if (direct_functions =3D=3D EMPTY_HASH) - return -EINVAL; =20 /* * We can be called from within ops_func callback with direct_mutex @@ -6632,6 +6635,12 @@ int update_ftrace_direct_mod(struct ftrace_ops *ops,= struct ftrace_hash *hash, b */ if (do_direct_lock) mutex_lock(&direct_mutex); + else + lockdep_assert_held_once(&direct_mutex); + + direct_hash =3D rcu_dereference_protected(direct_functions, lockdep_is_he= ld(&direct_mutex)); + if (direct_hash =3D=3D EMPTY_HASH) + goto unlock; =20 orig_hash =3D ops->func_hash ? ops->func_hash->filter_hash : NULL; if (!orig_hash) @@ -6663,7 +6672,7 @@ int update_ftrace_direct_mod(struct ftrace_ops *ops, = struct ftrace_hash *hash, b size =3D 1 << hash->size_bits; for (i =3D 0; i < size; i++) { hlist_for_each_entry(entry, &hash->buckets[i], hlist) { - tmp =3D __ftrace_lookup_ip(direct_functions, entry->ip); + tmp =3D __ftrace_lookup_ip(direct_hash, entry->ip); if (!tmp) continue; tmp->direct =3D entry->direct; @@ -8296,7 +8305,8 @@ static void add_to_clear_hash_list(struct list_head *= clear_list, void ftrace_free_mem(struct module *mod, void *start_ptr, void *end_ptr) { unsigned long start =3D (unsigned long)(start_ptr); - unsigned long end =3D (unsigned long)(end_ptr); + /* end is inclusive and end_ptr is exclusive */ + unsigned long end =3D (unsigned long)(end_ptr) - 1; struct ftrace_page **last_pg =3D &ftrace_pages_start; struct ftrace_page *tmp_page =3D NULL; struct ftrace_page *pg; @@ -8306,6 +8316,9 @@ void ftrace_free_mem(struct module *mod, void *start_= ptr, void *end_ptr) struct ftrace_init_func *func, *func_next; LIST_HEAD(clear_hash); =20 + if (start_ptr >=3D end_ptr) + return; + key.ip =3D start; key.flags =3D end; /* overload flags, as it is unsigned long */ =20 diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 8e2485bb3aa8..2667992f0aa2 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -2510,6 +2510,7 @@ rb_allocate_cpu_buffer(struct trace_buffer *buffer, l= ong nr_pages, int cpu) bpage =3D alloc_cpu_page(cpu); if (!bpage) return NULL; + bpage->order =3D cpu_buffer->buffer->subbuf_order; =20 rb_check_bpage(cpu_buffer, bpage); =20 @@ -2528,6 +2529,8 @@ rb_allocate_cpu_buffer(struct trace_buffer *buffer, l= ong nr_pages, int cpu) if (cpu_buffer->ring_meta->head_buffer) rb_meta_buffer_update(cpu_buffer, bpage); bpage->range =3D 1; + + atomic_inc(&cpu_buffer->resize_disabled); } else if (buffer->remote) { struct ring_buffer_desc *desc =3D ring_buffer_desc(buffer->remote->desc,= cpu); =20 @@ -6852,7 +6855,7 @@ int ring_buffer_swap_cpu(struct trace_buffer *buffer_= a, { struct ring_buffer_per_cpu *cpu_buffer_a; struct ring_buffer_per_cpu *cpu_buffer_b; - int ret =3D -EINVAL; + int ret =3D -EBUSY; =20 if (!cpumask_test_cpu(cpu, buffer_a->cpumask) || !cpumask_test_cpu(cpu, buffer_b->cpumask)) @@ -6893,10 +6896,10 @@ int ring_buffer_swap_cpu(struct trace_buffer *buffe= r_a, atomic_inc(&cpu_buffer_a->record_disabled); atomic_inc(&cpu_buffer_b->record_disabled); =20 - ret =3D -EBUSY; - if (local_read(&cpu_buffer_a->committing)) + /* Do not swap if either buffer is in the process of writing */ + if (cpu_buffer_a->current_context) goto out_dec; - if (local_read(&cpu_buffer_b->committing)) + if (cpu_buffer_b->current_context) goto out_dec; =20 /* @@ -7358,7 +7361,7 @@ int ring_buffer_subbuf_order_set(struct trace_buffer = *buffer, int order) =20 cpu_buffer =3D buffer->buffers[cpu]; =20 - if (cpu_buffer->mapped) { + if (atomic_read(&cpu_buffer->resize_disabled)) { err =3D -EBUSY; goto error; } @@ -8214,7 +8217,7 @@ static __init int test_ringbuffer(void) =20 out_free: for_each_online_cpu(cpu) { - if (!rb_threads[cpu]) + if (IS_ERR_OR_NULL(rb_threads[cpu])) break; kthread_stop(rb_threads[cpu]); } diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 01a5e87af299..395238b2b715 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -1788,7 +1788,7 @@ void trace_buffered_event_enable(void) =20 per_cpu(trace_buffered_event, cpu) =3D event; =20 - scoped_guard(preempt,) { + scoped_guard(preempt) { if (cpu =3D=3D smp_processor_id() && __this_cpu_read(trace_buffered_event) !=3D per_cpu(trace_buffered_event, cpu))