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)

Reply via email to