From patchwork Fri Jul 14 15:20:27 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rob Gardner X-Patchwork-Id: 788588 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3x8GbZ6W90z9s76 for ; Sat, 15 Jul 2017 01:20:42 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754416AbdGNPUm (ORCPT ); Fri, 14 Jul 2017 11:20:42 -0400 Received: from aserp1040.oracle.com ([141.146.126.69]:32117 "EHLO aserp1040.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754076AbdGNPUl (ORCPT ); Fri, 14 Jul 2017 11:20:41 -0400 Received: from aserv0022.oracle.com (aserv0022.oracle.com [141.146.126.234]) by aserp1040.oracle.com (Sentrion-MTA-4.3.2/Sentrion-MTA-4.3.2) with ESMTP id v6EFKe5W017926 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Fri, 14 Jul 2017 15:20:40 GMT Received: from brm-t84-02.us.oracle.com (brm-t84-02.us.oracle.com [10.80.150.81]) by aserv0022.oracle.com (8.14.4/8.14.4) with ESMTP id v6EFKe7l021080; Fri, 14 Jul 2017 15:20:40 GMT From: Rob Gardner To: sparclinux@vger.kernel.org Cc: Rob Gardner , Dave Aldridge Subject: [PATCH v2] sparc64: Prevent perf from running during super critical sections Date: Fri, 14 Jul 2017 09:20:27 -0600 Message-Id: <1500045627-451648-1-git-send-email-rob.gardner@oracle.com> X-Mailer: git-send-email 1.7.1 X-Source-IP: aserv0022.oracle.com [141.146.126.234] Sender: sparclinux-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: sparclinux@vger.kernel.org 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. Fixed by masking non-maskable interrupts just before the the super critical section in switch_mm(), and in restore_processor_state() which has the identical logic. This change persists until the end of the original critical section. Orabug: 25577560 Signed-off-by: Dave Aldridge Signed-off-by: Rob Gardner --- arch/sparc/include/asm/irqflags_64.h | 10 ++++++++++ arch/sparc/include/asm/mmu_context_64.h | 1 + arch/sparc/power/hibernate.c | 1 + 3 files changed, 12 insertions(+), 0 deletions(-) diff --git a/arch/sparc/include/asm/irqflags_64.h b/arch/sparc/include/asm/irqflags_64.h index 23cd27f..22f8228 100644 --- a/arch/sparc/include/asm/irqflags_64.h +++ b/arch/sparc/include/asm/irqflags_64.h @@ -36,6 +36,16 @@ static inline notrace void arch_local_irq_restore(unsigned long flags) ); } +static inline notrace void arch_local_nmi_disable(void) +{ + __asm__ __volatile__( + "wrpr %0, %%pil" + : /* no outputs */ + : "i" (PIL_NMI) + : "memory" + ); +} + static inline notrace void arch_local_irq_disable(void) { __asm__ __volatile__( diff --git a/arch/sparc/include/asm/mmu_context_64.h b/arch/sparc/include/asm/mmu_context_64.h index 2cddcda..cffd627 100644 --- a/arch/sparc/include/asm/mmu_context_64.h +++ b/arch/sparc/include/asm/mmu_context_64.h @@ -112,6 +112,7 @@ static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, str * cpu0 to update it's TSB because at that point the cpu_vm_mask * only had cpu1 set in it. */ + arch_local_nmi_disable(); load_secondary_context(mm); tsb_context_switch(mm); diff --git a/arch/sparc/power/hibernate.c b/arch/sparc/power/hibernate.c index 17bd2e1..1d77045 100644 --- a/arch/sparc/power/hibernate.c +++ b/arch/sparc/power/hibernate.c @@ -35,6 +35,7 @@ void restore_processor_state(void) { struct mm_struct *mm = current->active_mm; + arch_local_nmi_disable(); load_secondary_context(mm); tsb_context_switch(mm); }