From nobody Sat Sep 26 09:19:12 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (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 BFFF240DB45; Wed, 2 Sep 2026 21:25:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788384341; cv=none; b=CbKwKghap0Yy/FXky1NP9Dp79tRQyhkhTHUpqd19jyc6wDKRqPT8Wpf8LJPj3HG7i6XA2bKcWHl9Eoe7gvlUhYEQ9LDIQMjo0ARTw+NWZ3avg2aSgmpUpApxn4W2vOXTvNYGDvNpJFFdJL7Zv9rWF9NegZxXtioK+9lLsM09BMI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788384341; c=relaxed/simple; bh=nASpRVZNQfybcknvo2KZJ092zpupeGE1xqHWWG2ZuLE=; h=Message-ID:Date:From:To:Cc:Subject:References:MIME-Version: Content-Type; b=WVnJ+rv7xSk2fOsNQifV4ex5BCOf28KJKwxTtTW1AFiPRK9tkTEocJGbQAWxZrk9a83FiCewdy+iEw6HU+vMqtyGYJ6bdsIRL6kg3ke8eZC6n7MsBcN0kLz95Z9HIYB0p4osHbAwtuSMGemJNoSiql52iKuBI5xhP2KulQxxkHw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=CPeh9yn9; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="CPeh9yn9" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4C2C91F00A3A; Wed, 2 Sep 2026 21:25:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1788384336; bh=WdcIkIc+E7fO4R7iGBi1jsLtuH0TPPijixHoyZ+hEag=; h=Date:From:To:Cc:Subject:References; b=CPeh9yn9h1UacsUlrjfGNDhMpPvRvr8LG8Tu4eAJVJrQHTKnGn+/tvRWMR/hcMA4Q 5bWzn8yW39EPteeZh9/hzjRjN4PKEb94gigzEdVq3H+7aUDvhihzXEu4lZtbYVrQvL donYJL8Nyj4KmybmHuB0UwB1SfCU+98oouL1ljlfhqtTQ9KhEXVd7Q5hNZXES61YcV lRaUVDO1eI3ooqUaBGkH8ug7mHRCXdfbubDN2Wdko+/GrfQlUSWGEWH84vSVb5OC55 gxkWapyNXRuW1fpv73HIga2ILNbUWQXujgeUykZSP74jsRA6I7RheCnLvYbi/Brn7a TUZ+I+UVSflVQ== Received: from rostedt by gandalf with local (Exim 4.99.4) (envelope-from ) id 1x1sTe-0000000ECdp-0CUQ; Wed, 02 Sep 2026 17:26:38 -0400 Message-ID: <20260902212637.906950608@kernel.org> User-Agent: quilt/0.69 Date: Wed, 02 Sep 2026 17:26:10 -0400 From: Steven Rostedt To: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org Cc: Masami Hiramatsu , Mark Rutland , Mathieu Desnoyers , Andrew Morton Subject: [PATCH 1/2] tracing: Use a single array to represent tracer options files References: <20260902212609.542937225@kernel.org> 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" From: Steven Rostedt An instance is represented by a trace_array descriptor that has an array for options of each tracer. That array is a pointer to another array that represents every option for a specific tracer. Instead of having two arrays use just a single array for every tracer option within a trace_array. This not only simplifies the logic for representing the tracer option in the callbacks, but also can be used to simplify a way to find the trace_array descriptor from this one single array when needing to find which trace_array the option is attached to in order to take its reference. Signed-off-by: Steven Rostedt --- kernel/trace/trace.c | 47 ++++++++++++++++++-------------------------- kernel/trace/trace.h | 21 ++++++++------------ 2 files changed, 27 insertions(+), 41 deletions(-) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 722d0ba2d233..f26244253a8b 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -7689,7 +7689,7 @@ static ssize_t trace_options_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) { - struct trace_option_dentry *topt =3D filp->private_data; + struct trace_options *topt =3D filp->private_data; char *buf; =20 if (topt->flags->val & topt->opt->bit) @@ -7704,7 +7704,7 @@ static ssize_t trace_options_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) { - struct trace_option_dentry *topt =3D filp->private_data; + struct trace_options *topt =3D filp->private_data; unsigned long val; int ret; =20 @@ -7730,7 +7730,7 @@ trace_options_write(struct file *filp, const char __u= ser *ubuf, size_t cnt, =20 static int tracing_open_options(struct inode *inode, struct file *filp) { - struct trace_option_dentry *topt =3D inode->i_private; + struct trace_options *topt =3D inode->i_private; int ret; =20 ret =3D tracing_check_open_get_tr(topt->tr); @@ -7743,7 +7743,7 @@ static int tracing_open_options(struct inode *inode, = struct file *filp) =20 static int tracing_release_options(struct inode *inode, struct file *file) { - struct trace_option_dentry *topt =3D file->private_data; + struct trace_options *topt =3D file->private_data; =20 trace_array_put(topt->tr); return 0; @@ -7946,8 +7946,9 @@ static struct dentry *trace_options_init_dentry(struc= t trace_array *tr) =20 static void create_trace_option_file(struct trace_array *tr, - struct trace_option_dentry *topt, + struct trace_options *topt, struct tracer_flags *flags, + struct tracer *tracer, struct tracer_opt *opt) { struct dentry *t_options; @@ -7959,6 +7960,7 @@ create_trace_option_file(struct trace_array *tr, topt->flags =3D flags; topt->opt =3D opt; topt->tr =3D tr; + topt->tracer =3D tracer; =20 topt->entry =3D trace_create_file(opt->name, TRACE_MODE_WRITE, t_options, topt, &trace_options_fops); @@ -7968,10 +7970,9 @@ static int create_trace_option_files(struct trace_array *tr, struct tracer *tracer, struct tracer_flags *flags) { - struct trace_option_dentry *topts; - struct trace_options *tr_topts; + struct trace_options *topts; struct tracer_opt *opts; - int cnt; + int i, cnt; =20 if (!flags || !flags->opts) return 0; @@ -7981,29 +7982,22 @@ create_trace_option_files(struct trace_array *tr, s= truct tracer *tracer, for (cnt =3D 0; opts[cnt].name; cnt++) ; =20 - topts =3D kzalloc_objs(*topts, cnt + 1); - if (!topts) - return 0; - - tr_topts =3D krealloc_array(tr->topts, tr->nr_topts + 1, sizeof(*tr->topt= s), + topts =3D krealloc_array(tr->topts, tr->nr_topts + cnt, sizeof(*tr->topts= ), GFP_KERNEL); - if (!tr_topts) { - kfree(topts); + if (!topts) return -ENOMEM; - } =20 - tr->topts =3D tr_topts; - tr->topts[tr->nr_topts].tracer =3D tracer; - tr->topts[tr->nr_topts].topts =3D topts; - tr->nr_topts++; + tr->topts =3D topts; =20 - for (cnt =3D 0; opts[cnt].name; cnt++) { - create_trace_option_file(tr, &topts[cnt], flags, - &opts[cnt]); - MEM_FAIL(topts[cnt].entry =3D=3D NULL, + for (topts +=3D tr->nr_topts, i =3D 0; i < cnt; topts++, i++) { + create_trace_option_file(tr, topts, flags, tracer, + &opts[i]); + MEM_FAIL(topts->entry =3D=3D NULL, "Failed to create trace option: %s", - opts[cnt].name); + opts[i].name); } + + tr->nr_topts +=3D cnt; return 0; } =20 @@ -8865,9 +8859,6 @@ static int __remove_instance(struct trace_array *tr) if (tr->flags & TRACE_ARRAY_FL_VMALLOC) vfree((void *)tr->range_addr_start); =20 - for (i =3D 0; i < tr->nr_topts; i++) { - kfree(tr->topts[i].topts); - } kfree(tr->topts); =20 free_cpumask_var(tr->pipe_cpumask); diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 3c111ca88e32..a07802be5673 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -224,11 +224,6 @@ struct array_buffer { =20 #define TRACE_FLAGS_MAX_SIZE 64 =20 -struct trace_options { - struct tracer *tracer; - struct trace_option_dentry *topts; -}; - struct trace_pid_list *trace_pid_list_alloc(void); void trace_pid_list_free(struct trace_pid_list *pid_list); bool trace_pid_list_is_set(struct trace_pid_list *pid_list, unsigned int p= id); @@ -325,6 +320,14 @@ struct trace_module_delta { long delta[]; }; =20 +struct trace_options { + struct tracer_opt *opt; + struct tracer_flags *flags; + struct trace_array *tr; + struct tracer *tracer; + struct dentry *entry; +}; + /* * The trace array - an array of per-CPU trace arrays. This is the * highest level data structure that individual tracers deal with. @@ -605,14 +608,6 @@ struct tracer_flags { /* Makes more easy to define a tracer opt */ #define TRACER_OPT(s, b) .name =3D #s, .bit =3D b =20 - -struct trace_option_dentry { - struct tracer_opt *opt; - struct tracer_flags *flags; - struct trace_array *tr; - struct dentry *entry; -}; - /** * struct tracer - a specific tracer and its callbacks to interact with tr= acefs * @name: the name chosen to select it on the available_tracers file --=20 2.53.0 From nobody Sat Sep 26 09:19:12 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (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 C3ACF4AEBE4; Wed, 2 Sep 2026 21:25:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788384342; cv=none; b=HYd4ULxs346yr5BPtLUUfTjgU2ETxnEdBI0Fhz9cBANNRbsvr5yQGheyTvuk+gvxOhbyEjd1SeoWkNqUNLy/L6rm1bWFu+48shKKsPlpfoYj3gaFUWGjjrMxvKqwo6rbp1ZSKtpRBumpz5d1ROOQCoieByyqSJxh7RBq33Q9KOo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788384342; c=relaxed/simple; bh=X56F6/Rw/OC7cVqwl8APBTeGZERd8XZX5CpXU9160IY=; h=Message-ID:Date:From:To:Cc:Subject:References:MIME-Version: Content-Type; b=DhHQYpZF9Vusdvwy/y0L6EBsrDblqELJsU5a4rnR5sitRWCsusQoXe1C2DYq76B/j3UnqcPpWULlalmnCHJtP7zcOyqy12FHCmBTGCHArCzMl+Ho94rRUzo5lqXBQaReC+PGXE/1hpY5H2Bs6wqhZHzE9SmAbUUNARDohwf85P4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=L02hJBDg; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="L02hJBDg" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 648D11F00A3F; Wed, 2 Sep 2026 21:25:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1788384336; bh=YPWAPuL82q8pso9D+jtuK/10ik3eUpR2CT7apuaRUKQ=; h=Date:From:To:Cc:Subject:References; b=L02hJBDgU2rj7eqaXG2Y8OIsUC+b9Kne9Ei7FwqHkL2koruHcCuml15QyETIy1NhE rVyXcgmpNKAnqXjUCgQ2OdXsioccEaUmtgI85h5NgY1YJolUS4kbZSBI9UYNiX/s2I klX0jplyQ7RhCweZmG2di7akcHkvlJTQ35iy8PzdrQF35YaoD3ffF+4iDSbc+8EfJC 9reWNu1pxAbe+Eic+vvjuBmHJoC8+7aJguemkt2F052pFnBBcFDJYtgJIrN0WTE4Q0 0ekep5JObiCcKOBwd5a4SRhwrIJTcxTrZj7avGShNyeRheUphAaC4aF2EiZi9IRxH+ xQjIzNSRCRoEQ== Received: from rostedt by gandalf with local (Exim 4.99.4) (envelope-from ) id 1x1sTe-0000000ECeu-0swp; Wed, 02 Sep 2026 17:26:38 -0400 Message-ID: <20260902212638.065669192@kernel.org> User-Agent: quilt/0.69 Date: Wed, 02 Sep 2026 17:26:11 -0400 From: Steven Rostedt To: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org Cc: Masami Hiramatsu , Mark Rutland , Mathieu Desnoyers , Andrew Morton , stable@vger.kernel.org, sashiko-bot@kernel.org Subject: [PATCH 2/2] tracing: Take trace_array reference when opening a tracer options file References: <20260902212609.542937225@kernel.org> 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" From: Steven Rostedt When a tracer option file is opened, it is passed a descriptor that points to an element on the trace_array's topts array. This element has information to find the trace array and other information. It uses this element to take a reference of the trace_array so that the trace_array does not get removed while this file is opened. Unfortunately, there's a race condition where the element itself could be freed by the removal of the instance the trace_array represents causing a use-after-free as this element that is used to find the trace_array to increment its reference counter is also freed when the instance is removed. To solve this, add a trace_array_tracer_options_get() helper function that will take the address of the element that is passed to the open function by the inode->i_private pointer and search all the trace_arrays under a lock to find the one that the element's address is in the range of the trace_arrays topts array. When a match happens, that trace_array's reference would be increased. Note, there's a race where if an admin was deleting and creating trace instances at the same time and the memory of the old trace_array's array matched the memory of the new trace_array that it could in theory open the option from the wrong trace array. But we do not care because it would be stupid to perform that kind of action. As long as the only thing that can happen is that the option from the wrong trace array is used and doesn't crash the kernel it will only make the user confused. But if they are doing something stupid like this, they are already confused, so no harm done. Cc: stable@vger.kernel.org Fixes: 7e2cfbd2d3c86 ("tracing: Have option files inc the trace array ref c= ount") Reported-by: sashiko-bot@kernel.org Closes: https://lore.kernel.org/linux-trace-kernel/20260902121918.5a9e9d1b@= gandalf.local.home/ Signed-off-by: Steven Rostedt --- kernel/trace/trace.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index f26244253a8b..03080fcf7f04 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -7728,12 +7728,44 @@ trace_options_write(struct file *filp, const char _= _user *ubuf, size_t cnt, return cnt; } =20 +/* + * The topt is the address of a trace_array->topts[] element that holds the + * the tracer options descriptor. But since the trace_array reference has = not + * been taken yet, it cannot be dereferenced as it could have been freed by + * a rmdir of the instance the trace_array represents. + * + * Search the list of trace_arrays and compare the topt to the address of + * the entire trace_array topts array for each trace_array in the list. + * If one is matched, then take the reference and return it. If not, the + * trace_array no longer exits. + */ +static int trace_array_tracer_options_get(void *topt) +{ + struct trace_array *tr; + int ret; + + ret =3D security_locked_down(LOCKDOWN_TRACEFS); + if (ret) + return ret; + + if (tracing_disabled) + return -ENODEV; + + guard(mutex)(&trace_types_lock); + list_for_each_entry(tr, &ftrace_trace_arrays, list) { + if (topt >=3D (void *)&tr->topts[0] && + topt < (void *)&tr->topts[tr->nr_topts]) + return __trace_array_get(tr); + } + return -ENODEV; +} + static int tracing_open_options(struct inode *inode, struct file *filp) { struct trace_options *topt =3D inode->i_private; int ret; =20 - ret =3D tracing_check_open_get_tr(topt->tr); + ret =3D trace_array_tracer_options_get(topt); if (ret) return ret; =20 --=20 2.53.0