2021-01-15 13:06:18

by Alexander Potapenko

[permalink] [raw]
Subject: [PATCH v2 0/5] Add sysfs interface to collect reports from debugging tools

This patchset adds a library that captures error reports from debugging
tools like KASAN or KFENCE and exposes those reports to userspace via
sysfs. Report capturing is controlled by two new types of tracepoints:
error_report_start and error_report_end, that must be added to the tools
that want to use this new feature.

v2:
- added ABI documentation for /sys/kernel/error_report/
- changed error_report_start and error_report end tracepoints to take
a fixed set of values for the error detector

Alexander Potapenko (5):
tracing: add error_report trace points
lib: add error_report_notify to collect debugging tools' reports
docs: ABI: add /sys/kernel/error_report/ documentation
kfence: use error_report_start and error_report_end tracepoints
kasan: use error_report_start and error_report_end tracepoints

.../ABI/testing/sysfs-kernel-error_report | 41 +++
include/trace/events/error_report.h | 84 ++++++
kernel/trace/Makefile | 1 +
kernel/trace/error_report-traces.c | 11 +
lib/Kconfig.debug | 14 +
lib/Makefile | 2 +
lib/error_report_notify.c | 278 ++++++++++++++++++
mm/kasan/report.c | 15 +-
mm/kfence/report.c | 3 +
9 files changed, 443 insertions(+), 6 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-kernel-error_report
create mode 100644 include/trace/events/error_report.h
create mode 100644 kernel/trace/error_report-traces.c
create mode 100644 lib/error_report_notify.c

--
2.30.0.284.gd98b1dd5eaa7-goog


2021-01-15 13:06:34

by Alexander Potapenko

[permalink] [raw]
Subject: [PATCH v2 5/5] kasan: use error_report_start and error_report_end tracepoints

Make it possible to trace KASAN error reporting (in particular, for
compatibility with CONFIG_ERROR_REPORT_NOTIFY).

Suggested-by: Marco Elver <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Andrey Konovalov <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Marco Elver <[email protected]>
Cc: Petr Mladek <[email protected]>
Cc: Steven Rostedt <[email protected]>
Cc: Sergey Senozhatsky <[email protected]>
Cc: [email protected]
Signed-off-by: Alexander Potapenko <[email protected]>

---
v2:
- change error_report_start and error_report_end prototypes
to accept enum error_detector instead of char*
(as suggested by Steven Rostedt)
---
mm/kasan/report.c | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/mm/kasan/report.c b/mm/kasan/report.c
index c0fb21797550..78b8bbc84dc2 100644
--- a/mm/kasan/report.c
+++ b/mm/kasan/report.c
@@ -25,6 +25,7 @@
#include <linux/module.h>
#include <linux/sched/task_stack.h>
#include <linux/uaccess.h>
+#include <trace/events/error_report.h>

#include <asm/sections.h>

@@ -74,7 +75,7 @@ static void print_error_description(struct kasan_access_info *info)

static DEFINE_SPINLOCK(report_lock);

-static void start_report(unsigned long *flags)
+static void start_report(unsigned long *flags, unsigned long addr)
{
/*
* Make sure we don't end up in loop.
@@ -82,10 +83,12 @@ static void start_report(unsigned long *flags)
kasan_disable_current();
spin_lock_irqsave(&report_lock, *flags);
pr_err("==================================================================\n");
+ trace_error_report_start(ERROR_DETECTOR_KASAN, addr);
}

-static void end_report(unsigned long *flags)
+static void end_report(unsigned long *flags, unsigned long addr)
{
+ trace_error_report_end(ERROR_DETECTOR_KASAN, addr);
pr_err("==================================================================\n");
add_taint(TAINT_BAD_PAGE, LOCKDEP_NOW_UNRELIABLE);
spin_unlock_irqrestore(&report_lock, *flags);
@@ -348,14 +351,14 @@ void kasan_report_invalid_free(void *object, unsigned long ip)
kasan_update_kunit_status(current->kunit_test);
#endif /* IS_ENABLED(CONFIG_KUNIT) */

- start_report(&flags);
+ start_report(&flags, (unsigned long)object);
pr_err("BUG: KASAN: double-free or invalid-free in %pS\n", (void *)ip);
print_tags(tag, object);
pr_err("\n");
print_address_description(object, tag);
pr_err("\n");
print_memory_metadata(object);
- end_report(&flags);
+ end_report(&flags, (unsigned long)object);
}

static void __kasan_report(unsigned long addr, size_t size, bool is_write,
@@ -385,7 +388,7 @@ static void __kasan_report(unsigned long addr, size_t size, bool is_write,
info.is_write = is_write;
info.ip = ip;

- start_report(&flags);
+ start_report(&flags, addr);

print_error_description(&info);
if (addr_has_metadata(untagged_addr))
@@ -400,7 +403,7 @@ static void __kasan_report(unsigned long addr, size_t size, bool is_write,
dump_stack();
}

- end_report(&flags);
+ end_report(&flags, addr);
}

bool kasan_report(unsigned long addr, size_t size, bool is_write,
--
2.30.0.284.gd98b1dd5eaa7-goog

2021-01-15 13:06:43

by Alexander Potapenko

[permalink] [raw]
Subject: [PATCH v2 4/5] kfence: use error_report_start and error_report_end tracepoints

Make it possible to trace KFENCE error reporting (in particular, for
compatibility with CONFIG_ERROR_REPORT_NOTIFY).

Suggested-by: Marco Elver <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Andrey Konovalov <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Marco Elver <[email protected]>
Cc: Petr Mladek <[email protected]>
Cc: Steven Rostedt <[email protected]>
Cc: Sergey Senozhatsky <[email protected]>
Cc: [email protected]
Signed-off-by: Alexander Potapenko <[email protected]>

---
v2:
- change error_report_start and error_report_end prototypes
to accept enum error_detector instead of char*
(as suggested by Steven Rostedt)
---
mm/kfence/report.c | 3 +++
1 file changed, 3 insertions(+)

diff --git a/mm/kfence/report.c b/mm/kfence/report.c
index 4dedc2ff8f28..bbe7dad5f249 100644
--- a/mm/kfence/report.c
+++ b/mm/kfence/report.c
@@ -9,6 +9,7 @@
#include <linux/seq_file.h>
#include <linux/stacktrace.h>
#include <linux/string.h>
+#include <trace/events/error_report.h>

#include <asm/kfence.h>

@@ -184,6 +185,7 @@ void kfence_report_error(unsigned long address, struct pt_regs *regs,
lockdep_off();

pr_err("==================================================================\n");
+ trace_error_report_start(ERROR_DETECTOR_KFENCE, address);
/* Print report header. */
switch (type) {
case KFENCE_ERROR_OOB: {
@@ -232,6 +234,7 @@ void kfence_report_error(unsigned long address, struct pt_regs *regs,
show_regs(regs);
else
dump_stack_print_info(KERN_ERR);
+ trace_error_report_end(ERROR_DETECTOR_KFENCE, address);
pr_err("==================================================================\n");

lockdep_on();
--
2.30.0.284.gd98b1dd5eaa7-goog

2021-01-15 13:06:46

by Alexander Potapenko

[permalink] [raw]
Subject: [PATCH v2 1/5] tracing: add error_report trace points

Introduce error_report_start and error_report_end tracepoints.
Those can be used in debugging tools like KASAN, KFENCE, etc.
to provide extensions to the error reporting mechanisms (e.g. allow
tests hook into error reporting, ease error report collection from
production kernels).
Another benefit would be making use of ftrace for debugging or
benchmarking the tools themselves.

Suggested-by: Marco Elver <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Andrey Konovalov <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Marco Elver <[email protected]>
Cc: Petr Mladek <[email protected]>
Cc: Steven Rostedt <[email protected]>
Cc: Sergey Senozhatsky <[email protected]>
Cc: [email protected]
Signed-off-by: Alexander Potapenko <[email protected]>

---
v2: - change error_report_start and error_report_end prototypes
to accept enum error_detector instead of char*
(as suggested by Steven Rostedt)
---
include/trace/events/error_report.h | 84 +++++++++++++++++++++++++++++
kernel/trace/Makefile | 1 +
kernel/trace/error_report-traces.c | 11 ++++
3 files changed, 96 insertions(+)
create mode 100644 include/trace/events/error_report.h
create mode 100644 kernel/trace/error_report-traces.c

diff --git a/include/trace/events/error_report.h b/include/trace/events/error_report.h
new file mode 100644
index 000000000000..bbf8543fc31a
--- /dev/null
+++ b/include/trace/events/error_report.h
@@ -0,0 +1,84 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM error_report
+
+#if !defined(_TRACE_ERROR_REPORT_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_ERROR_REPORT_H
+
+#include <linux/tracepoint.h>
+
+#ifndef __ERROR_REPORT_DECLARE_TRACE_ENUMS_ONCE_ONLY
+#define __ERROR_REPORT_DECLARE_TRACE_ENUMS_ONCE_ONLY
+
+enum error_detector {
+ ERROR_DETECTOR_KFENCE,
+ ERROR_DETECTOR_KASAN
+};
+
+#endif /* __ERROR_REPORT_DECLARE_TRACE_ENUMS_ONCE_ONLY */
+
+#define error_detector_list \
+ EM(ERROR_DETECTOR_KFENCE, "kfence") \
+ EMe(ERROR_DETECTOR_KASAN, "kasan")
+/* Always end the list with an EMe. */
+
+#undef EM
+#undef EMe
+
+#define EM(a, b) TRACE_DEFINE_ENUM(a);
+#define EMe(a, b) TRACE_DEFINE_ENUM(a);
+
+error_detector_list
+
+#undef EM
+#undef EMe
+
+#define EM(a, b) { a, b },
+#define EMe(a, b) { a, b }
+
+#define show_error_detector_list(val) \
+ __print_symbolic(val, error_detector_list)
+
+DECLARE_EVENT_CLASS(error_report_template,
+ TP_PROTO(enum error_detector error_detector, unsigned long id),
+ TP_ARGS(error_detector, id),
+ TP_STRUCT__entry(__field(enum error_detector, error_detector)
+ __field(unsigned long, id)),
+ TP_fast_assign(__entry->error_detector = error_detector;
+ __entry->id = id;),
+ TP_printk("[%s] %lx",
+ show_error_detector_list(__entry->error_detector),
+ __entry->id));
+
+/**
+ * error_report_start - called before printing the error report
+ * @error_detector: short string describing the error detection tool
+ * @id: pseudo-unique descriptor that can help distinguish reports
+ * from one another. Depending on the tool, good examples
+ * could be: memory access address, call site, allocation
+ * site, etc.
+ *
+ * This event occurs right before a debugging tool starts printing the error
+ * report.
+ */
+DEFINE_EVENT(error_report_template, error_report_start,
+ TP_PROTO(enum error_detector error_detector, unsigned long id),
+ TP_ARGS(error_detector, id));
+
+/**
+ * error_report_end - called after printing the error report
+ * @error_detector: short string describing the error detection tool
+ * @id: pseudo-unique descriptor, matches that passed to
+ * error_report_start
+ *
+ * This event occurs right after a debugging tool finishes printing the error
+ * report.
+ */
+DEFINE_EVENT(error_report_template, error_report_end,
+ TP_PROTO(enum error_detector error_detector, unsigned long id),
+ TP_ARGS(error_detector, id));
+
+#endif /* _TRACE_ERROR_REPORT_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
index 7e44cea89fdc..b28d3e5013cd 100644
--- a/kernel/trace/Makefile
+++ b/kernel/trace/Makefile
@@ -81,6 +81,7 @@ obj-$(CONFIG_SYNTH_EVENTS) += trace_events_synth.o
obj-$(CONFIG_HIST_TRIGGERS) += trace_events_hist.o
obj-$(CONFIG_BPF_EVENTS) += bpf_trace.o
obj-$(CONFIG_KPROBE_EVENTS) += trace_kprobe.o
+obj-$(CONFIG_TRACEPOINTS) += error_report-traces.o
obj-$(CONFIG_TRACEPOINTS) += power-traces.o
ifeq ($(CONFIG_PM),y)
obj-$(CONFIG_TRACEPOINTS) += rpm-traces.o
diff --git a/kernel/trace/error_report-traces.c b/kernel/trace/error_report-traces.c
new file mode 100644
index 000000000000..80960c52c705
--- /dev/null
+++ b/kernel/trace/error_report-traces.c
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Error reporting trace points
+ */
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/error_report.h>
+
+EXPORT_TRACEPOINT_SYMBOL_GPL(error_report_start);
+EXPORT_TRACEPOINT_SYMBOL_GPL(error_report_end);
+
--
2.30.0.284.gd98b1dd5eaa7-goog

2021-01-15 13:08:29

by Vlastimil Babka

[permalink] [raw]
Subject: Re: [PATCH v2 0/5] Add sysfs interface to collect reports from debugging tools

Should have CCd linux-api@, please do next time

On 1/15/21 2:03 PM, Alexander Potapenko wrote:
> This patchset adds a library that captures error reports from debugging
> tools like KASAN or KFENCE and exposes those reports to userspace via
> sysfs. Report capturing is controlled by two new types of tracepoints:
> error_report_start and error_report_end, that must be added to the tools
> that want to use this new feature.
>
> v2:
> - added ABI documentation for /sys/kernel/error_report/
> - changed error_report_start and error_report end tracepoints to take
> a fixed set of values for the error detector
>
> Alexander Potapenko (5):
> tracing: add error_report trace points
> lib: add error_report_notify to collect debugging tools' reports
> docs: ABI: add /sys/kernel/error_report/ documentation
> kfence: use error_report_start and error_report_end tracepoints
> kasan: use error_report_start and error_report_end tracepoints
>
> .../ABI/testing/sysfs-kernel-error_report | 41 +++
> include/trace/events/error_report.h | 84 ++++++
> kernel/trace/Makefile | 1 +
> kernel/trace/error_report-traces.c | 11 +
> lib/Kconfig.debug | 14 +
> lib/Makefile | 2 +
> lib/error_report_notify.c | 278 ++++++++++++++++++
> mm/kasan/report.c | 15 +-
> mm/kfence/report.c | 3 +
> 9 files changed, 443 insertions(+), 6 deletions(-)
> create mode 100644 Documentation/ABI/testing/sysfs-kernel-error_report
> create mode 100644 include/trace/events/error_report.h
> create mode 100644 kernel/trace/error_report-traces.c
> create mode 100644 lib/error_report_notify.c
>

2021-01-15 13:11:23

by Alexander Potapenko

[permalink] [raw]
Subject: Re: [PATCH v2 0/5] Add sysfs interface to collect reports from debugging tools

On Fri, Jan 15, 2021 at 2:06 PM Vlastimil Babka <[email protected]> wrote:
>
> Should have CCd linux-api@, please do next time
Thanks, will do!
Shall I also CC the v2 ABI patch explicitly?

2021-01-21 12:59:09

by Alexander Potapenko

[permalink] [raw]
Subject: Re: [PATCH v2 0/5] Add sysfs interface to collect reports from debugging tools

On Fri, Jan 15, 2021 at 2:09 PM Alexander Potapenko <[email protected]> wrote:
>
> On Fri, Jan 15, 2021 at 2:06 PM Vlastimil Babka <[email protected]> wrote:
> >
> > Should have CCd linux-api@, please do next time
> Thanks, will do!
> Shall I also CC the v2 ABI patch explicitly?

I'll be dropping the sysfs changes from this patchset, but assume it
still makes sense to CC linux-api@ since v3 will be introducing
tracepoints.