Received: by 2002:a25:8b91:0:0:0:0:0 with SMTP id j17csp4643667ybl; Wed, 22 Jan 2020 01:55:41 -0800 (PST) X-Google-Smtp-Source: APXvYqzwjr4h8nOL5L8sSkfBOHHfpq4tWUaL6VXmFhkzwqU85gMdBcypbeK42C8jPPLQLXHEzl5j X-Received: by 2002:aca:6289:: with SMTP id w131mr6084778oib.61.1579686940912; Wed, 22 Jan 2020 01:55:40 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1579686940; cv=none; d=google.com; s=arc-20160816; b=df203wctfGx5pdTnXCt/bxCrGY3U1lc6XGGQc9s3uKlSiLgLLODX6zGshQYjO6WqS4 RGnb5SEikW1xOxXZr3oDmGI/XKKIUBmU/cUzpAjleA6e10vHxCce+sxQ7e62Rzr3EPFI O9tij4IOTpzQLDI6SxqL3F1nFOjW9BUMBdSyNRgCrEBZbq4RIa+YwhI5oFrlLYy8SSq9 C7tdY2LxruFT5z3mao7sjSrgaMRoSEYtM88u87HRQmJBZWh5WeAVga0hh3cI8tWqjmnj MSQbHyi0dBKkBHVkylc58FUnRVAIUtQP5bB++KTVo+xuEouJrHIFqKludalYt1/ydRz8 k9ow== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=WVFLIWvvGo4iizMI6FmGlyDpg8drLcDnjCJ2DHd6kZ0=; b=da6APBJOK7mrLEEHsg5YDfHFmTtE5sPR4DuwoNDmBtyeBzeOPx3TnAcyO76NZJV1lz JvehekKyWA0Hk9mfi2Rae1EIy7WzZjZdUabz0CfeWRcoLpDNyqpFUs79GQXh4rVG9ipC EV3Ag3G4MzKuFFVUnl13JsGeo1Co3xOTuM/Qhxok2Ri/KNFSfHrCTLBqLItw+ecmiRuP gQLikgavCleCBgiHPJgi9etXZ5cO+23JrE1gM3GE1OGRMaBbr8/cxELmqShn96Hkxkib MXeUmvvmLMAD3s27sfYOZH+6MUpqEQPK/AwOzUJT1hP+PDEPqllecZp3IYQt8HFTlEo1 Vtsw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b="RIWgB/TJ"; 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 g26si23530233otn.180.2020.01.22.01.55.29; Wed, 22 Jan 2020 01:55:40 -0800 (PST) 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; dkim=pass header.i=@kernel.org header.s=default header.b="RIWgB/TJ"; 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 S1730964AbgAVJyb (ORCPT + 99 others); Wed, 22 Jan 2020 04:54:31 -0500 Received: from mail.kernel.org ([198.145.29.99]:48094 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730039AbgAVJd7 (ORCPT ); Wed, 22 Jan 2020 04:33:59 -0500 Received: from localhost (83-86-89-107.cable.dynamic.v4.ziggo.nl [83.86.89.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 6DC3B24673; Wed, 22 Jan 2020 09:33:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1579685635; bh=EVjgaJW8OE5sV1Q9fTEbc2fZ13z60TLkZJ4lEhs+L4k=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=RIWgB/TJ5pAf+dh2yvyBwY3MKr5wpmNYgVFqGWBpRycyo9DHotnY0Dj8obP9uPtFq b1fsu4fL5klORFzhVPDVA7Lxs1DaG41aO/r69FA8tTC5t67Tqb/Vsl7yonY3gt0dIL jcOomAjmX51hxic++pWv7pcIB6DbJL8upFV18f0g= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Ard Biesheuvel , Catalin Marinas , Ben Hutchings Subject: [PATCH 4.9 07/97] arm64: mm: BUG on unsupported manipulations of live kernel mappings Date: Wed, 22 Jan 2020 10:28:11 +0100 Message-Id: <20200122092756.943196447@linuxfoundation.org> X-Mailer: git-send-email 2.25.0 In-Reply-To: <20200122092755.678349497@linuxfoundation.org> References: <20200122092755.678349497@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Ard Biesheuvel commit e98216b52176ba2bfa4bdb02f178f4d08832d465 upstream. Now that we take care not manipulate the live kernel page tables in a way that may lead to TLB conflicts, the case where a table mapping is replaced by a block mapping can no longer occur. So remove the handling of this at the PUD and PMD levels, and instead, BUG() on any occurrence of live kernel page table manipulations that modify anything other than the permission bits. Since mark_rodata_ro() is the only caller where the kernel mappings that are being manipulated are actually live, drop the various conditional flush_tlb_all() invocations, and add a single call to mark_rodata_ro() instead. Signed-off-by: Ard Biesheuvel Signed-off-by: Catalin Marinas Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- arch/arm64/mm/mmu.c | 70 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 27 deletions(-) --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -28,8 +28,6 @@ #include #include #include -#include -#include #include #include @@ -95,6 +93,17 @@ static phys_addr_t __init early_pgtable_ return phys; } +static bool pgattr_change_is_safe(u64 old, u64 new) +{ + /* + * The following mapping attributes may be updated in live + * kernel mappings without the need for break-before-make. + */ + static const pteval_t mask = PTE_PXN | PTE_RDONLY | PTE_WRITE; + + return old == 0 || new == 0 || ((old ^ new) & ~mask) == 0; +} + static void alloc_init_pte(pmd_t *pmd, unsigned long addr, unsigned long end, unsigned long pfn, pgprot_t prot, @@ -115,8 +124,17 @@ static void alloc_init_pte(pmd_t *pmd, u pte = pte_set_fixmap_offset(pmd, addr); do { + pte_t old_pte = *pte; + set_pte(pte, pfn_pte(pfn, prot)); pfn++; + + /* + * After the PTE entry has been populated once, we + * only allow updates to the permission attributes. + */ + BUG_ON(!pgattr_change_is_safe(pte_val(old_pte), pte_val(*pte))); + } while (pte++, addr += PAGE_SIZE, addr != end); pte_clear_fixmap(); @@ -146,27 +164,27 @@ static void alloc_init_pmd(pud_t *pud, u pmd = pmd_set_fixmap_offset(pud, addr); do { + pmd_t old_pmd = *pmd; + next = pmd_addr_end(addr, end); + /* try section mapping first */ if (((addr | next | phys) & ~SECTION_MASK) == 0 && allow_block_mappings) { - pmd_t old_pmd =*pmd; pmd_set_huge(pmd, phys, prot); + /* - * Check for previous table entries created during - * boot (__create_page_tables) and flush them. + * After the PMD entry has been populated once, we + * only allow updates to the permission attributes. */ - if (!pmd_none(old_pmd)) { - flush_tlb_all(); - if (pmd_table(old_pmd)) { - phys_addr_t table = pmd_page_paddr(old_pmd); - if (!WARN_ON_ONCE(slab_is_available())) - memblock_free(table, PAGE_SIZE); - } - } + BUG_ON(!pgattr_change_is_safe(pmd_val(old_pmd), + pmd_val(*pmd))); } else { alloc_init_pte(pmd, addr, next, __phys_to_pfn(phys), prot, pgtable_alloc); + + BUG_ON(pmd_val(old_pmd) != 0 && + pmd_val(old_pmd) != pmd_val(*pmd)); } phys += next - addr; } while (pmd++, addr = next, addr != end); @@ -204,33 +222,28 @@ static void alloc_init_pud(pgd_t *pgd, u pud = pud_set_fixmap_offset(pgd, addr); do { + pud_t old_pud = *pud; + next = pud_addr_end(addr, end); /* * For 4K granule only, attempt to put down a 1GB block */ if (use_1G_block(addr, next, phys) && allow_block_mappings) { - pud_t old_pud = *pud; pud_set_huge(pud, phys, prot); /* - * If we have an old value for a pud, it will - * be pointing to a pmd table that we no longer - * need (from swapper_pg_dir). - * - * Look up the old pmd table and free it. + * After the PUD entry has been populated once, we + * only allow updates to the permission attributes. */ - if (!pud_none(old_pud)) { - flush_tlb_all(); - if (pud_table(old_pud)) { - phys_addr_t table = pud_page_paddr(old_pud); - if (!WARN_ON_ONCE(slab_is_available())) - memblock_free(table, PAGE_SIZE); - } - } + BUG_ON(!pgattr_change_is_safe(pud_val(old_pud), + pud_val(*pud))); } else { alloc_init_pmd(pud, addr, next, phys, prot, pgtable_alloc, allow_block_mappings); + + BUG_ON(pud_val(old_pud) != 0 && + pud_val(old_pud) != pud_val(*pud)); } phys += next - addr; } while (pud++, addr = next, addr != end); @@ -396,6 +409,9 @@ void mark_rodata_ro(void) section_size = (unsigned long)__init_begin - (unsigned long)__start_rodata; create_mapping_late(__pa(__start_rodata), (unsigned long)__start_rodata, section_size, PAGE_KERNEL_RO); + + /* flush the TLBs after updating live kernel mappings */ + flush_tlb_all(); } static void __init map_kernel_segment(pgd_t *pgd, void *va_start, void *va_end,