Skip to content

Commit 3079517

Browse files
Pu Lehuigregkh
authored andcommitted
tracing: Limit access to parser->buffer when trace_get_user failed
[ Upstream commit 6a909ea ] 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. Cc: stable@vger.kernel.org Link: https://lore.kernel.org/20250813040232.1344527-1-pulehui@huaweicloud.com Fixes: 8c9af47 ("ftrace: Handle commands when closing set_ftrace_filter file") Signed-off-by: Pu Lehui <pulehui@huawei.com> Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org> Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent a970a8a commit 3079517

File tree

2 files changed

+19
-7
lines changed

2 files changed

+19
-7
lines changed

kernel/trace/trace.c

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1846,7 +1846,7 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf,
18461846

18471847
ret = get_user(ch, ubuf++);
18481848
if (ret)
1849-
return ret;
1849+
goto fail;
18501850

18511851
read++;
18521852
cnt--;
@@ -1860,7 +1860,7 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf,
18601860
while (cnt && isspace(ch)) {
18611861
ret = get_user(ch, ubuf++);
18621862
if (ret)
1863-
return ret;
1863+
goto fail;
18641864
read++;
18651865
cnt--;
18661866
}
@@ -1878,12 +1878,14 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf,
18781878
while (cnt && !isspace(ch) && ch) {
18791879
if (parser->idx < parser->size - 1)
18801880
parser->buffer[parser->idx++] = ch;
1881-
else
1882-
return -EINVAL;
1881+
else {
1882+
ret = -EINVAL;
1883+
goto fail;
1884+
}
18831885

18841886
ret = get_user(ch, ubuf++);
18851887
if (ret)
1886-
return ret;
1888+
goto fail;
18871889
read++;
18881890
cnt--;
18891891
}
@@ -1898,11 +1900,15 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf,
18981900
/* Make sure the parsed string always terminates with '\0'. */
18991901
parser->buffer[parser->idx] = 0;
19001902
} else {
1901-
return -EINVAL;
1903+
ret = -EINVAL;
1904+
goto fail;
19021905
}
19031906

19041907
*ppos += read;
19051908
return read;
1909+
fail:
1910+
trace_parser_fail(parser);
1911+
return ret;
19061912
}
19071913

19081914
/* TODO add a seq_buf_to_buffer() */

kernel/trace/trace.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1292,14 +1292,15 @@ bool ftrace_event_is_function(struct trace_event_call *call);
12921292
*/
12931293
struct trace_parser {
12941294
bool cont;
1295+
bool fail;
12951296
char *buffer;
12961297
unsigned idx;
12971298
unsigned size;
12981299
};
12991300

13001301
static inline bool trace_parser_loaded(struct trace_parser *parser)
13011302
{
1302-
return (parser->idx != 0);
1303+
return !parser->fail && parser->idx != 0;
13031304
}
13041305

13051306
static inline bool trace_parser_cont(struct trace_parser *parser)
@@ -1313,6 +1314,11 @@ static inline void trace_parser_clear(struct trace_parser *parser)
13131314
parser->idx = 0;
13141315
}
13151316

1317+
static inline void trace_parser_fail(struct trace_parser *parser)
1318+
{
1319+
parser->fail = true;
1320+
}
1321+
13161322
extern int trace_parser_get_init(struct trace_parser *parser, int size);
13171323
extern void trace_parser_put(struct trace_parser *parser);
13181324
extern int trace_get_user(struct trace_parser *parser, const char __user *ubuf,

0 commit comments

Comments
 (0)