From: Josh Poimboeuf <jpoimboe@redhat.com>
To: Jessica Yu <jeyu@redhat.com>, Jiri Kosina <jikos@kernel.org>,
Miroslav Benes <mbenes@suse.cz>, Petr Mladek <pmladek@suse.com>
Cc: linux-kernel@vger.kernel.org, live-patching@vger.kernel.org,
Michael Ellerman <mpe@ellerman.id.au>,
Heiko Carstens <heiko.carstens@de.ibm.com>,
x86@kernel.org, linuxppc-dev@lists.ozlabs.org,
linux-s390@vger.kernel.org, Vojtech Pavlik <vojtech@suse.com>,
Jiri Slaby <jslaby@suse.cz>,
Chris J Arges <chris.j.arges@canonical.com>,
Andy Lutomirski <luto@kernel.org>, Ingo Molnar <mingo@kernel.org>,
Peter Zijlstra <peterz@infradead.org>
Subject: [PATCH v3 01/15] stacktrace/x86: add function for detecting reliable stack traces
Date: Thu, 8 Dec 2016 12:08:26 -0600 [thread overview]
Message-ID: <0315b36c08c104d56a4b43537fb300d200418996.1481220077.git.jpoimboe@redhat.com> (raw)
In-Reply-To: <cover.1481220077.git.jpoimboe@redhat.com>
For live patching and possibly other use cases, a stack trace is only
useful if it can be assured that it's completely reliable. Add a new
save_stack_trace_tsk_reliable() function to achieve that.
Scenarios which indicate that a stack trace may be unreliable:
- running task
- interrupt stack
- preemption
- corrupted stack data
- stack grows the wrong way
- stack walk doesn't reach the bottom
- user didn't provide a large enough entries array
Also add CONFIG_HAVE_RELIABLE_STACKTRACE so arch-independent code can
determine at build time whether the function is implemented.
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
---
arch/Kconfig | 6 +++++
arch/x86/Kconfig | 1 +
arch/x86/include/asm/unwind.h | 6 +++++
arch/x86/kernel/stacktrace.c | 59 +++++++++++++++++++++++++++++++++++++++++-
arch/x86/kernel/unwind_frame.c | 1 +
include/linux/stacktrace.h | 8 +++---
kernel/stacktrace.c | 12 +++++++--
7 files changed, 87 insertions(+), 6 deletions(-)
diff --git a/arch/Kconfig b/arch/Kconfig
index 13f27c1..d61a133 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -678,6 +678,12 @@ config HAVE_STACK_VALIDATION
Architecture supports the 'objtool check' host tool command, which
performs compile-time stack metadata validation.
+config HAVE_RELIABLE_STACKTRACE
+ bool
+ help
+ Architecture has a save_stack_trace_tsk_reliable() function which
+ only returns a stack trace if it can guarantee the trace is reliable.
+
config HAVE_ARCH_HASH
bool
default n
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 215612c..b4a6663 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -155,6 +155,7 @@ config X86
select HAVE_PERF_REGS
select HAVE_PERF_USER_STACK_DUMP
select HAVE_REGS_AND_STACK_ACCESS_API
+ select HAVE_RELIABLE_STACKTRACE if X86_64 && FRAME_POINTER && STACK_VALIDATION
select HAVE_STACK_VALIDATION if X86_64
select HAVE_SYSCALL_TRACEPOINTS
select HAVE_UNSTABLE_SCHED_CLOCK
diff --git a/arch/x86/include/asm/unwind.h b/arch/x86/include/asm/unwind.h
index c5a7f3a..44f86dc 100644
--- a/arch/x86/include/asm/unwind.h
+++ b/arch/x86/include/asm/unwind.h
@@ -11,6 +11,7 @@ struct unwind_state {
unsigned long stack_mask;
struct task_struct *task;
int graph_idx;
+ bool error;
#ifdef CONFIG_FRAME_POINTER
unsigned long *bp;
struct pt_regs *regs;
@@ -40,6 +41,11 @@ void unwind_start(struct unwind_state *state, struct task_struct *task,
__unwind_start(state, task, regs, first_frame);
}
+static inline bool unwind_error(struct unwind_state *state)
+{
+ return state->error;
+}
+
#ifdef CONFIG_FRAME_POINTER
static inline
diff --git a/arch/x86/kernel/stacktrace.c b/arch/x86/kernel/stacktrace.c
index 0653788..3e0cf5e 100644
--- a/arch/x86/kernel/stacktrace.c
+++ b/arch/x86/kernel/stacktrace.c
@@ -74,6 +74,64 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
}
EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
+#ifdef CONFIG_HAVE_RELIABLE_STACKTRACE
+static int __save_stack_trace_reliable(struct stack_trace *trace,
+ struct task_struct *task)
+{
+ struct unwind_state state;
+ struct pt_regs *regs;
+ unsigned long addr;
+
+ for (unwind_start(&state, task, NULL, NULL); !unwind_done(&state);
+ unwind_next_frame(&state)) {
+
+ regs = unwind_get_entry_regs(&state);
+ if (regs) {
+ /*
+ * Preemption and page faults on the stack can make
+ * frame pointers unreliable.
+ */
+ if (!user_mode(regs))
+ return -1;
+
+ /*
+ * This frame contains the (user mode) pt_regs at the
+ * end of the stack. Finish the unwind.
+ */
+ unwind_next_frame(&state);
+ break;
+ }
+
+ addr = unwind_get_return_address(&state);
+ if (!addr || save_stack_address(trace, addr, false))
+ return -1;
+ }
+
+ if (!unwind_done(&state) || unwind_error(&state))
+ return -1;
+
+ if (trace->nr_entries < trace->max_entries)
+ trace->entries[trace->nr_entries++] = ULONG_MAX;
+
+ return 0;
+}
+
+int save_stack_trace_tsk_reliable(struct task_struct *tsk,
+ struct stack_trace *trace)
+{
+ int ret;
+
+ if (!try_get_task_stack(tsk))
+ return -EINVAL;
+
+ ret = __save_stack_trace_reliable(trace, tsk);
+
+ put_task_stack(tsk);
+
+ return ret;
+}
+#endif /* CONFIG_HAVE_RELIABLE_STACKTRACE */
+
/* Userspace stacktrace - based on kernel/trace/trace_sysprof.c */
struct stack_frame_user {
@@ -136,4 +194,3 @@ void save_stack_trace_user(struct stack_trace *trace)
if (trace->nr_entries < trace->max_entries)
trace->entries[trace->nr_entries++] = ULONG_MAX;
}
-
diff --git a/arch/x86/kernel/unwind_frame.c b/arch/x86/kernel/unwind_frame.c
index ea7b7f9..f82525a 100644
--- a/arch/x86/kernel/unwind_frame.c
+++ b/arch/x86/kernel/unwind_frame.c
@@ -184,6 +184,7 @@ bool unwind_next_frame(struct unwind_state *state)
state->bp, state->task->comm,
state->task->pid, next_frame);
}
+ state->error = true;
the_end:
state->stack_info.type = STACK_TYPE_UNKNOWN;
return false;
diff --git a/include/linux/stacktrace.h b/include/linux/stacktrace.h
index 0a34489..8e8b67b 100644
--- a/include/linux/stacktrace.h
+++ b/include/linux/stacktrace.h
@@ -18,6 +18,8 @@ extern void save_stack_trace_regs(struct pt_regs *regs,
struct stack_trace *trace);
extern void save_stack_trace_tsk(struct task_struct *tsk,
struct stack_trace *trace);
+extern int save_stack_trace_tsk_reliable(struct task_struct *tsk,
+ struct stack_trace *trace);
extern void print_stack_trace(struct stack_trace *trace, int spaces);
extern int snprint_stack_trace(char *buf, size_t size,
@@ -29,12 +31,12 @@ extern void save_stack_trace_user(struct stack_trace *trace);
# define save_stack_trace_user(trace) do { } while (0)
#endif
-#else
+#else /* !CONFIG_STACKTRACE */
# define save_stack_trace(trace) do { } while (0)
# define save_stack_trace_tsk(tsk, trace) do { } while (0)
# define save_stack_trace_user(trace) do { } while (0)
# define print_stack_trace(trace, spaces) do { } while (0)
# define snprint_stack_trace(buf, size, trace, spaces) do { } while (0)
-#endif
+#endif /* CONFIG_STACKTRACE */
-#endif
+#endif /* __LINUX_STACKTRACE_H */
diff --git a/kernel/stacktrace.c b/kernel/stacktrace.c
index b6e4c16..4ef81dc 100644
--- a/kernel/stacktrace.c
+++ b/kernel/stacktrace.c
@@ -58,8 +58,8 @@ int snprint_stack_trace(char *buf, size_t size,
EXPORT_SYMBOL_GPL(snprint_stack_trace);
/*
- * Architectures that do not implement save_stack_trace_tsk or
- * save_stack_trace_regs get this weak alias and a once-per-bootup warning
+ * Architectures that do not implement save_stack_trace_*()
+ * get these weak aliases and once-per-bootup warnings
* (whenever this facility is utilized - for example by procfs):
*/
__weak void
@@ -73,3 +73,11 @@ save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace)
{
WARN_ONCE(1, KERN_INFO "save_stack_trace_regs() not implemented yet.\n");
}
+
+__weak int
+save_stack_trace_tsk_reliable(struct task_struct *tsk,
+ struct stack_trace *trace)
+{
+ WARN_ONCE(1, KERN_INFO "save_stack_tsk_reliable() not implemented yet.\n");
+ return -ENOSYS;
+}
--
2.7.4
next prev parent reply other threads:[~2016-12-08 18:12 UTC|newest]
Thread overview: 78+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-12-08 18:08 [PATCH v3 00/15] livepatch: hybrid consistency model Josh Poimboeuf
2016-12-08 18:08 ` Josh Poimboeuf [this message]
2016-12-16 13:07 ` [PATCH v3 01/15] stacktrace/x86: add function for detecting reliable stack traces Petr Mladek
2016-12-16 22:09 ` Josh Poimboeuf
2016-12-19 16:25 ` Miroslav Benes
2016-12-19 17:25 ` Josh Poimboeuf
2016-12-19 18:23 ` Miroslav Benes
2016-12-20 9:39 ` Petr Mladek
2016-12-20 21:21 ` Josh Poimboeuf
2016-12-08 18:08 ` [PATCH v3 02/15] x86/entry: define _TIF_ALLWORK_MASK flags explicitly Josh Poimboeuf
2016-12-16 14:17 ` Petr Mladek
2016-12-16 22:13 ` Josh Poimboeuf
2016-12-19 16:39 ` Miroslav Benes
2017-01-10 8:49 ` Kamalesh Babulal
2016-12-08 18:08 ` [PATCH v3 03/15] livepatch: temporary stubs for klp_patch_pending() and klp_update_patch_state() Josh Poimboeuf
2016-12-16 14:41 ` Petr Mladek
2016-12-16 22:15 ` Josh Poimboeuf
2016-12-08 18:08 ` [PATCH v3 04/15] livepatch/x86: add TIF_PATCH_PENDING thread flag Josh Poimboeuf
2016-12-08 18:27 ` Andy Lutomirski
2016-12-16 15:39 ` Petr Mladek
2016-12-21 13:54 ` Miroslav Benes
2017-01-11 7:06 ` Kamalesh Babulal
2016-12-08 18:08 ` [PATCH v3 05/15] livepatch/powerpc: " Josh Poimboeuf
2016-12-16 16:00 ` Petr Mladek
2016-12-21 14:30 ` Miroslav Benes
2017-01-10 8:29 ` Kamalesh Babulal
2016-12-08 18:08 ` [PATCH v3 06/15] livepatch/s390: reorganize TIF thread flag bits Josh Poimboeuf
2016-12-21 15:29 ` Miroslav Benes
2016-12-08 18:08 ` [PATCH v3 07/15] livepatch/s390: add TIF_PATCH_PENDING thread flag Josh Poimboeuf
2016-12-08 18:08 ` [PATCH v3 08/15] livepatch: separate enabled and patched states Josh Poimboeuf
2016-12-16 16:21 ` Petr Mladek
2016-12-23 12:54 ` Miroslav Benes
2017-01-10 9:10 ` Kamalesh Babulal
2016-12-08 18:08 ` [PATCH v3 09/15] livepatch: remove unnecessary object loaded check Josh Poimboeuf
2016-12-16 16:26 ` Petr Mladek
2016-12-23 12:58 ` Miroslav Benes
2017-01-10 9:14 ` Kamalesh Babulal
2016-12-08 18:08 ` [PATCH v3 10/15] livepatch: move patching functions into patch.c Josh Poimboeuf
2016-12-16 16:49 ` Petr Mladek
2016-12-23 13:06 ` Miroslav Benes
2017-01-10 9:15 ` Kamalesh Babulal
2016-12-08 18:08 ` [PATCH v3 11/15] livepatch: use kstrtobool() in enabled_store() Josh Poimboeuf
2016-12-16 16:55 ` Petr Mladek
2016-12-16 22:19 ` Josh Poimboeuf
2016-12-23 13:13 ` Miroslav Benes
2016-12-08 18:08 ` [PATCH v3 12/15] livepatch: store function sizes Josh Poimboeuf
2016-12-19 13:10 ` Petr Mladek
2016-12-23 13:40 ` Miroslav Benes
2017-01-11 10:09 ` Kamalesh Babulal
2016-12-08 18:08 ` [PATCH v3 13/15] livepatch: change to a per-task consistency model Josh Poimboeuf
2016-12-20 17:32 ` Petr Mladek
2016-12-21 21:25 ` Josh Poimboeuf
2016-12-22 14:34 ` Petr Mladek
2016-12-22 18:31 ` Josh Poimboeuf
2017-01-10 13:00 ` Petr Mladek
2017-01-10 20:46 ` Josh Poimboeuf
2017-01-11 15:18 ` Petr Mladek
2017-01-11 15:26 ` Josh Poimboeuf
2016-12-23 9:24 ` Miroslav Benes
2016-12-23 10:18 ` Petr Mladek
2017-01-06 20:07 ` Josh Poimboeuf
2017-01-10 10:40 ` Petr Mladek
2017-01-04 13:44 ` Miroslav Benes
2017-01-06 21:01 ` Josh Poimboeuf
2017-01-10 10:45 ` Miroslav Benes
2017-01-05 9:34 ` Miroslav Benes
2017-01-06 21:04 ` Josh Poimboeuf
2016-12-08 18:08 ` [PATCH v3 14/15] livepatch: add /proc/<pid>/patch_state Josh Poimboeuf
2016-12-21 11:20 ` Petr Mladek
2017-01-04 14:50 ` Miroslav Benes
2016-12-08 18:08 ` [PATCH v3 15/15] livepatch: allow removal of a disabled patch Josh Poimboeuf
2016-12-21 14:44 ` Petr Mladek
2017-01-04 14:57 ` Miroslav Benes
2017-01-06 21:04 ` Josh Poimboeuf
2016-12-10 5:46 ` [PATCH v3 00/15] livepatch: hybrid consistency model Balbir Singh
2016-12-10 17:17 ` Josh Poimboeuf
2016-12-11 2:08 ` Balbir Singh
2016-12-12 14:04 ` Josh Poimboeuf
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=0315b36c08c104d56a4b43537fb300d200418996.1481220077.git.jpoimboe@redhat.com \
--to=jpoimboe@redhat.com \
--cc=chris.j.arges@canonical.com \
--cc=heiko.carstens@de.ibm.com \
--cc=jeyu@redhat.com \
--cc=jikos@kernel.org \
--cc=jslaby@suse.cz \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-s390@vger.kernel.org \
--cc=linuxppc-dev@lists.ozlabs.org \
--cc=live-patching@vger.kernel.org \
--cc=luto@kernel.org \
--cc=mbenes@suse.cz \
--cc=mingo@kernel.org \
--cc=mpe@ellerman.id.au \
--cc=peterz@infradead.org \
--cc=pmladek@suse.com \
--cc=vojtech@suse.com \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).