FAILED: patch "[PATCH] tracing: Limit access to parser->buffer when trace_get_user" failed to apply to 5.15-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 5.15-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-5.15.y
git checkout FETCH_HEAD
git cherry-pick -x 6a909ea83f226803ea0e718f6e88613df9234d58
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2025082331-pushing-surrender-b647@gregkh' --subject-prefix 'PATCH 5.15.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 6a909ea83f226803ea0e718f6e88613df9234d58 Mon Sep 17 00:00:00 2001
From: Pu Lehui <[email protected]>
Date: Wed, 13 Aug 2025 04:02:32 +0000
Subject: [PATCH] tracing: Limit access to parser->buffer when trace_get_user
failed
When the length of the string written to set_ftrace_filter exceeds FTRACE_BUFF_MAX, the following KASAN alarm will be triggered:
BUG: KASAN: slab-out-of-bounds in strsep+0x18c/0x1b0 Read of size 1 at addr ffff0000d00bd5ba by task ash/165 CPU: 1 UID: 0 PID: 165 Comm: ash Not tainted 6.16.0-g6bcdbd62bd56-dirty Hardware name: linux,dummy-virt (DT) Call trace: show_stack+0x34/0x50 (C) dump_stack_lvl+0xa0/0x158 print_address_description.constprop.0+0x88/0x398 print_report+0xb0/0x280 kasan_report+0xa4/0xf0 __asan_report_load1_noabort+0x20/0x30 strsep+0x18c/0x1b0 ftrace_process_regex.isra.0+0x100/0x2d8 ftrace_regex_release+0x484/0x618 __fput+0x364/0xa58 ____fput+0x28/0x40 task_work_run+0x154/0x278 do_notify_resume+0x1f0/0x220 el0_svc+0xec/0xf0 el0t_64_sync_handler+0xa0/0xe8 el0t_64_sync+0x1ac/0x1b0
The reason is that trace_get_user will fail when processing a string longer than FTRACE_BUFF_MAX, but not set the end of parser->buffer to 0. Then an OOB access will be triggered in ftrace_regex_release-> ftrace_process_regex->strsep->strpbrk. We can solve this problem by limiting access to parser->buffer when trace_get_user failed.
kernel/trace/trace.c +12 -6
@@ -1816,7 +1816,7 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf, ret =get_user (ch, ubuf++);if (ret) -return ret; + goto fail; read++; cnt--;
@@ -1830,7 +1830,7 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf,while (cnt &&isspace (ch)) { ret =get_user (ch, ubuf++);if (ret) -return ret; + goto fail; read++; cnt--; }
@@ -1848,12 +1848,14 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf,while (cnt && !isspace (ch) && ch) {if (parser->idx < parser->size -1 ) parser->buffer[parser->idx++] = ch; -else -return -EINVAL ; +else { + ret = -EINVAL ; + goto fail; + } ret =get_user (ch, ubuf++);if (ret) -return ret; + goto fail; read++; cnt--; }
@@ -1868,11 +1870,15 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf,/* Make sure the parsed string always terminates with '\0'. */ parser->buffer[parser->idx] =0 ; }else { -return -EINVAL ; + ret = -EINVAL ; + goto fail; } *ppos += read;return read; +fail: +trace_parser_fail (parser); +return ret; }/* TODO add a seq_buf_to_buffer() */
kernel/trace/trace.h +7 -1
@@ -1292,6 +1292,7 @@ bool ftrace_event_is_function(struct trace_event_call *call);*/ struct trace_parser {bool cont; +bool fail;char *buffer;unsigned idx;unsigned size;
@@ -1299,7 +1300,7 @@ struct trace_parser {static inline bool trace_parser_loaded (struct trace_parser *parser) { -return (parser->idx !=0 ); +return !parser->fail && parser->idx !=0 ; }static inline bool trace_parser_cont (struct trace_parser *parser)
@@ -1313,6 +1314,11 @@ static inline void trace_parser_clear(struct trace_parser *parser) parser->idx =0 ; } +static inline void trace_parser_fail (struct trace_parser *parser) +{ + parser->fail = true; +} +extern int trace_parser_get_init (struct trace_parser *parser,int size);extern void trace_parser_put (struct trace_parser *parser); extern int trace_get_user(struct trace_parser *parser, const char __user *ubuf,
Sasha Levin
maintainerPATCH 1/2 tracing: Remove unneeded goto out logic
From: Steven Rostedt <[email protected]>
[ Upstream commit c89504a703fb779052213add0e8ed642f4a4f1c8 ]
Several places in the trace.c file there's a goto out where the out is simply a return. There's no reason to jump to the out label if it's not doing any more logic but simply returning from the function.
Replace the goto outs with a return and remove the out labels.
--- kernel/trace/trace.c | 37 ++++++++++++++----------------------- 1 file changed, 14 insertions(+), 23 deletions(-)
kernel/trace/trace.c +14 -23
@@ -1605,7 +1605,7 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf, ret =get_user (ch, ubuf++);if (ret) - goto out; +return ret; read++; cnt--;
@@ -1619,7 +1619,7 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf,while (cnt &&isspace (ch)) { ret =get_user (ch, ubuf++);if (ret) - goto out; +return ret; read++; cnt--; }
@@ -1629,8 +1629,7 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf,/* only spaces were written */ if (isspace (ch) || !ch) { *ppos += read; - ret = read; - goto out; +return read; } }
@@ -1638,13 +1637,12 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf,while (cnt && !isspace (ch) && ch) {if (parser->idx < parser->size -1 ) parser->buffer[parser->idx++] = ch; -else { - ret = -EINVAL ; - goto out; - } +else +return -EINVAL ; + ret =get_user (ch, ubuf++);if (ret) - goto out; +return ret; read++; cnt--; }
@@ -1659,15 +1657,11 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf,/* Make sure the parsed string always terminates with '\0'. */ parser->buffer[parser->idx] =0 ; }else { - ret = -EINVAL ; - goto out; +return -EINVAL ; } *ppos += read; - ret = read; - -out: -return ret; +return read; }/* TODO add a seq_buf_to_buffer() */
@@ -2136,10 +2130,10 @@ int __init register_tracer(struct tracer *type)mutex_unlock (&trace_types_lock);if (ret || !default_bootup_tracer) - goto out_unlock; +return ret;if (strncmp (default_bootup_tracer, type->name,MAX_TRACER_SIZE )) - goto out_unlock; +return 0 ;printk (KERN_INFO "Starting tracer '%s'\n" , type->name);/* Do we want this tracer to start on bootup? */
@@ -2151,8 +2145,7 @@ int __init register_tracer(struct tracer *type)/* disable other selftests, since this will break it. */ disable_tracing_selftest ("running a tracer" ); - out_unlock: -return ret; +return 0 ; }static void tracing_reset_cpu (struct array_buffer *buf,int cpu)
@@ -8711,11 +8704,10 @@ ftrace_trace_snapshot_callback(struct trace_array *tr, struct ftrace_hash *hash, out_reg: ret =tracing_alloc_snapshot_instance (tr);if (ret <0 ) - goto out; +return ret; ret =register_ftrace_function_probe (glob, tr, ops, count); - out:return ret <0 ? ret :0 ; }
@@ -10231,7 +10223,7 @@ __init static int tracer_alloc_buffers(void)BUILD_BUG_ON (TRACE_ITER_LAST_BIT >TRACE_FLAGS_MAX_SIZE );if (!alloc_cpumask_var (&tracing_buffer_mask,GFP_KERNEL )) - goto out; +return -ENOMEM ;if (!alloc_cpumask_var (&global_trace.tracing_cpumask,GFP_KERNEL )) goto out_free_buffer_mask;
@@ -10344,7 +10336,6 @@ __init static int tracer_alloc_buffers(void)free_cpumask_var (global_trace.tracing_cpumask); out_free_buffer_mask:free_cpumask_var (tracing_buffer_mask); -out:return ret; }
Signature · 1 line
2.50.1
Sasha Levin
maintainerPATCH 2/2 tracing: Limit access to parser->buffer when trace_get_user failed
From: Pu Lehui <[email protected]>
[ Upstream commit 6a909ea83f226803ea0e718f6e88613df9234d58 ]
When the length of the string written to set_ftrace_filter exceeds FTRACE_BUFF_MAX, the following KASAN alarm will be triggered:
BUG: KASAN: slab-out-of-bounds in strsep+0x18c/0x1b0 Read of size 1 at addr ffff0000d00bd5ba by task ash/165 CPU: 1 UID: 0 PID: 165 Comm: ash Not tainted 6.16.0-g6bcdbd62bd56-dirty Hardware name: linux,dummy-virt (DT) Call trace: show_stack+0x34/0x50 (C) dump_stack_lvl+0xa0/0x158 print_address_description.constprop.0+0x88/0x398 print_report+0xb0/0x280 kasan_report+0xa4/0xf0 __asan_report_load1_noabort+0x20/0x30 strsep+0x18c/0x1b0 ftrace_process_regex.isra.0+0x100/0x2d8 ftrace_regex_release+0x484/0x618 __fput+0x364/0xa58 ____fput+0x28/0x40 task_work_run+0x154/0x278 do_notify_resume+0x1f0/0x220 el0_svc+0xec/0xf0 el0t_64_sync_handler+0xa0/0xe8 el0t_64_sync+0x1ac/0x1b0
The reason is that trace_get_user will fail when processing a string longer than FTRACE_BUFF_MAX, but not set the end of parser->buffer to 0. Then an OOB access will be triggered in ftrace_regex_release-> ftrace_process_regex->strsep->strpbrk. We can solve this problem by limiting access to parser->buffer when trace_get_user failed.
--- kernel/trace/trace.c | 18 ++++++++++++------ kernel/trace/trace.h | 8 +++++++- 2 files changed, 19 insertions(+), 7 deletions(-)
kernel/trace/trace.c +12 -6
@@ -1605,7 +1605,7 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf, ret =get_user (ch, ubuf++);if (ret) -return ret; + goto fail; read++; cnt--;
@@ -1619,7 +1619,7 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf,while (cnt &&isspace (ch)) { ret =get_user (ch, ubuf++);if (ret) -return ret; + goto fail; read++; cnt--; }
@@ -1637,12 +1637,14 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf,while (cnt && !isspace (ch) && ch) {if (parser->idx < parser->size -1 ) parser->buffer[parser->idx++] = ch; -else -return -EINVAL ; +else { + ret = -EINVAL ; + goto fail; + } ret =get_user (ch, ubuf++);if (ret) -return ret; + goto fail; read++; cnt--; }
@@ -1657,11 +1659,15 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf,/* Make sure the parsed string always terminates with '\0'. */ parser->buffer[parser->idx] =0 ; }else { -return -EINVAL ; + ret = -EINVAL ; + goto fail; } *ppos += read;return read; +fail: +trace_parser_fail (parser); +return ret; }/* TODO add a seq_buf_to_buffer() */
kernel/trace/trace.h +7 -1
@@ -1132,6 +1132,7 @@ bool ftrace_event_is_function(struct trace_event_call *call);*/ struct trace_parser {bool cont; +bool fail;char *buffer;unsigned idx;unsigned size;
@@ -1139,7 +1140,7 @@ struct trace_parser {static inline bool trace_parser_loaded (struct trace_parser *parser) { -return (parser->idx !=0 ); +return !parser->fail && parser->idx !=0 ; }static inline bool trace_parser_cont (struct trace_parser *parser)
@@ -1153,6 +1154,11 @@ static inline void trace_parser_clear(struct trace_parser *parser) parser->idx =0 ; } +static inline void trace_parser_fail (struct trace_parser *parser) +{ + parser->fail = true; +} +extern int trace_parser_get_init (struct trace_parser *parser,int size);extern void trace_parser_put (struct trace_parser *parser); extern int trace_get_user(struct trace_parser *parser, const char __user *ubuf,
Signature · 1 line
2.50.1