user_event_parse_field() accepts large structure sizes but accumulates
field offsets in a u32 before storing them in signed int fields. A
declaration can wrap the recorded minimum event size while a fixed-width
field retains an offset outside the accepted record. A short write is
then accepted and a field filter reads beyond the event buffer.
KASAN reports:
BUG: KASAN: slab-use-after-free in filter_match_preds
Read of size 8
filter_match_preds
trace_event_buffer_commit
user_event_ftrace
user_events_write_core
Use checked addition and reject offsets that cannot be represented by the
downstream signed fields.
The patched kernel rejects the overflowing declaration and accepts a valid
control event without a KASAN report.
Fixes: 7f5a08c79df3 ("user_events: Add minimal support for trace_event into
ftrace")
Signed-off-by: Yifan Zhang <[email protected]>
---
kernel/trace/trace_events_user.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/kernel/trace/trace_events_user.c b/kernel/trace/trace_events_user.c
index 85938b45b7618..88d384c9e101f 100644
--- a/kernel/trace/trace_events_user.c
+++ b/kernel/trace/trace_events_user.c
@@ -1207,6 +1207,7 @@ static int user_event_parse_field(char *field, struct
user_event *user,
{
char *part, *type, *name;
u32 depth = 0, saved_offset = *offset;
+ u32 new_offset;
int len, size = -EINVAL;
bool is_struct = false;
@@ -1287,7 +1288,11 @@ parse:
if (size < 0)
return size;
- *offset = saved_offset + size;
+ if (check_add_overflow(saved_offset, (u32)size, &new_offset) ||
+ new_offset > INT_MAX)
+ return -E2BIG;
+
+ *offset = new_offset;
return user_event_add_field(user, type, name, saved_offset, size,
type[0] != 'u', FILTER_OTHER);
--
2.39.5 (Apple Git-154)