From: "Steven Rostedt (Google)" <rostedt@xxxxxxxxxxx> If a field is referenced outside of the event that is being processed, do not access that field and warn about it. This was triggered when there was a bug in the kernel that showed the wrong offset to the fields that were outside the size of the event. When trace-cmd used this library to get a field of an event that was at the end of a sub buffer, it read past the page that was not allocated and crashed. Not only warn when this happens, but also just return a zero value and not read past the event. Link: https://lore.kernel.org/all/20220731015928.7ab3a154@xxxxxxxxxxxxxxxxxxxx/ Signed-off-by: Steven Rostedt (Google) <rostedt@xxxxxxxxxxx> --- src/event-parse.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/event-parse.c b/src/event-parse.c index b252c4d..b3caff6 100644 --- a/src/event-parse.c +++ b/src/event-parse.c @@ -4084,6 +4084,18 @@ static inline void dynamic_offset_field(struct tep_handle *tep, *offset += field->offset + field->size; } +static bool check_data_offset_size(struct tep_event *event, const char *field_name, + int data_size, int field_offset, int field_size) +{ + /* Check to make sure the field is within the data */ + if (field_offset + field_size <= data_size) + return false; + + tep_warning("Event '%s' field '%s' goes beyond the size of the event (%d > %d)", + event->name, field_name, field_offset + field_size, data_size); + return true; +} + static unsigned long long eval_num_arg(void *data, int size, struct tep_event *event, struct tep_print_arg *arg) { @@ -4110,6 +4122,12 @@ eval_num_arg(void *data, int size, struct tep_event *event, struct tep_print_arg if (!arg->field.field) goto out_warning_field; } + if (check_data_offset_size(event, arg->field.name, size, + arg->field.field->offset, + arg->field.field->size)) { + val = 0; + break; + } /* must be a number */ val = tep_read_number(tep, data + arg->field.field->offset, arg->field.field->size); @@ -4177,6 +4195,11 @@ eval_num_arg(void *data, int size, struct tep_event *event, struct tep_print_arg default: goto default_op; /* oops, all bets off */ } + if (check_data_offset_size(event, arg->field.name, size, + offset, field_size)) { + val = 0; + break; + } val = tep_read_number(tep, data + offset, field_size); if (typearg) @@ -4286,6 +4309,11 @@ eval_num_arg(void *data, int size, struct tep_event *event, struct tep_print_arg /* Without [], we pass the address to the dynamic data */ dynamic_offset_field(tep, arg->dynarray.field, data, size, &offset, NULL); + if (check_data_offset_size(event, arg->field.name, size, + offset, field_size)) { + val = (unsigned long)data; + break; + } val = (unsigned long long)((unsigned long)data + offset); val = (unsigned long)data + offset; break; -- 2.35.1