From: Ard Biesheuvel <ardb+git@google.com>
To: linux-kernel@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org, Ard Biesheuvel <ardb@kernel.org>
Subject: [RFC PATCH v2 1/4] arm64: mm: Map fixmap PTE tables r/o in the linear map
Date: Thu, 27 Aug 2026 18:44:11 +0200 [thread overview]
Message-ID: <20260827164409.3421848-7-ardb+git@google.com> (raw)
In-Reply-To: <20260827164409.3421848-6-ardb+git@google.com>
From: Ard Biesheuvel <ardb@kernel.org>
Without physical KASLR, the fixmap page tables will appear at an a
priori known offset in the physical address space, and due to the lack
of randomization, the linear map carries a writeable alias of the fixmap
PTE pages, which appears at an offset in the kernel VA space that is
also predictable.
Given that the placement of the fixmap area is never randomized either,
a single store to this linear alias region is sufficient to map any
physical page with any permissions at a known offset in the kernel VA
space, including on top of the PTI trampoline.
Avoid this, by remapping the fixmap PTE pages read-only in the linear
map. This is possible because all updates to bm_pte[] occur via the
mapping of the kernel image in the vmap area. A read-only mapping is
still needed for things like ptdump that walk the page tables.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/arm64/include/asm/fixmap.h | 3 +++
arch/arm64/mm/fixmap.c | 8 +++++---
arch/arm64/mm/mmu.c | 8 ++++++++
3 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h
index 170c3502d723..9191125738e9 100644
--- a/arch/arm64/include/asm/fixmap.h
+++ b/arch/arm64/include/asm/fixmap.h
@@ -112,6 +112,9 @@ enum fixed_addresses {
void __init early_fixmap_init(void);
+extern pte_t fixmap_bm_pte[][PTRS_PER_PTE];
+extern const size_t fixmap_bm_pte_size;
+
#define __early_set_fixmap __set_fixmap
extern void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot);
diff --git a/arch/arm64/mm/fixmap.c b/arch/arm64/mm/fixmap.c
index f66a0016dd02..3a8cf6de6a7d 100644
--- a/arch/arm64/mm/fixmap.c
+++ b/arch/arm64/mm/fixmap.c
@@ -31,13 +31,15 @@ static_assert(NR_BM_PMD_TABLES == 1);
#define BM_PTE_TABLE_IDX(addr) __BM_TABLE_IDX(addr, PMD_SHIFT)
-static pte_t bm_pte[NR_BM_PTE_TABLES][PTRS_PER_PTE] __bss_pgtbl;
+pte_t fixmap_bm_pte[NR_BM_PTE_TABLES][PTRS_PER_PTE] __bss_pgtbl;
static pmd_t bm_pmd[PTRS_PER_PMD] __bss_pgtbl __maybe_unused;
static pud_t bm_pud[PTRS_PER_PUD] __bss_pgtbl __maybe_unused;
+const size_t fixmap_bm_pte_size = sizeof(fixmap_bm_pte);
+
static inline pte_t *fixmap_pte(unsigned long addr)
{
- return &bm_pte[BM_PTE_TABLE_IDX(addr)][pte_index(addr)];
+ return &fixmap_bm_pte[BM_PTE_TABLE_IDX(addr)][pte_index(addr)];
}
static void __init early_fixmap_init_pte(pmd_t *pmdp, unsigned long addr)
@@ -46,7 +48,7 @@ static void __init early_fixmap_init_pte(pmd_t *pmdp, unsigned long addr)
pte_t *ptep;
if (pmd_none(pmd)) {
- ptep = bm_pte[BM_PTE_TABLE_IDX(addr)];
+ ptep = fixmap_bm_pte[BM_PTE_TABLE_IDX(addr)];
__pmd_populate(pmdp, __pa_symbol(ptep),
PMD_TYPE_TABLE | PMD_TABLE_AF);
}
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 79d90226fd5d..9c1aa838e9d5 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -1184,6 +1184,7 @@ static void __init map_mem(void)
phys_addr_t init_begin = __pa_symbol(__init_begin);
phys_addr_t init_end = __pa_symbol(__init_end);
phys_addr_t kernel_end = __pa_symbol(__bss_stop);
+ phys_addr_t fixmap_pte_base = __pa_symbol(fixmap_bm_pte);
phys_addr_t start, end;
int flags = NO_EXEC_MAPPINGS;
u64 i;
@@ -1225,6 +1226,9 @@ static void __init map_mem(void)
__map_memblock(init_end, kernel_end, pgprot_tagged(PAGE_KERNEL),
flags);
+ __map_memblock(fixmap_pte_base, fixmap_pte_base + fixmap_bm_pte_size,
+ pgprot_tagged(PAGE_KERNEL), flags);
+
/* map all the memory banks */
for_each_mem_range(i, &start, &end) {
/*
@@ -1268,6 +1272,10 @@ void mark_rodata_ro(void)
(unsigned long)_stext - (unsigned long)_text,
PAGE_KERNEL_RO);
+ update_mapping_prot(__pa_symbol(fixmap_bm_pte),
+ (unsigned long)lm_alias(fixmap_bm_pte),
+ fixmap_bm_pte_size, PAGE_KERNEL_RO);
+
/* Map the kernel data/bss as invalid in the linear map */
mark_linear_data_alias_valid(false);
}
--
2.55.0.887.g758fc8c411-goog
next prev parent reply other threads:[~2026-08-27 16:44 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-27 16:44 [RFC PATCH v2 0/4] arm64: mm: Map fixmap page tables read-only Ard Biesheuvel
2026-08-27 16:44 ` Ard Biesheuvel [this message]
2026-08-27 16:44 ` [RFC PATCH v2 2/4] arm64: mm: Use fault handler to permit swapper_pg_dir updates Ard Biesheuvel
2026-08-27 16:44 ` [RFC PATCH v2 3/4] arm64: mm: Create r/o page table region that permits updates Ard Biesheuvel
2026-08-27 16:44 ` [RFC PATCH v2 4/4] arm64: mm: Move fixmap intermediate page tables into .rodata Ard Biesheuvel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260827164409.3421848-7-ardb+git@google.com \
--to=ardb+git@google.com \
--cc=ardb@kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox