From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754100AbdKXRas (ORCPT ); Fri, 24 Nov 2017 12:30:48 -0500 Received: from mail-wm0-f67.google.com ([74.125.82.67]:37654 "EHLO mail-wm0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753982AbdKXRZI (ORCPT ); Fri, 24 Nov 2017 12:25:08 -0500 X-Google-Smtp-Source: AGs4zMbw6etiLfMGrPAYQ7c9lHtod9omMJQw3G0h5IkqFuXmjcH8gyYZigPAVcV64ajg9kdlIAVL3w== From: Ingo Molnar To: linux-kernel@vger.kernel.org Cc: Dave Hansen , Andy Lutomirski , Thomas Gleixner , "H . Peter Anvin" , Peter Zijlstra , Borislav Petkov , Linus Torvalds Subject: [PATCH 21/43] x86/mm/kaiser: Disable global pages by default with KAISER Date: Fri, 24 Nov 2017 18:23:49 +0100 Message-Id: <20171124172411.19476-22-mingo@kernel.org> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20171124172411.19476-1-mingo@kernel.org> References: <20171124172411.19476-1-mingo@kernel.org> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Dave Hansen Global pages stay in the TLB across context switches. Since all contexts share the same kernel mapping, these mappings are marked as global pages so kernel entries in the TLB are not flushed out on a context switch. But, even having these entries in the TLB opens up something that an attacker can use [1]. That means that even when KAISER switches page tables on return to user space the global pages would stay in the TLB cache. Disable global pages so that kernel TLB entries can be flushed before returning to user space. This way, all accesses to kernel addresses from userspace result in a TLB miss independent of the existence of a kernel mapping. Replace _PAGE_GLOBAL by __PAGE_KERNEL_GLOBAL and keep _PAGE_GLOBAL available so that it can still be used for a few selected kernel mappings which must be visible to userspace, when KAISER is enabled, like the entry/exit code and data. 1. The double-page-fault attack: http://www.ieee-security.org/TC/SP2013/papers/4977a191.pdf Signed-off-by: Dave Hansen Signed-off-by: Thomas Gleixner Reviewed-by: Borislav Petkov Reviewed-by: Thomas Gleixner Cc: Linus Torvalds Cc: Peter Zijlstra Cc: daniel.gruss@iaik.tugraz.at Cc: hughd@google.com Cc: keescook@google.com Cc: linux-mm@kvack.org Cc: luto@kernel.org Cc: michael.schwarz@iaik.tugraz.at Cc: moritz.lipp@iaik.tugraz.at Cc: richard.fellner@student.tugraz.at Link: https://lkml.kernel.org/r/20171123003441.63DDFC6F@viggo.jf.intel.com Signed-off-by: Ingo Molnar --- arch/x86/include/asm/pgtable_types.h | 14 +++++++++++++- arch/x86/mm/pageattr.c | 16 ++++++++-------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h index 9e9b05fc4860..1fc2f22b9002 100644 --- a/arch/x86/include/asm/pgtable_types.h +++ b/arch/x86/include/asm/pgtable_types.h @@ -180,8 +180,20 @@ enum page_cache_mode { #define PAGE_READONLY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | \ _PAGE_ACCESSED) +/* + * Disable global pages for anything using the default + * __PAGE_KERNEL* macros. PGE will still be enabled + * and _PAGE_GLOBAL may still be used carefully. + */ +#ifdef CONFIG_KAISER +#define __PAGE_KERNEL_GLOBAL 0 +#else +#define __PAGE_KERNEL_GLOBAL _PAGE_GLOBAL +#endif + #define __PAGE_KERNEL_EXEC \ - (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_GLOBAL) + (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | \ + __PAGE_KERNEL_GLOBAL) #define __PAGE_KERNEL (__PAGE_KERNEL_EXEC | _PAGE_NX) #define __PAGE_KERNEL_RO (__PAGE_KERNEL & ~_PAGE_RW) diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 3fe68483463c..ffe584fa1f5e 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c @@ -585,9 +585,9 @@ try_preserve_large_page(pte_t *kpte, unsigned long address, * for the ancient hardware that doesn't support it. */ if (pgprot_val(req_prot) & _PAGE_PRESENT) - pgprot_val(req_prot) |= _PAGE_PSE | _PAGE_GLOBAL; + pgprot_val(req_prot) |= _PAGE_PSE | __PAGE_KERNEL_GLOBAL; else - pgprot_val(req_prot) &= ~(_PAGE_PSE | _PAGE_GLOBAL); + pgprot_val(req_prot) &= ~(_PAGE_PSE | __PAGE_KERNEL_GLOBAL); req_prot = canon_pgprot(req_prot); @@ -705,9 +705,9 @@ __split_large_page(struct cpa_data *cpa, pte_t *kpte, unsigned long address, * for the ancient hardware that doesn't support it. */ if (pgprot_val(ref_prot) & _PAGE_PRESENT) - pgprot_val(ref_prot) |= _PAGE_GLOBAL; + pgprot_val(ref_prot) |= __PAGE_KERNEL_GLOBAL; else - pgprot_val(ref_prot) &= ~_PAGE_GLOBAL; + pgprot_val(ref_prot) &= ~__PAGE_KERNEL_GLOBAL; /* * Get the target pfn from the original entry: @@ -938,9 +938,9 @@ static void populate_pte(struct cpa_data *cpa, * support it. */ if (pgprot_val(pgprot) & _PAGE_PRESENT) - pgprot_val(pgprot) |= _PAGE_GLOBAL; + pgprot_val(pgprot) |= __PAGE_KERNEL_GLOBAL; else - pgprot_val(pgprot) &= ~_PAGE_GLOBAL; + pgprot_val(pgprot) &= ~__PAGE_KERNEL_GLOBAL; pgprot = canon_pgprot(pgprot); @@ -1242,9 +1242,9 @@ static int __change_page_attr(struct cpa_data *cpa, int primary) * support it. */ if (pgprot_val(new_prot) & _PAGE_PRESENT) - pgprot_val(new_prot) |= _PAGE_GLOBAL; + pgprot_val(new_prot) |= __PAGE_KERNEL_GLOBAL; else - pgprot_val(new_prot) &= ~_PAGE_GLOBAL; + pgprot_val(new_prot) &= ~__PAGE_KERNEL_GLOBAL; /* * We need to keep the pfn from the existing PTE, -- 2.14.1