Patch "sparc64: Prevent perf from running during super critical sections" has been added to the 4.9-stable tree
Subsystems (2)
This is a note to let you know that I've just added the patch titled
sparc64: Prevent perf from running during super critical sections
to the 4.9-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
sparc64-prevent-perf-from-running-during-super-critical-sections.patch
and it can be found in the queue-4.9 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
fc290a114fc6034b0f6a5a46e2fb7d54976cf87aMon Sep 17 00:00:00 2001
From: Rob Gardner <[email protected]>
Date: Mon, 17 Jul 2017 09:22:27 -0600
Subject: sparc64: Prevent perf from running during super critical sections
From: Rob Gardner <[email protected]>
commit fc290a114fc6034b0f6a5a46e2fb7d54976cf87a upstream.
This fixes another cause of random segfaults and bus errors that may occur while running perf with the callgraph option.
Critical sections beginning with spin_lock_irqsave() raise the interrupt level to PIL_NORMAL_MAX (14) and intentionally do not block performance counter interrupts, which arrive at PIL_NMI (15).
But some sections of code are "super critical" with respect to perf because the perf_callchain_user() path accesses user space and may cause TLB activity as well as faults as it unwinds the user stack.
One particular critical section occurs in switch_mm:
spin_lock_irqsave(&mm->context.lock, flags);
...
load_secondary_context(mm);
tsb_context_switch(mm);
...
spin_unlock_irqrestore(&mm->context.lock, flags);If a perf interrupt arrives in between load_secondary_context() and tsb_context_switch(), then perf_callchain_user() could execute with the context ID of one process, but with an active TSB for a different process. When the user stack is accessed, it is very likely to incur a TLB miss, since the h/w context ID has been changed. The TLB will then be reloaded with a translation from the TSB for one process, but using a context ID for another process. This exposes memory from one process to another, and since it is a mapping for stack memory, this usually causes the new process to crash quickly.
This super critical section needs more protection than is provided by spin_lock_irqsave() since perf interrupts must not be allowed in.
Since __tsb_context_switch already goes through the trouble of disabling interrupts completely, we fix this by moving the secondary context load down into this better protected region.
Orabug: 25577560
--- arch/sparc/include/asm/mmu_context_64.h | 14 +++++++++----- arch/sparc/kernel/tsb.S | 12 ++++++++++++ arch/sparc/power/hibernate.c | 3 +-- 3 files changed, 22 insertions(+), 7 deletions(-)
arch/sparc/include/asm/mmu_context_64.h +9 -5
@@ -25,9 +25,11 @@ void destroy_context(struct mm_struct *mvoid __tsb_context_switch (unsigned long pgd_pa,struct tsb_config *tsb_base,struct tsb_config *tsb_huge, -unsigned long tsb_descr_pa); +unsigned long tsb_descr_pa, +unsigned long secondary_ctx); -static inline void tsb_context_switch (struct mm_struct *mm) +static inline void tsb_context_switch_ctx (struct mm_struct *mm, +unsigned long ctx) { __tsb_context_switch(__pa(mm->pgd), &mm->context.tsb_block[0],
@@ -38,9 +40,12 @@ static inline void tsb_context_switch(st#else NULL #endif - , __pa(&mm->context.tsb_descr[0])); + ,__pa (&mm->context.tsb_descr[0 ]), + ctx); } +#define tsb_context_switch (X ) tsb_context_switch_ctx(X, 0) +void tsb_grow (struct mm_struct *mm,unsigned long tsb_index,unsigned long mm_rss);
@@ -110,8 +115,7 @@ static inline void switch_mm(struct mm_s* cpu0 to update it's TSB because at that point the cpu_vm_mask * only had cpu1 set in it. */ -load_secondary_context (mm); -tsb_context_switch (mm); +tsb_context_switch_ctx (mm,CTX_HWBITS (mm->context));/* Any time a processor runs a context on an address space * for the first time, we must flush that context out of the
arch/sparc/kernel/tsb.S +12 -0
@@ -375,6 +375,7 @@ tsb_flush: * %o1: TSB base config pointer * %o2: TSB huge config pointer, or NULL if none * %o3: Hypervisor TSB descriptor physical address + * %o4: Secondary context to load, if non-zero * * We have to run this whole thing with interrupts * disabled so that the current cpu doesn't change
@@ -387,6 +388,17 @@ __tsb_context_switch: rdpr %pstate, %g1 wrpr %g1, PSTATE_IE, %pstate + brz,pn %o4, 1f + mov SECONDARY_CONTEXT, %o5 + +661: stxa %o4, [%o5] ASI_DMMU + .section .sun4v_1insn_patch, "ax" + .word 661b + stxa %o4, [%o5] ASI_MMU + .previous + flush %g6 + +1: TRAP_LOAD_TRAP_BLOCK(%g2, %g3) stx %o0, [%g2 + TRAP_PER_CPU_PGD_PADDR]
arch/sparc/power/hibernate.c +1 -2
@@ -35,6 +35,5 @@ void restore_processor_state(void) {struct mm_struct *mm = current->active_mm; -load_secondary_context (mm); -tsb_context_switch (mm); +tsb_context_switch_ctx (mm,CTX_HWBITS (mm->context)); }
Patches currently in stable-queue which might be from [email protected] are
queue-4.9/sparc64-prevent-perf-from-running-during-super-critical-sections.patch