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>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Fri,  5 May 2017 14:21:59 +0200
From:   Jiri Slaby <jslaby@...e.cz>
To:     akpm@...ux-foundation.org
Cc:     torvalds@...ux-foundation.org, live-patching@...r.kernel.org,
        linux-kernel@...r.kernel.org, Jiri Slaby <jslaby@...e.cz>,
        Thomas Gleixner <tglx@...utronix.de>,
        Ingo Molnar <mingo@...hat.com>,
        "H. Peter Anvin" <hpa@...or.com>, x86@...nel.org,
        Josh Poimboeuf <jpoimboe@...hat.com>
Subject: [PATCH 6/7] unwinder: plug in the DWARF unwinder

The DWARF unwinder is ready to use, so plug it into the generic
unwinding code.

Signed-off-by: Jiri Slaby <jslaby@...e.cz>
Cc: Thomas Gleixner <tglx@...utronix.de>
Cc: Ingo Molnar <mingo@...hat.com>
Cc: "H. Peter Anvin" <hpa@...or.com>
Cc: x86@...nel.org
Cc: Josh Poimboeuf <jpoimboe@...hat.com>
---
 arch/x86/include/asm/unwind.h  | 36 +++++++++++++++-
 arch/x86/kernel/Makefile       |  4 ++
 arch/x86/kernel/unwind_dwarf.c | 95 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 133 insertions(+), 2 deletions(-)
 create mode 100644 arch/x86/kernel/unwind_dwarf.c

diff --git a/arch/x86/include/asm/unwind.h b/arch/x86/include/asm/unwind.h
index e6676495b125..4c792ad0d9f9 100644
--- a/arch/x86/include/asm/unwind.h
+++ b/arch/x86/include/asm/unwind.h
@@ -12,7 +12,14 @@ struct unwind_state {
 	struct task_struct *task;
 	int graph_idx;
 	bool error;
-#ifdef CONFIG_FRAME_POINTER
+#ifdef CONFIG_DWARF_UNWIND
+	union {
+		struct pt_regs regs;
+		char regs_arr[sizeof(struct pt_regs)];
+	} u;
+	unsigned long dw_sp;
+	unsigned call_frame:1;
+#elif defined(CONFIG_FRAME_POINTER)
 	bool got_irq;
 	unsigned long *bp, *orig_sp;
 	struct pt_regs *regs;
@@ -48,7 +55,32 @@ static inline bool unwind_error(struct unwind_state *state)
 	return state->error;
 }
 
-#ifdef CONFIG_FRAME_POINTER
+#ifdef CONFIG_DWARF_UNWIND
+
+#include <asm/dwarf.h>
+
+static inline
+unsigned long *unwind_get_return_address_ptr(struct unwind_state *state)
+{
+	if (unwind_done(state))
+		return NULL;
+
+	return &DW_PC(state);
+}
+
+static inline struct pt_regs *unwind_get_entry_regs(struct unwind_state *state)
+{
+	if (unwind_done(state))
+		return NULL;
+
+	/*
+	 * Should we return something? If we return the registers here, they
+	 * are output for every frame.
+	 */
+	return NULL;
+}
+
+#elif defined(CONFIG_FRAME_POINTER)
 
 static inline
 unsigned long *unwind_get_return_address_ptr(struct unwind_state *state)
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 4b994232cb57..604cbcbba9a5 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -124,11 +124,15 @@ obj-$(CONFIG_PERF_EVENTS)		+= perf_regs.o
 obj-$(CONFIG_TRACING)			+= tracepoint.o
 obj-$(CONFIG_SCHED_MC_PRIO)		+= itmt.o
 
+ifdef CONFIG_DWARF_UNWIND
+obj-y					+= unwind_dwarf.o
+else
 ifdef CONFIG_FRAME_POINTER
 obj-y					+= unwind_frame.o
 else
 obj-y					+= unwind_guess.o
 endif
+endif
 
 ###
 # 64 bit specific files
diff --git a/arch/x86/kernel/unwind_dwarf.c b/arch/x86/kernel/unwind_dwarf.c
new file mode 100644
index 000000000000..bbcca970aca8
--- /dev/null
+++ b/arch/x86/kernel/unwind_dwarf.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2016-2017 SUSE
+ *      Jiri Slaby <jirislaby@...nel.org>
+ * This code is released under the GPL v2.
+ */
+
+#include <linux/dwarf.h>
+
+unsigned long unwind_get_return_address(struct unwind_state *state)
+{
+	unsigned long *addr = unwind_get_return_address_ptr(state);
+
+	if (unwind_done(state))
+		return 0;
+
+	return ftrace_graph_ret_addr(state->task, &state->graph_idx, *addr,
+			addr);
+}
+EXPORT_SYMBOL_GPL(unwind_get_return_address);
+
+bool unwind_next_frame(struct unwind_state *state)
+{
+	if (unwind_done(state))
+		goto bad;
+
+	if (arch_dwarf_user_mode(state))
+		goto bad;
+
+	if ((state->dw_sp & PAGE_MASK) == (DW_SP(state) & PAGE_MASK) &&
+			state->dw_sp > DW_SP(state))
+		goto bad;
+
+	if (dwarf_unwind(state) || !DW_PC(state))
+		goto bad;
+
+	state->dw_sp = DW_SP(state);
+
+	return true;
+bad:
+	state->stack_info.type = STACK_TYPE_UNKNOWN;
+	return false;
+}
+EXPORT_SYMBOL_GPL(unwind_next_frame);
+
+void __unwind_start(struct unwind_state *state, struct task_struct *task,
+		struct pt_regs *regs, unsigned long *first_frame)
+{
+	bool do_skipping = true;
+	char type;
+
+	memset(state, 0, sizeof(*state));
+	state->task = task;
+
+	if (regs) {
+		arch_dwarf_init_frame_info(state, regs);
+		type = 'R';
+	} else if (task == current) {
+		arch_dwarf_init_running(&state->u.regs);
+		type = 'C';
+#ifdef CONFIG_SMP
+	} else if (task->on_cpu) {
+		return;
+#endif
+	} else {
+		arch_dwarf_init_blocked(state);
+		type = 'B';
+		do_skipping = false;
+	}
+
+	pr_debug("%s: %c FF=%p rip=%lx (%pS) rsp=%lx rbp=%lx\n",
+			__func__, type, first_frame, DW_PC(state),
+			(void *)DW_PC(state), DW_SP(state), DW_FP(state));
+
+	get_stack_info((void *)DW_SP(state), task, &state->stack_info,
+			&state->stack_mask);
+
+	state->dw_sp = DW_SP(state);
+
+	if (arch_dwarf_user_mode(state))
+		return;
+
+	while (do_skipping) {
+		if (DW_SP(state) > (unsigned long)first_frame) {
+			pr_debug("%s: hit first=%p sp=%lx\n", __func__,
+					first_frame, DW_SP(state));
+			break;
+		}
+		if (!unwind_next_frame(state))
+			break;
+		pr_debug("%s: skipped to %pS rsp=%lx rbp=%lx\n", __func__,
+				(void *)DW_PC(state), DW_SP(state),
+				DW_FP(state));
+	}
+}
+EXPORT_SYMBOL_GPL(__unwind_start);
-- 
2.12.2

Powered by blists - more mailing lists