The following commit has been merged into the x86/seves branch of tip:

Commit-ID:     6b27edd74a5e9669120f7bd0ae1f475d124c1042
Gitweb:        
https://git.kernel.org/tip/6b27edd74a5e9669120f7bd0ae1f475d124c1042
Author:        Joerg Roedel <jroe...@suse.de>
AuthorDate:    Mon, 07 Sep 2020 15:15:45 +02:00
Committer:     Borislav Petkov <b...@suse.de>
CommitterDate: Wed, 09 Sep 2020 11:33:19 +02:00

x86/dumpstack/64: Add noinstr version of get_stack_info()

The get_stack_info() functionality is needed in the entry code for the
#VC exception handler. Provide a version of it in the .text.noinstr
section which can be called safely from there.

Signed-off-by: Joerg Roedel <jroe...@suse.de>
Signed-off-by: Borislav Petkov <b...@suse.de>
Link: https://lkml.kernel.org/r/20200907131613.12703-45-j...@8bytes.org
---
 arch/x86/include/asm/stacktrace.h |  2 ++-
 arch/x86/kernel/dumpstack.c       |  7 +++---
 arch/x86/kernel/dumpstack_64.c    | 38 +++++++++++++++++-------------
 arch/x86/mm/cpu_entry_area.c      |  3 +-
 4 files changed, 30 insertions(+), 20 deletions(-)

diff --git a/arch/x86/include/asm/stacktrace.h 
b/arch/x86/include/asm/stacktrace.h
index 5ae5a68..4960064 100644
--- a/arch/x86/include/asm/stacktrace.h
+++ b/arch/x86/include/asm/stacktrace.h
@@ -35,6 +35,8 @@ bool in_entry_stack(unsigned long *stack, struct stack_info 
*info);
 
 int get_stack_info(unsigned long *stack, struct task_struct *task,
                   struct stack_info *info, unsigned long *visit_mask);
+bool get_stack_info_noinstr(unsigned long *stack, struct task_struct *task,
+                           struct stack_info *info);
 
 const char *stack_type_name(enum stack_type type);
 
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c
index 48ce445..74147f7 100644
--- a/arch/x86/kernel/dumpstack.c
+++ b/arch/x86/kernel/dumpstack.c
@@ -29,8 +29,8 @@ static int die_counter;
 
 static struct pt_regs exec_summary_regs;
 
-bool in_task_stack(unsigned long *stack, struct task_struct *task,
-                  struct stack_info *info)
+bool noinstr in_task_stack(unsigned long *stack, struct task_struct *task,
+                          struct stack_info *info)
 {
        unsigned long *begin = task_stack_page(task);
        unsigned long *end   = task_stack_page(task) + THREAD_SIZE;
@@ -46,7 +46,8 @@ bool in_task_stack(unsigned long *stack, struct task_struct 
*task,
        return true;
 }
 
-bool in_entry_stack(unsigned long *stack, struct stack_info *info)
+/* Called from get_stack_info_noinstr - so must be noinstr too */
+bool noinstr in_entry_stack(unsigned long *stack, struct stack_info *info)
 {
        struct entry_stack *ss = cpu_entry_stack(smp_processor_id());
 
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
index c49cf59..1dd8513 100644
--- a/arch/x86/kernel/dumpstack_64.c
+++ b/arch/x86/kernel/dumpstack_64.c
@@ -85,7 +85,7 @@ struct estack_pages estack_pages[CEA_ESTACK_PAGES] 
____cacheline_aligned = {
        EPAGERANGE(VC2),
 };
 
-static bool in_exception_stack(unsigned long *stack, struct stack_info *info)
+static __always_inline bool in_exception_stack(unsigned long *stack, struct 
stack_info *info)
 {
        unsigned long begin, end, stk = (unsigned long)stack;
        const struct estack_pages *ep;
@@ -126,7 +126,7 @@ static bool in_exception_stack(unsigned long *stack, struct 
stack_info *info)
        return true;
 }
 
-static bool in_irq_stack(unsigned long *stack, struct stack_info *info)
+static __always_inline bool in_irq_stack(unsigned long *stack, struct 
stack_info *info)
 {
        unsigned long *end   = (unsigned long 
*)this_cpu_read(hardirq_stack_ptr);
        unsigned long *begin = end - (IRQ_STACK_SIZE / sizeof(long));
@@ -151,32 +151,38 @@ static bool in_irq_stack(unsigned long *stack, struct 
stack_info *info)
        return true;
 }
 
-int get_stack_info(unsigned long *stack, struct task_struct *task,
-                  struct stack_info *info, unsigned long *visit_mask)
+bool noinstr get_stack_info_noinstr(unsigned long *stack, struct task_struct 
*task,
+                                   struct stack_info *info)
 {
-       if (!stack)
-               goto unknown;
-
-       task = task ? : current;
-
        if (in_task_stack(stack, task, info))
-               goto recursion_check;
+               return true;
 
        if (task != current)
-               goto unknown;
+               return false;
 
        if (in_exception_stack(stack, info))
-               goto recursion_check;
+               return true;
 
        if (in_irq_stack(stack, info))
-               goto recursion_check;
+               return true;
 
        if (in_entry_stack(stack, info))
-               goto recursion_check;
+               return true;
+
+       return false;
+}
+
+int get_stack_info(unsigned long *stack, struct task_struct *task,
+                  struct stack_info *info, unsigned long *visit_mask)
+{
+       task = task ? : current;
 
-       goto unknown;
+       if (!stack)
+               goto unknown;
+
+       if (!get_stack_info_noinstr(stack, task, info))
+               goto unknown;
 
-recursion_check:
        /*
         * Make sure we don't iterate through any given stack more than once.
         * If it comes up a second time then there's something wrong going on:
diff --git a/arch/x86/mm/cpu_entry_area.c b/arch/x86/mm/cpu_entry_area.c
index 770b613..f5e1e60 100644
--- a/arch/x86/mm/cpu_entry_area.c
+++ b/arch/x86/mm/cpu_entry_area.c
@@ -21,7 +21,8 @@ DEFINE_PER_CPU(struct cea_exception_stacks*, 
cea_exception_stacks);
 DECLARE_PER_CPU_PAGE_ALIGNED(struct doublefault_stack, doublefault_stack);
 #endif
 
-struct cpu_entry_area *get_cpu_entry_area(int cpu)
+/* Is called from entry code, so must be noinstr */
+noinstr struct cpu_entry_area *get_cpu_entry_area(int cpu)
 {
        unsigned long va = CPU_ENTRY_AREA_PER_CPU + cpu * CPU_ENTRY_AREA_SIZE;
        BUILD_BUG_ON(sizeof(struct cpu_entry_area) % PAGE_SIZE != 0);

Reply via email to