lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-Id: <20200610121254.1780-1-yuanjunqing66@163.com>
Date:   Wed, 10 Jun 2020 20:12:54 +0800
From:   YuanJunQing <yuanjunqing66@....com>
To:     tsbogend@...ha.franken.de
Cc:     yszhou4tech@...il.com, linux-mips@...r.kernel.org,
        linux-kernel@...r.kernel.org, liulichao@...ngson.cn,
        YuanJunQing <yuanjunqing66@....com>
Subject: [PATCH] mips/ftrace: Fix stack backtrace in unwind_stack_by_address()

Calling the unwind_stack_by_address() function for stack backtrace
will fail, when we use "echo function: stacktrace > set_ftrace_filter".

The stack backtrace as follows:
           <...>-3102  [001] ...2    63.557737: <stack trace>
 => 0
 => 0
 => 0
 => 0
 => 0
 => 0
 => 0
 => 0
 =>
          <idle>-0     [000] .N.2    63.558793: <stack trace>

The reason is that when performing stack backtrace, the "ftrace_call"
and "ftrace_graph_call" global symbols in ftrace_caller() are
treated as functions.

If CONFIG_FUNCTION_GRAPH_TRACER is defined, the value in the "ra"
register is the address of ftrace_graph_call when the stack
backtrace back to ftrace_caller(). ”ftrace_graph_call“ is a global
symbol, and the value of "ofs" is set to zero when the
kallsyms_lookup_size_offset() is called. Otherwise, the value
in the "ra" register is the address of ftrace_call+8. "ftrace_call"
is the global symbol, and return one when the get_frame_info() is called.

Signed-off-by: YuanJunQing <yuanjunqing66@....com>
---
 arch/mips/kernel/process.c | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index b2a797557825..ac4fe79bc5bc 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -53,6 +53,8 @@
 #include <asm/inst.h>
 #include <asm/stacktrace.h>
 #include <asm/irq_regs.h>
+#include <linux/ftrace.h>
+#include <generated/asm-offsets.h>
 
 #ifdef CONFIG_HOTPLUG_CPU
 void arch_cpu_idle_dead(void)
@@ -569,6 +571,13 @@ unsigned long notrace unwind_stack_by_address(unsigned long stack_page,
 	 * Return ra if an exception occurred at the first instruction
 	 */
 	if (unlikely(ofs == 0)) {
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+		extern void ftrace_graph_call(void);
+		if ((pc == (unsigned long)ftrace_graph_call)) {
+			pc = ((unsigned long *)(*sp))[PT_R31/sizeof(long)];
+			*sp += PT_SIZE;
+		} else
+#endif
 		pc = *ra;
 		*ra = 0;
 		return pc;
@@ -583,16 +592,23 @@ unsigned long notrace unwind_stack_by_address(unsigned long stack_page,
 	if (*sp < low || *sp + info.frame_size > high)
 		return 0;
 
-	if (leaf)
+	if (leaf) {
 		/*
 		 * For some extreme cases, get_frame_info() can
 		 * consider wrongly a nested function as a leaf
 		 * one. In that cases avoid to return always the
 		 * same value.
 		 */
+#ifdef CONFIG_DYNAMIC_FTRACE
+		if (info.func == (void *)ftrace_call) {
+			pc = ((unsigned long *)(*sp))[PT_R31/sizeof(long)];
+			info.frame_size = PT_SIZE;
+		} else
+#endif
 		pc = pc != *ra ? *ra : 0;
-	else
+	} else {
 		pc = ((unsigned long *)(*sp))[info.pc_offset];
+	}
 
 	*sp += info.frame_size;
 	*ra = 0;
-- 
2.17.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ