aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/hyperv/hv_init.c7
-rw-r--r--arch/x86/include/asm/page_64_types.h4
-rw-r--r--arch/x86/include/asm/unwind.h6
-rw-r--r--arch/x86/kernel/unwind_frame.c25
-rw-r--r--arch/x86/kernel/unwind_orc.c17
-rw-r--r--arch/x86/mm/pageattr.c4
-rw-r--r--include/asm-generic/vmlinux.lds.h2
7 files changed, 55 insertions, 10 deletions
diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c
index 7f2eed1fc81b..6461a16b4559 100644
--- a/arch/x86/hyperv/hv_init.c
+++ b/arch/x86/hyperv/hv_init.c
@@ -407,6 +407,13 @@ void hyperv_cleanup(void)
407 /* Reset our OS id */ 407 /* Reset our OS id */
408 wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0); 408 wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0);
409 409
410 /*
411 * Reset hypercall page reference before reset the page,
412 * let hypercall operations fail safely rather than
413 * panic the kernel for using invalid hypercall page
414 */
415 hv_hypercall_pg = NULL;
416
410 /* Reset the hypercall page */ 417 /* Reset the hypercall page */
411 hypercall_msr.as_uint64 = 0; 418 hypercall_msr.as_uint64 = 0;
412 wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); 419 wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
diff --git a/arch/x86/include/asm/page_64_types.h b/arch/x86/include/asm/page_64_types.h
index 0ce558a8150d..8f657286d599 100644
--- a/arch/x86/include/asm/page_64_types.h
+++ b/arch/x86/include/asm/page_64_types.h
@@ -7,11 +7,7 @@
7#endif 7#endif
8 8
9#ifdef CONFIG_KASAN 9#ifdef CONFIG_KASAN
10#ifdef CONFIG_KASAN_EXTRA
11#define KASAN_STACK_ORDER 2
12#else
13#define KASAN_STACK_ORDER 1 10#define KASAN_STACK_ORDER 1
14#endif
15#else 11#else
16#define KASAN_STACK_ORDER 0 12#define KASAN_STACK_ORDER 0
17#endif 13#endif
diff --git a/arch/x86/include/asm/unwind.h b/arch/x86/include/asm/unwind.h
index 1f86e1b0a5cd..499578f7e6d7 100644
--- a/arch/x86/include/asm/unwind.h
+++ b/arch/x86/include/asm/unwind.h
@@ -23,6 +23,12 @@ struct unwind_state {
23#elif defined(CONFIG_UNWINDER_FRAME_POINTER) 23#elif defined(CONFIG_UNWINDER_FRAME_POINTER)
24 bool got_irq; 24 bool got_irq;
25 unsigned long *bp, *orig_sp, ip; 25 unsigned long *bp, *orig_sp, ip;
26 /*
27 * If non-NULL: The current frame is incomplete and doesn't contain a
28 * valid BP. When looking for the next frame, use this instead of the
29 * non-existent saved BP.
30 */
31 unsigned long *next_bp;
26 struct pt_regs *regs; 32 struct pt_regs *regs;
27#else 33#else
28 unsigned long *sp; 34 unsigned long *sp;
diff --git a/arch/x86/kernel/unwind_frame.c b/arch/x86/kernel/unwind_frame.c
index 3dc26f95d46e..9b9fd4826e7a 100644
--- a/arch/x86/kernel/unwind_frame.c
+++ b/arch/x86/kernel/unwind_frame.c
@@ -320,10 +320,14 @@ bool unwind_next_frame(struct unwind_state *state)
320 } 320 }
321 321
322 /* Get the next frame pointer: */ 322 /* Get the next frame pointer: */
323 if (state->regs) 323 if (state->next_bp) {
324 next_bp = state->next_bp;
325 state->next_bp = NULL;
326 } else if (state->regs) {
324 next_bp = (unsigned long *)state->regs->bp; 327 next_bp = (unsigned long *)state->regs->bp;
325 else 328 } else {
326 next_bp = (unsigned long *)READ_ONCE_TASK_STACK(state->task, *state->bp); 329 next_bp = (unsigned long *)READ_ONCE_TASK_STACK(state->task, *state->bp);
330 }
327 331
328 /* Move to the next frame if it's safe: */ 332 /* Move to the next frame if it's safe: */
329 if (!update_stack_state(state, next_bp)) 333 if (!update_stack_state(state, next_bp))
@@ -398,6 +402,21 @@ void __unwind_start(struct unwind_state *state, struct task_struct *task,
398 402
399 bp = get_frame_pointer(task, regs); 403 bp = get_frame_pointer(task, regs);
400 404
405 /*
406 * If we crash with IP==0, the last successfully executed instruction
407 * was probably an indirect function call with a NULL function pointer.
408 * That means that SP points into the middle of an incomplete frame:
409 * *SP is a return pointer, and *(SP-sizeof(unsigned long)) is where we
410 * would have written a frame pointer if we hadn't crashed.
411 * Pretend that the frame is complete and that BP points to it, but save
412 * the real BP so that we can use it when looking for the next frame.
413 */
414 if (regs && regs->ip == 0 &&
415 (unsigned long *)kernel_stack_pointer(regs) >= first_frame) {
416 state->next_bp = bp;
417 bp = ((unsigned long *)kernel_stack_pointer(regs)) - 1;
418 }
419
401 /* Initialize stack info and make sure the frame data is accessible: */ 420 /* Initialize stack info and make sure the frame data is accessible: */
402 get_stack_info(bp, state->task, &state->stack_info, 421 get_stack_info(bp, state->task, &state->stack_info,
403 &state->stack_mask); 422 &state->stack_mask);
@@ -410,7 +429,7 @@ void __unwind_start(struct unwind_state *state, struct task_struct *task,
410 */ 429 */
411 while (!unwind_done(state) && 430 while (!unwind_done(state) &&
412 (!on_stack(&state->stack_info, first_frame, sizeof(long)) || 431 (!on_stack(&state->stack_info, first_frame, sizeof(long)) ||
413 state->bp < first_frame)) 432 (state->next_bp == NULL && state->bp < first_frame)))
414 unwind_next_frame(state); 433 unwind_next_frame(state);
415} 434}
416EXPORT_SYMBOL_GPL(__unwind_start); 435EXPORT_SYMBOL_GPL(__unwind_start);
diff --git a/arch/x86/kernel/unwind_orc.c b/arch/x86/kernel/unwind_orc.c
index 26038eacf74a..89be1be1790c 100644
--- a/arch/x86/kernel/unwind_orc.c
+++ b/arch/x86/kernel/unwind_orc.c
@@ -113,6 +113,20 @@ static struct orc_entry *orc_ftrace_find(unsigned long ip)
113} 113}
114#endif 114#endif
115 115
116/*
117 * If we crash with IP==0, the last successfully executed instruction
118 * was probably an indirect function call with a NULL function pointer,
119 * and we don't have unwind information for NULL.
120 * This hardcoded ORC entry for IP==0 allows us to unwind from a NULL function
121 * pointer into its parent and then continue normally from there.
122 */
123static struct orc_entry null_orc_entry = {
124 .sp_offset = sizeof(long),
125 .sp_reg = ORC_REG_SP,
126 .bp_reg = ORC_REG_UNDEFINED,
127 .type = ORC_TYPE_CALL
128};
129
116static struct orc_entry *orc_find(unsigned long ip) 130static struct orc_entry *orc_find(unsigned long ip)
117{ 131{
118 static struct orc_entry *orc; 132 static struct orc_entry *orc;
@@ -120,6 +134,9 @@ static struct orc_entry *orc_find(unsigned long ip)
120 if (!orc_init) 134 if (!orc_init)
121 return NULL; 135 return NULL;
122 136
137 if (ip == 0)
138 return &null_orc_entry;
139
123 /* For non-init vmlinux addresses, use the fast lookup table: */ 140 /* For non-init vmlinux addresses, use the fast lookup table: */
124 if (ip >= LOOKUP_START_IP && ip < LOOKUP_STOP_IP) { 141 if (ip >= LOOKUP_START_IP && ip < LOOKUP_STOP_IP) {
125 unsigned int idx, start, stop; 142 unsigned int idx, start, stop;
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index 14e6119838a6..4c570612e24e 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -738,7 +738,7 @@ static int __should_split_large_page(pte_t *kpte, unsigned long address,
738{ 738{
739 unsigned long numpages, pmask, psize, lpaddr, pfn, old_pfn; 739 unsigned long numpages, pmask, psize, lpaddr, pfn, old_pfn;
740 pgprot_t old_prot, new_prot, req_prot, chk_prot; 740 pgprot_t old_prot, new_prot, req_prot, chk_prot;
741 pte_t new_pte, old_pte, *tmp; 741 pte_t new_pte, *tmp;
742 enum pg_level level; 742 enum pg_level level;
743 743
744 /* 744 /*
@@ -781,7 +781,7 @@ static int __should_split_large_page(pte_t *kpte, unsigned long address,
781 * Convert protection attributes to 4k-format, as cpa->mask* are set 781 * Convert protection attributes to 4k-format, as cpa->mask* are set
782 * up accordingly. 782 * up accordingly.
783 */ 783 */
784 old_pte = *kpte; 784
785 /* Clear PSE (aka _PAGE_PAT) and move PAT bit to correct position */ 785 /* Clear PSE (aka _PAGE_PAT) and move PAT bit to correct position */
786 req_prot = pgprot_large_2_4k(old_prot); 786 req_prot = pgprot_large_2_4k(old_prot);
787 787
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 3d7a6a9c2370..f8f6f04c4453 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -733,7 +733,7 @@
733 KEEP(*(.orc_unwind_ip)) \ 733 KEEP(*(.orc_unwind_ip)) \
734 __stop_orc_unwind_ip = .; \ 734 __stop_orc_unwind_ip = .; \
735 } \ 735 } \
736 . = ALIGN(6); \ 736 . = ALIGN(2); \
737 .orc_unwind : AT(ADDR(.orc_unwind) - LOAD_OFFSET) { \ 737 .orc_unwind : AT(ADDR(.orc_unwind) - LOAD_OFFSET) { \
738 __start_orc_unwind = .; \ 738 __start_orc_unwind = .; \
739 KEEP(*(.orc_unwind)) \ 739 KEEP(*(.orc_unwind)) \