Skip to contentSkip to conversation

tracing: kprobes: Prohibit probing on notrace functions

PATCH Superseded Masami Hiramatsu 1 participant 5 messages Jul 28, 2018 – Jul 30, 2018

Subsystems (2)

v4 of 5 Superseded Latest is v5 →

lore
Share & tools
lore

Masami Hiramatsu

author maintainer
#0 lore raw

v4 cover tracing: kprobes: Prohibit probing on notrace functions

Hi,

This is the 4th version of the series to prohibit kprobe on notrace functions which Francis sent before.

This version fixes a build error when CONFIG_FUNCTION_TRACER=n, since in that case notrace is just ignored and ftrace_location_range() is not defined.

Thank you,

---

Francis Deslauriers (1):
selftest/ftrace: Move kprobe selftest function to separate compile unit

Masami Hiramatsu (2):
tracing: kprobes: Prohibit probing on notrace function selftests/ftrace: Fix kprobe string testcase to not probe notrace function

 kernel/trace/Kconfig                               |   18 ++++++
 kernel/trace/Makefile                              |    5 ++
 kernel/trace/trace_kprobe.c                        |   59 +++++++++++++-------
 kernel/trace/trace_kprobe_selftest.c               |   10 +++
 kernel/trace/trace_kprobe_selftest.h               |    7 ++
 .../ftrace/test.d/kprobe/kprobe_args_string.tc     |   30 ++++------
 .../selftests/ftrace/test.d/kprobe/probepoint.tc   |    2 -
 7 files changed, 92 insertions(+), 39 deletions(-)
 create mode 100644 kernel/trace/trace_kprobe_selftest.c
 create mode 100644 kernel/trace/trace_kprobe_selftest.h

--
Masami Hiramatsu (Linaro) <[email protected]>

author maintainer
#1 lore raw

PATCH v4 1/3 tracing: kprobes: Prohibit probing on notrace function

Prohibit kprobe-events probing on notrace function. Since probing on the notrace function can cause recursive event call. In most case those are just skipped, but in some case it falls into infinit recursive call.

This protection can be disabled by the kconfig CONFIG_KPROBE_EVENTS_ON_NOTRACE=y, but it is highly recommended to keep it "n" for normal kernel.

---
Changes in v2
- Add CONFIG_KPROBE_EVENTS_ON_NOTRACE kconfig for knocking down the protection.
Changes in v3
- Fix to check raw-address (no symbol) probe point correctly.
Changes in v4
- No notrace check if CONFIG_FUNCTION_TRACER=n. In that case notrace is ignored.

---
 kernel/trace/Kconfig        |   18 ++++++++++++++++
 kernel/trace/trace_kprobe.c |   47 +++++++++++++++++++++++++++++++++++--------
 2 files changed, 56 insertions(+), 9 deletions(-)
kernel/trace/Kconfig +18 -0
index dcc0166d1997..24d5a58467a3 100644
@@ -456,6 +456,24 @@ config KPROBE_EVENTS
 	  This option is also required by perf-probe subcommand of perf tools.
 	  If you want to use perf tools, this option is strongly recommended.
 
+config KPROBE_EVENTS_ON_NOTRACE
+	bool "Do NOT protect notrace function from kprobe events"
+	depends on KPROBE_EVENTS
+	default n
+	help
+	  This is only for the developers who want to debug ftrace itself
+	  using kprobe events.
+
+	  Usually, ftrace related functions are protected from kprobe-events
+	  to prevent an infinit recursion or any unexpected execution path
+	  which leads to a kernel crash.
+
+	  This option disables such protection and allows you to put kprobe
+	  events on ftrace functions for debugging ftrace by itself.
+	  Note that this might let you shoot yourself in the foot.
+
+	  If unsure, say N.
+
 config UPROBE_EVENTS
 	bool "Enable uprobes-based dynamic events"
 	depends on ARCH_SUPPORTS_UPROBES
kernel/trace/trace_kprobe.c +38 -9

72 lines not on this page · raw message

author maintainer
#2 lore raw

Re: [PATCH v4 1/3] tracing: kprobes: Prohibit probing on notrace function

Quoted 11 lines · On Sat, 28 Jul 2018 22:55:27 +0900 Masami Hiramatsu <[email protected]> wrote:

Prohibit kprobe-events probing on notrace function. Since probing on the notrace function can cause recursive event call. In most case those are just skipped, but in some case it falls into infinit recursive call.

This protection can be disabled by the kconfig CONFIG_KPROBE_EVENTS_ON_NOTRACE=y, but it is highly recommended to keep it "n" for normal kernel.

Quoted 9 lines

---
Changes in v2
- Add CONFIG_KPROBE_EVENTS_ON_NOTRACE kconfig for knocking down the protection.
Changes in v3
- Fix to check raw-address (no symbol) probe point correctly.
Changes in v4
- No notrace check if CONFIG_FUNCTION_TRACER=n. In that case notrace is ignored.

Oops, this must be DYNAMIC_FTRACE, not FUNCTION_TRACER, since ftrace_location_range() is provided only if CONFIG_DYNAMIC_FTACE=y. (And CONFIG_DYNAMIC_FTRACE depends on FUNCTION_TRACER)

Thanks,

Quoted 115 lines
---
 kernel/trace/Kconfig        |   18 ++++++++++++++++
 kernel/trace/trace_kprobe.c |   47 +++++++++++++++++++++++++++++++++++--------
 2 files changed, 56 insertions(+), 9 deletions(-)
kernel/trace/Kconfig +18 -0
index dcc0166d1997..24d5a58467a3 100644
@@ -456,6 +456,24 @@ config KPROBE_EVENTS
 	  This option is also required by perf-probe subcommand of perf tools.
 	  If you want to use perf tools, this option is strongly recommended.
 
+config KPROBE_EVENTS_ON_NOTRACE
+	bool "Do NOT protect notrace function from kprobe events"
+	depends on KPROBE_EVENTS
+	default n
+	help
+	  This is only for the developers who want to debug ftrace itself
+	  using kprobe events.
+
+	  Usually, ftrace related functions are protected from kprobe-events
+	  to prevent an infinit recursion or any unexpected execution path
+	  which leads to a kernel crash.
+
+	  This option disables such protection and allows you to put kprobe
+	  events on ftrace functions for debugging ftrace by itself.
+	  Note that this might let you shoot yourself in the foot.
+
+	  If unsure, say N.
+
 config UPROBE_EVENTS
 	bool "Enable uprobes-based dynamic events"
 	depends on ARCH_SUPPORTS_UPROBES
kernel/trace/trace_kprobe.c +38 -9
index b37b92e7dbd4..a6ff37a9b65b 100644
@@ -87,6 +87,21 @@ static nokprobe_inline unsigned long trace_kprobe_nhit(struct trace_kprobe *tk)
 	return nhit;
 }
 
+static nokprobe_inline
+unsigned long trace_kprobe_address(struct trace_kprobe *tk)
+{
+	unsigned long addr;
+
+	if (tk->symbol) {
+		addr = (unsigned long)
+			kallsyms_lookup_name(trace_kprobe_symbol(tk));
+		addr += tk->rp.kp.offset;
+	} else {
+		addr = (unsigned long)tk->rp.kp.addr;
+	}
+	return addr;
+}
+
 bool trace_kprobe_on_func_entry(struct trace_event_call *call)
 {
 	struct trace_kprobe *tk = (struct trace_kprobe *)call->data;
@@ -99,16 +114,8 @@ bool trace_kprobe_on_func_entry(struct trace_event_call *call)
 bool trace_kprobe_error_injectable(struct trace_event_call *call)
 {
 	struct trace_kprobe *tk = (struct trace_kprobe *)call->data;
-	unsigned long addr;
 
-	if (tk->symbol) {
-		addr = (unsigned long)
-			kallsyms_lookup_name(trace_kprobe_symbol(tk));
-		addr += tk->rp.kp.offset;
-	} else {
-		addr = (unsigned long)tk->rp.kp.addr;
-	}
-	return within_error_injection_list(addr);
+	return within_error_injection_list(trace_kprobe_address(tk));
 }
 
 static int register_kprobe_event(struct trace_kprobe *tk);
@@ -487,6 +494,22 @@ disable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file)
 	return ret;
 }
 
+#if defined(CONFIG_KPROBE_EVENTS_ON_NOTRACE) || \
+	!defined(CONFIG_FUNCTION_TRACER)
+#define within_notrace_func(tk)	(false)
+#else
+static bool within_notrace_func(struct trace_kprobe *tk)
+{
+	unsigned long offset, size, addr;
+
+	addr = trace_kprobe_address(tk);
+	if (!kallsyms_lookup_size_offset(addr, &size, &offset))
+		return true;	/* Out of range. */
+
+	return !ftrace_location_range(addr - offset, addr - offset + size);
+}
+#endif
+
 /* Internal register function - just handle k*probes and flags */
 static int __register_trace_kprobe(struct trace_kprobe *tk)
 {
@@ -495,6 +518,12 @@ static int __register_trace_kprobe(struct trace_kprobe *tk)
 	if (trace_probe_is_registered(&tk->tp))
 		return -EINVAL;
 
+	if (within_notrace_func(tk)) {
+		pr_warn("Could not probe notrace function %s\n",
+			trace_kprobe_symbol(tk));
+		return -EINVAL;
+	}
+
 	for (i = 0; i < tk->tp.nr_args; i++)
 		traceprobe_update_arg(&tk->tp.args[i]);
 
Signature · 1 line
Masami Hiramatsu <[email protected]>
author maintainer
#3 lore raw

PATCH v4 2/3 selftest/ftrace: Move kprobe selftest function to separate compile unit

In reply to Masami Hiramatsu

From: Francis Deslauriers <[email protected]>

Move selftest function to its own compile unit so it can be compiled with the ftrace cflags (CC_FLAGS_FTRACE) allowing it to be probed during the ftrace startup tests.

---
 kernel/trace/Makefile                |    5 +++++
 kernel/trace/trace_kprobe.c          |   12 +-----------
 kernel/trace/trace_kprobe_selftest.c |   10 ++++++++++
 kernel/trace/trace_kprobe_selftest.h |    7 +++++++
 4 files changed, 23 insertions(+), 11 deletions(-)
 create mode 100644 kernel/trace/trace_kprobe_selftest.c
 create mode 100644 kernel/trace/trace_kprobe_selftest.h
kernel/trace/Makefile +5 -0
index e2538c7638d4..e38771eccb2f 100644
@@ -13,6 +13,11 @@ obj-y += trace_selftest_dynamic.o
 endif
 endif
 
+ifdef CONFIG_FTRACE_STARTUP_TEST
+CFLAGS_trace_kprobe_selftest.o = $(CC_FLAGS_FTRACE)
+obj-$(CONFIG_KPROBE_EVENTS) += trace_kprobe_selftest.o
+endif
+
 # If unlikely tracing is enabled, do not trace these files
 ifdef CONFIG_TRACING_BRANCHES
 KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
kernel/trace/trace_kprobe.c +1 -11
index a6ff37a9b65b..1cc61796f9c2 100644
@@ -23,6 +23,7 @@
 #include <linux/rculist.h>
 #include <linux/error-injection.h>
 
+#include "trace_kprobe_selftest.h"
 #include "trace_probe.h"
 
 #define KPROBE_EVENT_SYSTEM "kprobes"
@@ -1565,17 +1566,6 @@ fs_initcall(init_kprobe_trace);
 
 
 #ifdef CONFIG_FTRACE_STARTUP_TEST
-/*
- * The "__used" keeps gcc from removing the function symbol
- * from the kallsyms table. 'noinline' makes sure that there
- * isn't an inlined version used by the test method below
- */
-static __used __init noinline int
-kprobe_trace_selftest_target(int a1, int a2, int a3, int a4, int a5, int a6)
-{
-	return a1 + a2 + a3 + a4 + a5 + a6;
-}
-
 static __init struct trace_event_file *
 find_trace_probe_file(struct trace_kprobe *tk, struct trace_array *tr)
 {
kernel/trace/trace_kprobe_selftest.c new file +10 -0
new file mode 100644
index 000000000000..16548ee4c8c6
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Function used during the kprobe self test. This function is in a separate
+ * compile unit so it can be compile with CC_FLAGS_FTRACE to ensure that it
+ * can be probed by the selftests.
+ */
+int kprobe_trace_selftest_target(int a1, int a2, int a3, int a4, int a5, int a6)
+{
+	return a1 + a2 + a3 + a4 + a5 + a6;
+}
kernel/trace/trace_kprobe_selftest.h new file +7 -0
new file mode 100644
index 000000000000..4e10ec41c013
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Function used during the kprobe self test. This function is in a separate
+ * compile unit so it can be compile with CC_FLAGS_FTRACE to ensure that it
+ * can be probed by the selftests.
+ */
+int kprobe_trace_selftest_target(int a1, int a2, int a3, int a4, int a5, int a6);
author maintainer
#4 lore raw

PATCH v4 3/3 selftests/ftrace: Fix kprobe string testcase to not probe notrace function

In reply to Masami Hiramatsu

Fix kprobe string argument testcase to not probe notrace function. Instead, it probes tracefs function which must be available with ftrace.

---
Changes in v3:
- Fix probepoint testcase too.

---
 .../ftrace/test.d/kprobe/kprobe_args_string.tc     |   30 ++++++++------------
 .../selftests/ftrace/test.d/kprobe/probepoint.tc   |    2 +
 2 files changed, 13 insertions(+), 19 deletions(-)
tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc +12 -18
index a0002563e9ee..1ad70cdaf442 100644
@@ -9,28 +9,22 @@ echo > kprobe_events
 
 case `uname -m` in
 x86_64)
-  ARG2=%si
-  OFFS=8
+  ARG1=%di
 ;;
 i[3456]86)
-  ARG2=%cx
-  OFFS=4
+  ARG1=%ax
 ;;
 aarch64)
-  ARG2=%x1
-  OFFS=8
+  ARG1=%x0
 ;;
 arm*)
-  ARG2=%r1
-  OFFS=4
+  ARG1=%r0
 ;;
 ppc64*)
-  ARG2=%r4
-  OFFS=8
+  ARG1=%r3
 ;;
 ppc*)
-  ARG2=%r4
-  OFFS=4
+  ARG1=%r3
 ;;
 *)
   echo "Please implement other architecture here"
@@ -38,17 +32,17 @@ ppc*)
 esac
 
 : "Test get argument (1)"
-echo "p:testprobe create_trace_kprobe arg1=+0(+0(${ARG2})):string" > kprobe_events
+echo "p:testprobe tracefs_create_dir arg1=+0(${ARG1}):string" > kprobe_events
 echo 1 > events/kprobes/testprobe/enable
-! echo test >> kprobe_events
-tail -n 1 trace | grep -qe "testprobe.* arg1=\"test\""
+echo "p:test _do_fork" >> kprobe_events
+grep -qe "testprobe.* arg1=\"test\"" trace
 
 echo 0 > events/kprobes/testprobe/enable
 : "Test get argument (2)"
-echo "p:testprobe create_trace_kprobe arg1=+0(+0(${ARG2})):string arg2=+0(+${OFFS}(${ARG2})):string" > kprobe_events
+echo "p:testprobe tracefs_create_dir arg1=+0(${ARG1}):string arg2=+0(${ARG1}):string" > kprobe_events
 echo 1 > events/kprobes/testprobe/enable
-! echo test1 test2 >> kprobe_events
-tail -n 1 trace | grep -qe "testprobe.* arg1=\"test1\" arg2=\"test2\""
+echo "p:test _do_fork" >> kprobe_events
+grep -qe "testprobe.* arg1=\"test\" arg2=\"test\"" trace
 
 echo 0 > events/enable
 echo > kprobe_events
tools/testing/selftests/ftrace/test.d/kprobe/probepoint.tc +1 -1
index 4fda01a08da4..519d2763f5d2 100644
@@ -4,7 +4,7 @@
 
 [ -f kprobe_events ] || exit_unsupported # this is configurable
 
-TARGET_FUNC=create_trace_kprobe
+TARGET_FUNC=tracefs_create_dir
 
 dec_addr() { # hexaddr
   printf "%d" "0x"`echo $1 | tail -c 8`