Received: by 10.213.65.68 with SMTP id h4csp581074imn; Fri, 23 Mar 2018 10:51:35 -0700 (PDT) X-Google-Smtp-Source: AG47ELsCYOxoD+tV1sPy8i1rDtKKh5LmUPqDqsuTMxtyu1+08Bk+aGUr/2pEsiuPdecUa1mzi7LD X-Received: by 2002:a17:902:8d90:: with SMTP id v16-v6mr30068373plo.168.1521827495510; Fri, 23 Mar 2018 10:51:35 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1521827495; cv=none; d=google.com; s=arc-20160816; b=GZMm5SyRsehFzXFyIIosuIUJYeWcJBXOgzPJAKzK6eP/uyqkNMqc8N5jgQMyUTXlAC CozUN9hXvFrWBQ2sp+EXASFtT2lB9zbUaXMNoDT8lk8fzojNOeSCsewh/wkj8YDfPPZd mkkIu6/0wJNKCDMysItr5NkCXDNekkuaV2Pch/vsIud3ucIGtBGqsHsEcyn1Bi8BsuQF xJ7p1eMMSesiyXfAgAIT+w8B84Wp5Fh5ixsMH1obtT00jQtzX5T2BS0nC7aUsgRDWenC EW8wJWHAd0dfKSJIvVZ8zUn7nVj8OIVItoN5Jc27t6wdKONOSGsgg6CVhO2Ht93VbcBO 5r/w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:message-id:in-reply-to:references:date :from:cc:to:subject:arc-authentication-results; bh=PFzCJXX2vRm8RrY3ONbxolxRKOluD4Sbx++WhmR8NOM=; b=cBqM5Cvd8O/n7qvVjggqNqFFrqUWXPDs6bB0uj5cSDKWOO0XFjd1X7NLMWHiTgxl2B vyZ1oH74P3CrD97gF/8uj8X3gSNjGxPs2bKmHDSAY0MOEp6yE4xYS1tYR5oGY0HJAgwg AAVI3RgT+gBd8sfW2s6zaYASSH1R0yGYxfCXG6c7iYouuQlXBsnuc8x7gwpViEHgoX0O AA0xVWBTDVbd5vhcD1M1AsuOskv5tEk2JODw61hOce5S3teHuW/qZ8CjkCy35hkRucCy Jv9YQ+FLq+601USpYBx8Dkka2yrqhhiXmHHDs5NaKFSW/kjP/uwcYH70mUw1y3D5/6+9 CUAg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id b7-v6si10106562pla.345.2018.03.23.10.51.21; Fri, 23 Mar 2018 10:51:35 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752619AbeCWRt6 (ORCPT + 99 others); Fri, 23 Mar 2018 13:49:58 -0400 Received: from mga11.intel.com ([192.55.52.93]:18079 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752043AbeCWRq5 (ORCPT ); Fri, 23 Mar 2018 13:46:57 -0400 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 23 Mar 2018 10:46:56 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.48,351,1517904000"; d="scan'208";a="27909873" Received: from viggo.jf.intel.com (HELO localhost.localdomain) ([10.54.39.119]) by orsmga008.jf.intel.com with ESMTP; 23 Mar 2018 10:46:55 -0700 Subject: [PATCH 05/11] x86/mm: do not auto-massage page protections To: linux-kernel@vger.kernel.org Cc: linux-mm@kvack.org, Dave Hansen , aarcange@redhat.com, luto@kernel.org, torvalds@linux-foundation.org, keescook@google.com, hughd@google.com, jgross@suse.com, x86@kernel.org, namit@vmware.com From: Dave Hansen Date: Fri, 23 Mar 2018 10:44:54 -0700 References: <20180323174447.55F35636@viggo.jf.intel.com> In-Reply-To: <20180323174447.55F35636@viggo.jf.intel.com> Message-Id: <20180323174454.CD00F614@viggo.jf.intel.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Dave Hansen A PTE is constructed from a physical address and a pgprotval_t. __PAGE_KERNEL, for instance, is a pgprot_t and must be converted into a pgprotval_t before it can be used to create a PTE. This is done implicitly within functions like set_pte() by massage_pgprot(). However, this makes it very challenging to set bits (and keep them set) if your bit is being filtered out by massage_pgprot(). This moves the bit filtering out of set_pte() and friends. For users of PAGE_KERNEL*, filtering will be done automatically inside those macros but for users of __PAGE_KERNEL*, they need to do their own filtering now. Note that we also just move pfn_pte/pmd/pud() over to check_pgprot() instead of massage_pgprot(). This way, we still *look* for unsupported bits and properly warn about them if we find them. This might happen if an unfiltered __PAGE_KERNEL* value was passed in, for instance. Signed-off-by: Dave Hansen Cc: Andrea Arcangeli Cc: Andy Lutomirski Cc: Linus Torvalds Cc: Kees Cook Cc: Hugh Dickins Cc: Juergen Gross Cc: x86@kernel.org Cc: Nadav Amit --- b/arch/x86/include/asm/pgtable.h | 27 ++++++++++++++++++++++----- b/arch/x86/kernel/head64.c | 2 ++ b/arch/x86/kernel/ldt.c | 6 +++++- b/arch/x86/mm/ident_map.c | 3 +++ b/arch/x86/mm/iomap_32.c | 6 ++++++ b/arch/x86/mm/kasan_init_64.c | 14 +++++++++++++- b/arch/x86/power/hibernate_64.c | 20 +++++++++++++++----- b/mm/early_ioremap.c | 3 +++ 8 files changed, 69 insertions(+), 12 deletions(-) diff -puN arch/x86/include/asm/pgtable.h~x86-no-auto-massage arch/x86/include/asm/pgtable.h --- a/arch/x86/include/asm/pgtable.h~x86-no-auto-massage 2018-03-23 09:57:34.798820374 -0700 +++ b/arch/x86/include/asm/pgtable.h 2018-03-23 09:57:34.846820374 -0700 @@ -526,22 +526,39 @@ static inline pgprotval_t massage_pgprot return protval; } +static inline pgprotval_t check_pgprot(pgprot_t pgprot) +{ + pgprotval_t massaged_val = massage_pgprot(pgprot); + + /* mmdebug.h can not be included here because of dependencies */ +#ifdef CONFIG_DEBUG_VM + WARN_ONCE(pgprot_val(pgprot) != massaged_val, + "attempted to set unsupported pgprot: %016lx " + "bits: %016lx supported: %016lx\n", + pgprot_val(pgprot), + pgprot_val(pgprot) ^ massaged_val, + __supported_pte_mask); +#endif + + return massaged_val; +} + static inline pte_t pfn_pte(unsigned long page_nr, pgprot_t pgprot) { return __pte(((phys_addr_t)page_nr << PAGE_SHIFT) | - massage_pgprot(pgprot)); + check_pgprot(pgprot)); } static inline pmd_t pfn_pmd(unsigned long page_nr, pgprot_t pgprot) { return __pmd(((phys_addr_t)page_nr << PAGE_SHIFT) | - massage_pgprot(pgprot)); + check_pgprot(pgprot)); } static inline pud_t pfn_pud(unsigned long page_nr, pgprot_t pgprot) { return __pud(((phys_addr_t)page_nr << PAGE_SHIFT) | - massage_pgprot(pgprot)); + check_pgprot(pgprot)); } static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) @@ -553,7 +570,7 @@ static inline pte_t pte_modify(pte_t pte * the newprot (if present): */ val &= _PAGE_CHG_MASK; - val |= massage_pgprot(newprot) & ~_PAGE_CHG_MASK; + val |= check_pgprot(newprot) & ~_PAGE_CHG_MASK; return __pte(val); } @@ -563,7 +580,7 @@ static inline pmd_t pmd_modify(pmd_t pmd pmdval_t val = pmd_val(pmd); val &= _HPAGE_CHG_MASK; - val |= massage_pgprot(newprot) & ~_HPAGE_CHG_MASK; + val |= check_pgprot(newprot) & ~_HPAGE_CHG_MASK; return __pmd(val); } diff -puN arch/x86/kernel/head64.c~x86-no-auto-massage arch/x86/kernel/head64.c --- a/arch/x86/kernel/head64.c~x86-no-auto-massage 2018-03-23 09:57:34.800820374 -0700 +++ b/arch/x86/kernel/head64.c 2018-03-23 09:57:34.846820374 -0700 @@ -195,6 +195,8 @@ unsigned long __head __startup_64(unsign pud[i + 1] = (pudval_t)pmd + pgtable_flags; pmd_entry = __PAGE_KERNEL_LARGE_EXEC & ~_PAGE_GLOBAL; + /* Filter out unsupported __PAGE_KERNEL_* bits: */ + pmd_entry &= __supported_pte_mask; pmd_entry += sme_get_me_mask(); pmd_entry += physaddr; diff -puN arch/x86/kernel/ldt.c~x86-no-auto-massage arch/x86/kernel/ldt.c --- a/arch/x86/kernel/ldt.c~x86-no-auto-massage 2018-03-23 09:57:34.801820374 -0700 +++ b/arch/x86/kernel/ldt.c 2018-03-23 09:57:34.847820374 -0700 @@ -145,6 +145,7 @@ map_ldt_struct(struct mm_struct *mm, str unsigned long offset = i << PAGE_SHIFT; const void *src = (char *)ldt->entries + offset; unsigned long pfn; + pgprot_t pte_prot; pte_t pte, *ptep; va = (unsigned long)ldt_slot_va(slot) + offset; @@ -163,7 +164,10 @@ map_ldt_struct(struct mm_struct *mm, str * target via some kernel interface which misses a * permission check. */ - pte = pfn_pte(pfn, __pgprot(__PAGE_KERNEL_RO & ~_PAGE_GLOBAL)); + pte_prot = __pgprot(__PAGE_KERNEL_RO & ~_PAGE_GLOBAL); + /* Filter out unsuppored __PAGE_KERNEL* bits: */ + pgprot_val(pte_prot) |= __supported_pte_mask; + pte = pfn_pte(pfn, pte_prot); set_pte_at(mm, va, ptep, pte); pte_unmap_unlock(ptep, ptl); } diff -puN arch/x86/mm/ident_map.c~x86-no-auto-massage arch/x86/mm/ident_map.c --- a/arch/x86/mm/ident_map.c~x86-no-auto-massage 2018-03-23 09:57:34.803820374 -0700 +++ b/arch/x86/mm/ident_map.c 2018-03-23 09:57:34.847820374 -0700 @@ -98,6 +98,9 @@ int kernel_ident_mapping_init(struct x86 if (!info->kernpg_flag) info->kernpg_flag = _KERNPG_TABLE; + /* Filter out unsupported __PAGE_KERNEL_* bits: */ + info->kernpg_flag &= __default_kernel_pte_mask; + for (; addr < end; addr = next) { pgd_t *pgd = pgd_page + pgd_index(addr); p4d_t *p4d; diff -puN arch/x86/mm/iomap_32.c~x86-no-auto-massage arch/x86/mm/iomap_32.c --- a/arch/x86/mm/iomap_32.c~x86-no-auto-massage 2018-03-23 09:57:34.805820374 -0700 +++ b/arch/x86/mm/iomap_32.c 2018-03-23 09:57:34.847820374 -0700 @@ -44,6 +44,9 @@ int iomap_create_wc(resource_size_t base return ret; *prot = __pgprot(__PAGE_KERNEL | cachemode2protval(pcm)); + /* Filter out unsupported __PAGE_KERNEL* bits: */ + pgprot_val(*prot) &= __default_kernel_pte_mask; + return 0; } EXPORT_SYMBOL_GPL(iomap_create_wc); @@ -88,6 +91,9 @@ iomap_atomic_prot_pfn(unsigned long pfn, prot = __pgprot(__PAGE_KERNEL | cachemode2protval(_PAGE_CACHE_MODE_UC_MINUS)); + /* Filter out unsupported __PAGE_KERNEL* bits: */ + pgprot_val(prot) &= __default_kernel_pte_mask; + return (void __force __iomem *) kmap_atomic_prot_pfn(pfn, prot); } EXPORT_SYMBOL_GPL(iomap_atomic_prot_pfn); diff -puN arch/x86/mm/kasan_init_64.c~x86-no-auto-massage arch/x86/mm/kasan_init_64.c --- a/arch/x86/mm/kasan_init_64.c~x86-no-auto-massage 2018-03-23 09:57:34.807820374 -0700 +++ b/arch/x86/mm/kasan_init_64.c 2018-03-23 09:57:34.848820374 -0700 @@ -269,6 +269,12 @@ void __init kasan_early_init(void) pudval_t pud_val = __pa_nodebug(kasan_zero_pmd) | _KERNPG_TABLE; p4dval_t p4d_val = __pa_nodebug(kasan_zero_pud) | _KERNPG_TABLE; + /* Mask out unsupported __PAGE_KERNEL bits: */ + pte_val &= __default_kernel_pte_mask; + pmd_val &= __default_kernel_pte_mask; + pud_val &= __default_kernel_pte_mask; + p4d_val &= __default_kernel_pte_mask; + for (i = 0; i < PTRS_PER_PTE; i++) kasan_zero_pte[i] = __pte(pte_val); @@ -371,7 +377,13 @@ void __init kasan_init(void) */ memset(kasan_zero_page, 0, PAGE_SIZE); for (i = 0; i < PTRS_PER_PTE; i++) { - pte_t pte = __pte(__pa(kasan_zero_page) | __PAGE_KERNEL_RO | _PAGE_ENC); + pte_t pte; + pgprot_t prot; + + prot = __pgprot(__PAGE_KERNEL_RO | _PAGE_ENC); + pgprot_val(prot) &= __default_kernel_pte_mask; + + pte = __pte(__pa(kasan_zero_page) | pgprot_val(prot)); set_pte(&kasan_zero_pte[i], pte); } /* Flush TLBs again to be sure that write protection applied. */ diff -puN arch/x86/power/hibernate_64.c~x86-no-auto-massage arch/x86/power/hibernate_64.c --- a/arch/x86/power/hibernate_64.c~x86-no-auto-massage 2018-03-23 09:57:34.809820374 -0700 +++ b/arch/x86/power/hibernate_64.c 2018-03-23 09:58:20.228820261 -0700 @@ -51,6 +51,12 @@ static int set_up_temporary_text_mapping pmd_t *pmd; pud_t *pud; p4d_t *p4d = NULL; + pgprot_t pgtable_prot = __pgprot(_KERNPG_TABLE); + pgprot_t pmd_text_prot = __pgprot(__PAGE_KERNEL_LARGE_EXEC); + + /* Filter out unsupported __PAGE_KERNEL* bits: */ + pgprot_val(pmd_text_prot) &= __default_kernel_pte_mask; + pgprot_val(pgtable_prot) &= __default_kernel_pte_mask; /* * The new mapping only has to cover the page containing the image @@ -81,15 +87,19 @@ static int set_up_temporary_text_mapping return -ENOMEM; set_pmd(pmd + pmd_index(restore_jump_address), - __pmd((jump_address_phys & PMD_MASK) | __PAGE_KERNEL_LARGE_EXEC)); + __pmd((jump_address_phys & PMD_MASK) | pgprot_val(pmd_text_prot))); set_pud(pud + pud_index(restore_jump_address), - __pud(__pa(pmd) | _KERNPG_TABLE)); + __pud(__pa(pmd) | pgprot_val(pgtable_prot))); if (p4d) { - set_p4d(p4d + p4d_index(restore_jump_address), __p4d(__pa(pud) | _KERNPG_TABLE)); - set_pgd(pgd + pgd_index(restore_jump_address), __pgd(__pa(p4d) | _KERNPG_TABLE)); + p4d_t new_p4d = __p4d(__pa(pud) | pgprot_val(pgtable_prot)); + pgd_t new_pgd = __pgd(__pa(p4d) | pgprot_val(pgtable_prot)); + + set_p4d(p4d + p4d_index(restore_jump_address), new_p4d); + set_pgd(pgd + pgd_index(restore_jump_address), new_pgd); } else { /* No p4d for 4-level paging: point the pgd to the pud page table */ - set_pgd(pgd + pgd_index(restore_jump_address), __pgd(__pa(pud) | _KERNPG_TABLE)); + pgd_t new_pgd = __pgd(__pa(p4d) | pgprot_val(pgtable_prot)); + set_pgd(pgd + pgd_index(restore_jump_address), new_pgd); } return 0; diff -puN mm/early_ioremap.c~x86-no-auto-massage mm/early_ioremap.c --- a/mm/early_ioremap.c~x86-no-auto-massage 2018-03-23 09:57:34.811820374 -0700 +++ b/mm/early_ioremap.c 2018-03-23 09:57:34.848820374 -0700 @@ -113,6 +113,9 @@ __early_ioremap(resource_size_t phys_add WARN_ON(system_state >= SYSTEM_RUNNING); + /* Sanitize 'prot' against any unsupported bits: */ + pgprot_val(prot) &= __default_kernel_pte_mask; + slot = -1; for (i = 0; i < FIX_BTMAPS_SLOTS; i++) { if (!prev_map[i]) { _