The "cpu" field of trace entries processed by rtla in tracefs mode is
used as an index into an array of size nr_cpus. In case the cpu numbers
mismatch because either the kernel or rtla reporting the number
incorrectly, out-of-bounds read/write may occur.

Guard against this by dropping trace entries with cpu >= nr_cpus in
collect_registered_events(). A new counter, "invalid_events", is added
to struct trace_instance, and printed (if non zero) next to the
pre-existing missed events counter.

Signed-off-by: Tomas Glozar <[email protected]>
---
 tools/tracing/rtla/src/common.h        |  2 --
 tools/tracing/rtla/src/osnoise.c       | 26 +++++++++++++++++++++++++-
 tools/tracing/rtla/src/osnoise.h       |  2 ++
 tools/tracing/rtla/src/osnoise_hist.c  |  1 +
 tools/tracing/rtla/src/osnoise_top.c   |  1 +
 tools/tracing/rtla/src/timerlat_hist.c |  1 +
 tools/tracing/rtla/src/timerlat_top.c  |  1 +
 tools/tracing/rtla/src/trace.c         |  7 +++++++
 tools/tracing/rtla/src/trace.h         |  1 +
 tools/tracing/rtla/src/utils.h         |  2 ++
 10 files changed, 41 insertions(+), 3 deletions(-)

diff --git a/tools/tracing/rtla/src/common.h b/tools/tracing/rtla/src/common.h
index 04b287a03f6d4..051d56182276b 100644
--- a/tools/tracing/rtla/src/common.h
+++ b/tools/tracing/rtla/src/common.h
@@ -114,8 +114,6 @@ struct common_params {
        struct timerlat_u_params user;
 };
 
-extern int nr_cpus;
-
 #define for_each_monitored_cpu(cpu, common) \
        for (cpu = 0; cpu < nr_cpus; cpu++) \
                if (!(common)->cpus || CPU_ISSET(cpu, 
&(common)->monitored_cpus))
diff --git a/tools/tracing/rtla/src/osnoise.c b/tools/tracing/rtla/src/osnoise.c
index 4ff5dad013b10..b9bcbf9ee430c 100644
--- a/tools/tracing/rtla/src/osnoise.c
+++ b/tools/tracing/rtla/src/osnoise.c
@@ -1224,6 +1224,29 @@ bool osnoise_trace_is_off(struct osnoise_tool *tool, 
struct osnoise_tool *record
        return record && !tracefs_trace_is_on(record->trace.inst);
 }
 
+/*
+ * osnoise_report_invalid_events - report number of invalid events
+ */
+void
+osnoise_report_invalid_events(struct osnoise_tool *tool)
+{
+       unsigned long long total_events;
+
+       if (tool->trace.invalid_events > 0) {
+               if (tool->trace.missed_events != UINT64_MAX) {
+                       total_events = tool->trace.processed_events + 
tool->trace.invalid_events +
+                               tool->trace.missed_events;
+
+                       printf("%lld (%.2f%%) invalid events, results might not 
be accurate\n",
+                               tool->trace.invalid_events,
+                               (double) tool->trace.invalid_events / 
total_events * 100.0);
+               } else {
+                       printf("%lld invalid events, results might not be 
accurate\n",
+                               tool->trace.invalid_events);
+               }
+       }
+}
+
 /*
  * osnoise_report_missed_events - report number of events dropped by trace
  * buffer
@@ -1236,7 +1259,8 @@ osnoise_report_missed_events(struct osnoise_tool *tool)
        if (tool->trace.missed_events == UINT64_MAX)
                printf("unknown number of events missed, results might not be 
accurate\n");
        else if (tool->trace.missed_events > 0) {
-               total_events = tool->trace.processed_events + 
tool->trace.missed_events;
+               total_events = tool->trace.processed_events + 
tool->trace.invalid_events +
+                       tool->trace.missed_events;
 
                printf("%lld (%.2f%%) events missed, results might not be 
accurate\n",
                       tool->trace.missed_events,
diff --git a/tools/tracing/rtla/src/osnoise.h b/tools/tracing/rtla/src/osnoise.h
index 340ff5a64e6e4..b54e9ebef7f27 100644
--- a/tools/tracing/rtla/src/osnoise.h
+++ b/tools/tracing/rtla/src/osnoise.h
@@ -56,6 +56,8 @@ void osnoise_restore_timerlat_align_us(struct osnoise_context 
*context);
 int osnoise_set_timerlat_align(struct osnoise_context *context, bool onoff);
 
 int osnoise_set_irq_disable(struct osnoise_context *context, bool onoff);
+
+void osnoise_report_invalid_events(struct osnoise_tool *tool);
 void osnoise_report_missed_events(struct osnoise_tool *tool);
 int osnoise_apply_config(struct osnoise_tool *tool, struct osnoise_params 
*params);
 
diff --git a/tools/tracing/rtla/src/osnoise_hist.c 
b/tools/tracing/rtla/src/osnoise_hist.c
index dfa91d0681f8f..bad0b8958ddb2 100644
--- a/tools/tracing/rtla/src/osnoise_hist.c
+++ b/tools/tracing/rtla/src/osnoise_hist.c
@@ -397,6 +397,7 @@ osnoise_print_stats(struct osnoise_tool *tool)
        trace_seq_reset(trace->seq);
 
        osnoise_print_summary(params, trace, data);
+       osnoise_report_invalid_events(tool);
        osnoise_report_missed_events(tool);
 }
 
diff --git a/tools/tracing/rtla/src/osnoise_top.c 
b/tools/tracing/rtla/src/osnoise_top.c
index 512a6299cb018..3c0ff82a4b5c8 100644
--- a/tools/tracing/rtla/src/osnoise_top.c
+++ b/tools/tracing/rtla/src/osnoise_top.c
@@ -242,6 +242,7 @@ osnoise_print_stats(struct osnoise_tool *top)
 
        trace_seq_do_printf(trace->seq);
        trace_seq_reset(trace->seq);
+       osnoise_report_invalid_events(top);
        osnoise_report_missed_events(top);
 }
 
diff --git a/tools/tracing/rtla/src/timerlat_hist.c 
b/tools/tracing/rtla/src/timerlat_hist.c
index df7b1398a966d..b6af5ba11340d 100644
--- a/tools/tracing/rtla/src/timerlat_hist.c
+++ b/tools/tracing/rtla/src/timerlat_hist.c
@@ -682,6 +682,7 @@ timerlat_print_stats(struct osnoise_tool *tool)
 
        timerlat_print_summary(params, trace, data);
        timerlat_print_stats_all(params, trace, data);
+       osnoise_report_invalid_events(tool);
        osnoise_report_missed_events(tool);
 }
 
diff --git a/tools/tracing/rtla/src/timerlat_top.c 
b/tools/tracing/rtla/src/timerlat_top.c
index 6206a0a565ad3..2afd619c16059 100644
--- a/tools/tracing/rtla/src/timerlat_top.c
+++ b/tools/tracing/rtla/src/timerlat_top.c
@@ -456,6 +456,7 @@ timerlat_print_stats(struct osnoise_tool *top)
 
        trace_seq_do_printf(trace->seq);
        trace_seq_reset(trace->seq);
+       osnoise_report_invalid_events(top);
        osnoise_report_missed_events(top);
 }
 
diff --git a/tools/tracing/rtla/src/trace.c b/tools/tracing/rtla/src/trace.c
index e407447773d04..1c3e2b098ba81 100644
--- a/tools/tracing/rtla/src/trace.c
+++ b/tools/tracing/rtla/src/trace.c
@@ -138,6 +138,12 @@ collect_registered_events(struct tep_event *event, struct 
tep_record *record,
        struct trace_instance *trace = context;
        struct trace_seq *s = trace->seq;
 
+       if (cpu >= nr_cpus) {
+               /* Kernel reports event on CPU we don't see, corrupt data? */
+               trace->invalid_events++;
+               return 0;
+       }
+
        trace->processed_events++;
 
        if (!event->handler)
@@ -236,6 +242,7 @@ int trace_instance_init(struct trace_instance *trace, char 
*tool_name)
                                     trace);
 
        trace->processed_events = 0;
+       trace->invalid_events = 0;
 
        return 0;
 
diff --git a/tools/tracing/rtla/src/trace.h b/tools/tracing/rtla/src/trace.h
index 95b911a2228b2..715a3616fe45a 100644
--- a/tools/tracing/rtla/src/trace.h
+++ b/tools/tracing/rtla/src/trace.h
@@ -18,6 +18,7 @@ struct trace_instance {
        struct tep_handle               *tep;
        struct trace_seq                *seq;
        unsigned long long              missed_events;
+       unsigned long long              invalid_events;
        unsigned long long              processed_events;
 };
 
diff --git a/tools/tracing/rtla/src/utils.h b/tools/tracing/rtla/src/utils.h
index c26ba8827947a..2579e7fa08be6 100644
--- a/tools/tracing/rtla/src/utils.h
+++ b/tools/tracing/rtla/src/utils.h
@@ -40,6 +40,8 @@ static inline bool str_has_prefix(const char *str, const char 
*prefix)
 }
 
 extern bool config_debug;
+extern int nr_cpus;
+
 void debug_msg(const char *fmt, ...);
 void err_msg(const char *fmt, ...);
 void fatal(const char *fmt, ...);
-- 
2.55.0


Reply via email to