* [PATCH v2 00/10] arm64: Unmap linear alias of kernel data/bss
@ 2026-01-26 9:26 Ard Biesheuvel
2026-01-26 9:26 ` [PATCH v2 01/10] arm64: Move the zero page to rodata Ard Biesheuvel
` (9 more replies)
0 siblings, 10 replies; 38+ messages in thread
From: Ard Biesheuvel @ 2026-01-26 9:26 UTC (permalink / raw)
To: linux-kernel
Cc: linux-arm-kernel, will, catalin.marinas, mark.rutland,
Ard Biesheuvel, Ryan Roberts, Anshuman Khandual, Liz Prucka,
Seth Jenkins, Kees Cook, linux-hardening
From: Ard Biesheuvel <ardb@kernel.org>
One of the reasons the lack of randomization of the linear map on arm64
is considered problematic is the fact that bootloaders adhering to the
original arm64 boot protocol may place the kernel at the base of DRAM,
and therefore at the base of the non-randomized linear map. This puts a
writable alias of the kernel's data and bss regions at a predictable
location, removing the need for an attacker to guess where KASLR mapped
the kernel.
Let's unmap this linear, writable alias entirely, so that knowing the
location of the linear alias does not give write access to the kernel's
data and bss regions.
Changes since v1:
- Put zero page patch at the start of the series
- Tweak __map_memblock() API to respect existing table and contiguous
mappings, so that the logic to map the kernel alias can be simplified
- Stop abusing the MEMBLOCK_NOMAP flag to initially omit the kernel
linear alias from the linear map
- Some additional cleanup patches
- Use proper API [set_memory_valid()] to (un)map the linear alias of
data/bss.
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: Anshuman Khandual <anshuman.khandual@arm.com>
Cc: Liz Prucka <lizprucka@google.com>
Cc: Seth Jenkins <sethjenkins@google.com>
Cc: Kees Cook <kees@kernel.org>
Cc: linux-hardening@vger.kernel.org
Ard Biesheuvel (10):
arm64: Move the zero page to rodata
arm64: Move fixmap page tables to end of kernel image
arm64: mm: Permit contiguous descriptors to be rewritten
arm64: mm: Preserve existing table mappings when mapping DRAM
arm64: mm: Preserve non-contiguous descriptors when mapping DRAM
arm64: mm: Remove bogus stop condition from map_mem() loop
arm64: mm: Drop redundant pgd_t* argument from map_mem()
arm64: mm: Don't abuse memblock NOMAP to check for overlaps
arm64: mm: Map the kernel data/bss read-only in the linear map
arm64: mm: Unmap kernel data/bss entirely from the linear map
arch/arm64/include/asm/pgtable.h | 4 +
arch/arm64/include/asm/sections.h | 1 +
arch/arm64/kernel/vmlinux.lds.S | 6 ++
arch/arm64/mm/fixmap.c | 7 +-
arch/arm64/mm/mmu.c | 111 +++++++++++++-------
5 files changed, 87 insertions(+), 42 deletions(-)
base-commit: f8261772d6a032f18aacd4d1a18bca5bd4e4a368
--
2.52.0.457.g6b5491de43-goog
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH v2 01/10] arm64: Move the zero page to rodata
2026-01-26 9:26 [PATCH v2 00/10] arm64: Unmap linear alias of kernel data/bss Ard Biesheuvel
@ 2026-01-26 9:26 ` Ard Biesheuvel
2026-01-27 9:34 ` Ryan Roberts
2026-01-26 9:26 ` [PATCH v2 02/10] arm64: Move fixmap page tables to end of kernel image Ard Biesheuvel
` (8 subsequent siblings)
9 siblings, 1 reply; 38+ messages in thread
From: Ard Biesheuvel @ 2026-01-26 9:26 UTC (permalink / raw)
To: linux-kernel
Cc: linux-arm-kernel, will, catalin.marinas, mark.rutland,
Ard Biesheuvel, Ryan Roberts, Anshuman Khandual, Liz Prucka,
Seth Jenkins, Kees Cook, linux-hardening
From: Ard Biesheuvel <ardb@kernel.org>
The zero page should contain only zero bytes, and so mapping it
read-write is unnecessary. Combine it with reserved_pg_dir, which lives
in the read-only region of the kernel, and already serves a similar
purpose.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/arm64/kernel/vmlinux.lds.S | 1 +
arch/arm64/mm/mmu.c | 3 +--
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index ad6133b89e7a..b2a093f5b3fc 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -229,6 +229,7 @@ SECTIONS
#endif
reserved_pg_dir = .;
+ empty_zero_page = .;
. += PAGE_SIZE;
swapper_pg_dir = .;
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 9ae7ce00a7ef..c36422a3fae2 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -66,9 +66,8 @@ long __section(".mmuoff.data.write") __early_cpu_boot_status;
/*
* Empty_zero_page is a special page that is used for zero-initialized data
- * and COW.
+ * and COW. Defined in the linker script.
*/
-unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)] __page_aligned_bss;
EXPORT_SYMBOL(empty_zero_page);
static DEFINE_SPINLOCK(swapper_pgdir_lock);
--
2.52.0.457.g6b5491de43-goog
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH v2 02/10] arm64: Move fixmap page tables to end of kernel image
2026-01-26 9:26 [PATCH v2 00/10] arm64: Unmap linear alias of kernel data/bss Ard Biesheuvel
2026-01-26 9:26 ` [PATCH v2 01/10] arm64: Move the zero page to rodata Ard Biesheuvel
@ 2026-01-26 9:26 ` Ard Biesheuvel
2026-01-27 9:42 ` Ryan Roberts
2026-01-26 9:26 ` [PATCH v2 03/10] arm64: mm: Permit contiguous descriptors to be rewritten Ard Biesheuvel
` (7 subsequent siblings)
9 siblings, 1 reply; 38+ messages in thread
From: Ard Biesheuvel @ 2026-01-26 9:26 UTC (permalink / raw)
To: linux-kernel
Cc: linux-arm-kernel, will, catalin.marinas, mark.rutland,
Ard Biesheuvel, Ryan Roberts, Anshuman Khandual, Liz Prucka,
Seth Jenkins, Kees Cook, linux-hardening
From: Ard Biesheuvel <ardb@kernel.org>
Move the fixmap page tables out of the BSS section, and place them at
the end of the image, right before the init_pg_dir section where some of
the other statically allocated page tables live.
These page tables are currently the only data objects in vmlinux that
are meant to be accessed via the kernel image's linear alias, and so
placing them together allows the remainder of the data/bss section to be
remapped read-only or unmapped entirely.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/arm64/kernel/vmlinux.lds.S | 5 +++++
arch/arm64/mm/fixmap.c | 7 ++++---
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index b2a093f5b3fc..c089b83308a5 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -335,6 +335,11 @@ SECTIONS
__pi___bss_start = __bss_start;
. = ALIGN(PAGE_SIZE);
+ .pgdir : {
+ __pgdir_start = .;
+ *(.fixmap_bss)
+ }
+
__pi_init_pg_dir = .;
. += INIT_DIR_SIZE;
__pi_init_pg_end = .;
diff --git a/arch/arm64/mm/fixmap.c b/arch/arm64/mm/fixmap.c
index c5c5425791da..b649ea1a46e4 100644
--- a/arch/arm64/mm/fixmap.c
+++ b/arch/arm64/mm/fixmap.c
@@ -31,9 +31,10 @@ 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] __page_aligned_bss;
-static pmd_t bm_pmd[PTRS_PER_PMD] __page_aligned_bss __maybe_unused;
-static pud_t bm_pud[PTRS_PER_PUD] __page_aligned_bss __maybe_unused;
+#define __fixmap_bss __section(".fixmap_bss") __aligned(PAGE_SIZE)
+static pte_t bm_pte[NR_BM_PTE_TABLES][PTRS_PER_PTE] __fixmap_bss;
+static pmd_t bm_pmd[PTRS_PER_PMD] __fixmap_bss __maybe_unused;
+static pud_t bm_pud[PTRS_PER_PUD] __fixmap_bss __maybe_unused;
static inline pte_t *fixmap_pte(unsigned long addr)
{
--
2.52.0.457.g6b5491de43-goog
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH v2 03/10] arm64: mm: Permit contiguous descriptors to be rewritten
2026-01-26 9:26 [PATCH v2 00/10] arm64: Unmap linear alias of kernel data/bss Ard Biesheuvel
2026-01-26 9:26 ` [PATCH v2 01/10] arm64: Move the zero page to rodata Ard Biesheuvel
2026-01-26 9:26 ` [PATCH v2 02/10] arm64: Move fixmap page tables to end of kernel image Ard Biesheuvel
@ 2026-01-26 9:26 ` Ard Biesheuvel
2026-01-27 9:45 ` Ryan Roberts
2026-01-26 9:26 ` [PATCH v2 04/10] arm64: mm: Preserve existing table mappings when mapping DRAM Ard Biesheuvel
` (6 subsequent siblings)
9 siblings, 1 reply; 38+ messages in thread
From: Ard Biesheuvel @ 2026-01-26 9:26 UTC (permalink / raw)
To: linux-kernel
Cc: linux-arm-kernel, will, catalin.marinas, mark.rutland,
Ard Biesheuvel, Ryan Roberts, Anshuman Khandual, Liz Prucka,
Seth Jenkins, Kees Cook, linux-hardening
From: Ard Biesheuvel <ardb@kernel.org>
Currently, pgattr_change_is_safe() is overly pedantic when it comes to
descriptors with the contiguous hint attribute set, as it rejects
assignments even if the old and the new value are the same.
So relax the check to allow that.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/arm64/mm/mmu.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index c36422a3fae2..9d39de3cfe67 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -141,7 +141,7 @@ bool pgattr_change_is_safe(pteval_t old, pteval_t new)
return false;
/* live contiguous mappings may not be manipulated at all */
- if ((old | new) & PTE_CONT)
+ if ((old | new) & PTE_CONT && old != new)
return false;
/* Transitioning from Non-Global to Global is unsafe */
--
2.52.0.457.g6b5491de43-goog
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH v2 04/10] arm64: mm: Preserve existing table mappings when mapping DRAM
2026-01-26 9:26 [PATCH v2 00/10] arm64: Unmap linear alias of kernel data/bss Ard Biesheuvel
` (2 preceding siblings ...)
2026-01-26 9:26 ` [PATCH v2 03/10] arm64: mm: Permit contiguous descriptors to be rewritten Ard Biesheuvel
@ 2026-01-26 9:26 ` Ard Biesheuvel
2026-01-27 9:58 ` Ryan Roberts
2026-01-26 9:26 ` [PATCH v2 05/10] arm64: mm: Preserve non-contiguous descriptors " Ard Biesheuvel
` (5 subsequent siblings)
9 siblings, 1 reply; 38+ messages in thread
From: Ard Biesheuvel @ 2026-01-26 9:26 UTC (permalink / raw)
To: linux-kernel
Cc: linux-arm-kernel, will, catalin.marinas, mark.rutland,
Ard Biesheuvel, Ryan Roberts, Anshuman Khandual, Liz Prucka,
Seth Jenkins, Kees Cook, linux-hardening
From: Ard Biesheuvel <ardb@kernel.org>
Instead of blindly overwriting an existing table entry when mapping DRAM
regions, take care not to replace a pre-existing table entry with a
block entry. This permits the logic of mapping the kernel's linear alias
to be simplified in a subsequent patch.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/arm64/mm/mmu.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 9d39de3cfe67..28cc3cda042c 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -262,7 +262,8 @@ static int init_pmd(pmd_t *pmdp, unsigned long addr, unsigned long end,
/* try section mapping first */
if (((addr | next | phys) & ~PMD_MASK) == 0 &&
- (flags & NO_BLOCK_MAPPINGS) == 0) {
+ (flags & NO_BLOCK_MAPPINGS) == 0 &&
+ !pmd_table(old_pmd)) {
pmd_set_huge(pmdp, phys, prot);
/*
@@ -385,7 +386,8 @@ static int alloc_init_pud(p4d_t *p4dp, unsigned long addr, unsigned long end,
*/
if (pud_sect_supported() &&
((addr | next | phys) & ~PUD_MASK) == 0 &&
- (flags & NO_BLOCK_MAPPINGS) == 0) {
+ (flags & NO_BLOCK_MAPPINGS) == 0 &&
+ !pud_table(old_pud)) {
pud_set_huge(pudp, phys, prot);
/*
--
2.52.0.457.g6b5491de43-goog
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH v2 05/10] arm64: mm: Preserve non-contiguous descriptors when mapping DRAM
2026-01-26 9:26 [PATCH v2 00/10] arm64: Unmap linear alias of kernel data/bss Ard Biesheuvel
` (3 preceding siblings ...)
2026-01-26 9:26 ` [PATCH v2 04/10] arm64: mm: Preserve existing table mappings when mapping DRAM Ard Biesheuvel
@ 2026-01-26 9:26 ` Ard Biesheuvel
2026-01-27 9:58 ` Ryan Roberts
2026-01-26 9:26 ` [PATCH v2 06/10] arm64: mm: Remove bogus stop condition from map_mem() loop Ard Biesheuvel
` (4 subsequent siblings)
9 siblings, 1 reply; 38+ messages in thread
From: Ard Biesheuvel @ 2026-01-26 9:26 UTC (permalink / raw)
To: linux-kernel
Cc: linux-arm-kernel, will, catalin.marinas, mark.rutland,
Ard Biesheuvel, Ryan Roberts, Anshuman Khandual, Liz Prucka,
Seth Jenkins, Kees Cook, linux-hardening
From: Ard Biesheuvel <ardb@kernel.org>
Instead of blindly overwriting existing live entries with the contiguous
bit cleared when mapping DRAM regions, check whether the contiguous
region in question starts with a descriptor that has the valid bit set
and the contiguous bit cleared, and in that case, leave the contiguous
bit unset on the entire region. This permits the logic of mapping the
kernel's linear alias to be simplified in a subsequent patch.
Note that not setting the contiguous bit on any of the descriptors in
the contiguous region can only result in an invalid configuration if it
was already invalid to begin with.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/arm64/include/asm/pgtable.h | 4 ++++
arch/arm64/mm/mmu.c | 6 ++++--
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 64d5f1d9cce9..cb2c4525e49a 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -224,6 +224,10 @@ static inline pteval_t __phys_to_pte_val(phys_addr_t phys)
* Returns true if the pte is valid and has the contiguous bit set.
*/
#define pte_valid_cont(pte) (pte_valid(pte) && pte_cont(pte))
+/*
+ * Returns true if the pte is valid and has the contiguous bit cleared.
+ */
+#define pte_valid_noncont(pte) (pte_valid(pte) && !pte_cont(pte))
/*
* Could the pte be present in the TLB? We must check mm_tlb_flush_pending
* so that we don't erroneously return false for pages that have been
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 28cc3cda042c..d7faa98f427c 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -230,7 +230,8 @@ static int alloc_init_cont_pte(pmd_t *pmdp, unsigned long addr,
/* use a contiguous mapping if the range is suitably aligned */
if ((((addr | next | phys) & ~CONT_PTE_MASK) == 0) &&
- (flags & NO_CONT_MAPPINGS) == 0)
+ (flags & NO_CONT_MAPPINGS) == 0 &&
+ !pte_valid_noncont(__ptep_get(ptep)))
__prot = __pgprot(pgprot_val(prot) | PTE_CONT);
init_pte(ptep, addr, next, phys, __prot);
@@ -330,7 +331,8 @@ static int alloc_init_cont_pmd(pud_t *pudp, unsigned long addr,
/* use a contiguous mapping if the range is suitably aligned */
if ((((addr | next | phys) & ~CONT_PMD_MASK) == 0) &&
- (flags & NO_CONT_MAPPINGS) == 0)
+ (flags & NO_CONT_MAPPINGS) == 0 &&
+ !pte_valid_noncont(pmd_pte(READ_ONCE(*pmdp))))
__prot = __pgprot(pgprot_val(prot) | PTE_CONT);
ret = init_pmd(pmdp, addr, next, phys, __prot, pgtable_alloc, flags);
--
2.52.0.457.g6b5491de43-goog
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH v2 06/10] arm64: mm: Remove bogus stop condition from map_mem() loop
2026-01-26 9:26 [PATCH v2 00/10] arm64: Unmap linear alias of kernel data/bss Ard Biesheuvel
` (4 preceding siblings ...)
2026-01-26 9:26 ` [PATCH v2 05/10] arm64: mm: Preserve non-contiguous descriptors " Ard Biesheuvel
@ 2026-01-26 9:26 ` Ard Biesheuvel
2026-01-27 10:06 ` Ryan Roberts
2026-01-26 9:26 ` [PATCH v2 07/10] arm64: mm: Drop redundant pgd_t* argument from map_mem() Ard Biesheuvel
` (3 subsequent siblings)
9 siblings, 1 reply; 38+ messages in thread
From: Ard Biesheuvel @ 2026-01-26 9:26 UTC (permalink / raw)
To: linux-kernel
Cc: linux-arm-kernel, will, catalin.marinas, mark.rutland,
Ard Biesheuvel, Ryan Roberts, Anshuman Khandual, Liz Prucka,
Seth Jenkins, Kees Cook, linux-hardening
From: Ard Biesheuvel <ardb@kernel.org>
The memblock API guarantees that start is not greater than or equal to
end, so there is no need to test it. And if were, it is doubtful that
breaking out of the loop would be a reasonable course of action here
(rather than attempting to map the remaining regions)
So let's drop this check.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/arm64/mm/mmu.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index d7faa98f427c..377bdc4d84a1 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -1158,8 +1158,6 @@ static void __init map_mem(pgd_t *pgdp)
/* map all the memory banks */
for_each_mem_range(i, &start, &end) {
- if (start >= end)
- break;
/*
* The linear map must allow allocation tags reading/writing
* if MTE is present. Otherwise, it has the same attributes as
--
2.52.0.457.g6b5491de43-goog
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH v2 07/10] arm64: mm: Drop redundant pgd_t* argument from map_mem()
2026-01-26 9:26 [PATCH v2 00/10] arm64: Unmap linear alias of kernel data/bss Ard Biesheuvel
` (5 preceding siblings ...)
2026-01-26 9:26 ` [PATCH v2 06/10] arm64: mm: Remove bogus stop condition from map_mem() loop Ard Biesheuvel
@ 2026-01-26 9:26 ` Ard Biesheuvel
2026-01-27 10:10 ` Ryan Roberts
2026-01-26 9:26 ` [PATCH v2 08/10] arm64: mm: Don't abuse memblock NOMAP to check for overlaps Ard Biesheuvel
` (2 subsequent siblings)
9 siblings, 1 reply; 38+ messages in thread
From: Ard Biesheuvel @ 2026-01-26 9:26 UTC (permalink / raw)
To: linux-kernel
Cc: linux-arm-kernel, will, catalin.marinas, mark.rutland,
Ard Biesheuvel, Ryan Roberts, Anshuman Khandual, Liz Prucka,
Seth Jenkins, Kees Cook, linux-hardening
From: Ard Biesheuvel <ardb@kernel.org>
__map_memblock() and map_mem() always operate on swapper_pg_dir, so
there is no need to pass around a pgd_t pointer between them.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/arm64/mm/mmu.c | 25 ++++++++++----------
1 file changed, 12 insertions(+), 13 deletions(-)
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 377bdc4d84a1..80587cd47ce7 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -1020,11 +1020,11 @@ static void update_mapping_prot(phys_addr_t phys, unsigned long virt,
flush_tlb_kernel_range(virt, virt + size);
}
-static void __init __map_memblock(pgd_t *pgdp, phys_addr_t start,
- phys_addr_t end, pgprot_t prot, int flags)
+static void __init __map_memblock(phys_addr_t start, phys_addr_t end,
+ pgprot_t prot, int flags)
{
- early_create_pgd_mapping(pgdp, start, __phys_to_virt(start), end - start,
- prot, early_pgtable_alloc, flags);
+ early_create_pgd_mapping(swapper_pg_dir, start, __phys_to_virt(start),
+ end - start, prot, early_pgtable_alloc, flags);
}
void __init mark_linear_text_alias_ro(void)
@@ -1072,13 +1072,13 @@ static phys_addr_t __init arm64_kfence_alloc_pool(void)
return kfence_pool;
}
-static void __init arm64_kfence_map_pool(phys_addr_t kfence_pool, pgd_t *pgdp)
+static void __init arm64_kfence_map_pool(phys_addr_t kfence_pool)
{
if (!kfence_pool)
return;
/* KFENCE pool needs page-level mapping. */
- __map_memblock(pgdp, kfence_pool, kfence_pool + KFENCE_POOL_SIZE,
+ __map_memblock(kfence_pool, kfence_pool + KFENCE_POOL_SIZE,
pgprot_tagged(PAGE_KERNEL),
NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS);
memblock_clear_nomap(kfence_pool, KFENCE_POOL_SIZE);
@@ -1114,11 +1114,11 @@ bool arch_kfence_init_pool(void)
#else /* CONFIG_KFENCE */
static inline phys_addr_t arm64_kfence_alloc_pool(void) { return 0; }
-static inline void arm64_kfence_map_pool(phys_addr_t kfence_pool, pgd_t *pgdp) { }
+static inline void arm64_kfence_map_pool(phys_addr_t kfence_pool) { }
#endif /* CONFIG_KFENCE */
-static void __init map_mem(pgd_t *pgdp)
+static void __init map_mem(void)
{
static const u64 direct_map_end = _PAGE_END(VA_BITS_MIN);
phys_addr_t kernel_start = __pa_symbol(_text);
@@ -1163,7 +1163,7 @@ static void __init map_mem(pgd_t *pgdp)
* if MTE is present. Otherwise, it has the same attributes as
* PAGE_KERNEL.
*/
- __map_memblock(pgdp, start, end, pgprot_tagged(PAGE_KERNEL),
+ __map_memblock(start, end, pgprot_tagged(PAGE_KERNEL),
flags);
}
@@ -1177,10 +1177,9 @@ static void __init map_mem(pgd_t *pgdp)
* Note that contiguous mappings cannot be remapped in this way,
* so we should avoid them here.
*/
- __map_memblock(pgdp, kernel_start, kernel_end,
- PAGE_KERNEL, NO_CONT_MAPPINGS);
+ __map_memblock(kernel_start, kernel_end, PAGE_KERNEL, NO_CONT_MAPPINGS);
memblock_clear_nomap(kernel_start, kernel_end - kernel_start);
- arm64_kfence_map_pool(early_kfence_pool, pgdp);
+ arm64_kfence_map_pool(early_kfence_pool);
}
void mark_rodata_ro(void)
@@ -1402,7 +1401,7 @@ static void __init create_idmap(void)
void __init paging_init(void)
{
- map_mem(swapper_pg_dir);
+ map_mem();
memblock_allow_resize();
--
2.52.0.457.g6b5491de43-goog
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH v2 08/10] arm64: mm: Don't abuse memblock NOMAP to check for overlaps
2026-01-26 9:26 [PATCH v2 00/10] arm64: Unmap linear alias of kernel data/bss Ard Biesheuvel
` (6 preceding siblings ...)
2026-01-26 9:26 ` [PATCH v2 07/10] arm64: mm: Drop redundant pgd_t* argument from map_mem() Ard Biesheuvel
@ 2026-01-26 9:26 ` Ard Biesheuvel
2026-01-27 10:21 ` Ryan Roberts
2026-01-26 9:26 ` [PATCH v2 09/10] arm64: mm: Map the kernel data/bss read-only in the linear map Ard Biesheuvel
2026-01-26 9:26 ` [PATCH v2 10/10] arm64: mm: Unmap kernel data/bss entirely from " Ard Biesheuvel
9 siblings, 1 reply; 38+ messages in thread
From: Ard Biesheuvel @ 2026-01-26 9:26 UTC (permalink / raw)
To: linux-kernel
Cc: linux-arm-kernel, will, catalin.marinas, mark.rutland,
Ard Biesheuvel, Ryan Roberts, Anshuman Khandual, Liz Prucka,
Seth Jenkins, Kees Cook, linux-hardening
From: Ard Biesheuvel <ardb@kernel.org>
Now that the DRAM mapping routines respect existing table mappings and
contiguous block and page mappings, it is no longer needed to fiddle
with the memblock tables to set and clear the NOMAP attribute. Instead,
map the kernel text and rodata alias first, avoiding contiguous
mappings, so that they will not be added later when mapping the
memblocks.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/arm64/mm/mmu.c | 27 ++++++++------------
1 file changed, 10 insertions(+), 17 deletions(-)
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 80587cd47ce7..18415d4743bf 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -1149,12 +1149,17 @@ static void __init map_mem(void)
flags |= NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS;
/*
- * Take care not to create a writable alias for the
- * read-only text and rodata sections of the kernel image.
- * So temporarily mark them as NOMAP to skip mappings in
- * the following for-loop
+ * Map the linear alias of the [_text, __init_begin) interval
+ * as non-executable now, and remove the write permission in
+ * mark_linear_text_alias_ro() above (which will be called after
+ * alternative patching has completed). This makes the contents
+ * of the region accessible to subsystems such as hibernate,
+ * but protects it from inadvertent modification or execution.
+ * Note that contiguous mappings cannot be remapped in this way,
+ * so we should avoid them here.
*/
- memblock_mark_nomap(kernel_start, kernel_end - kernel_start);
+ __map_memblock(kernel_start, kernel_end, PAGE_KERNEL,
+ flags | NO_CONT_MAPPINGS);
/* map all the memory banks */
for_each_mem_range(i, &start, &end) {
@@ -1167,18 +1172,6 @@ static void __init map_mem(void)
flags);
}
- /*
- * Map the linear alias of the [_text, __init_begin) interval
- * as non-executable now, and remove the write permission in
- * mark_linear_text_alias_ro() below (which will be called after
- * alternative patching has completed). This makes the contents
- * of the region accessible to subsystems such as hibernate,
- * but protects it from inadvertent modification or execution.
- * Note that contiguous mappings cannot be remapped in this way,
- * so we should avoid them here.
- */
- __map_memblock(kernel_start, kernel_end, PAGE_KERNEL, NO_CONT_MAPPINGS);
- memblock_clear_nomap(kernel_start, kernel_end - kernel_start);
arm64_kfence_map_pool(early_kfence_pool);
}
--
2.52.0.457.g6b5491de43-goog
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH v2 09/10] arm64: mm: Map the kernel data/bss read-only in the linear map
2026-01-26 9:26 [PATCH v2 00/10] arm64: Unmap linear alias of kernel data/bss Ard Biesheuvel
` (7 preceding siblings ...)
2026-01-26 9:26 ` [PATCH v2 08/10] arm64: mm: Don't abuse memblock NOMAP to check for overlaps Ard Biesheuvel
@ 2026-01-26 9:26 ` Ard Biesheuvel
2026-01-27 10:33 ` Ryan Roberts
2026-01-26 9:26 ` [PATCH v2 10/10] arm64: mm: Unmap kernel data/bss entirely from " Ard Biesheuvel
9 siblings, 1 reply; 38+ messages in thread
From: Ard Biesheuvel @ 2026-01-26 9:26 UTC (permalink / raw)
To: linux-kernel
Cc: linux-arm-kernel, will, catalin.marinas, mark.rutland,
Ard Biesheuvel, Ryan Roberts, Anshuman Khandual, Liz Prucka,
Seth Jenkins, Kees Cook, linux-hardening
From: Ard Biesheuvel <ardb@kernel.org>
On systems where the bootloader adheres to the original arm64 boot
protocol, the placement of the kernel in the physical address space is
highly predictable, and this makes the placement of its linear alias in
the kernel virtual address space equally predictable, given the lack of
randomization of the linear map.
The linear aliases of the kernel text and rodata regions are already
mapped read-only, but the kernel data and bss are mapped read-write in
this region. This is not needed, so map them read-only as well.
Note that the statically allocated kernel page tables do need to be
modifiable via the linear map, so leave these mapped read-write.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/arm64/include/asm/sections.h | 1 +
arch/arm64/mm/mmu.c | 10 ++++++++--
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/include/asm/sections.h b/arch/arm64/include/asm/sections.h
index 51b0d594239e..f7fe2bcbfd03 100644
--- a/arch/arm64/include/asm/sections.h
+++ b/arch/arm64/include/asm/sections.h
@@ -23,6 +23,7 @@ extern char __irqentry_text_start[], __irqentry_text_end[];
extern char __mmuoff_data_start[], __mmuoff_data_end[];
extern char __entry_tramp_text_start[], __entry_tramp_text_end[];
extern char __relocate_new_kernel_start[], __relocate_new_kernel_end[];
+extern char __pgdir_start[];
static inline size_t entry_tramp_text_size(void)
{
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 18415d4743bf..fdbbb018adc5 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -1122,7 +1122,9 @@ static void __init map_mem(void)
{
static const u64 direct_map_end = _PAGE_END(VA_BITS_MIN);
phys_addr_t kernel_start = __pa_symbol(_text);
- phys_addr_t kernel_end = __pa_symbol(__init_begin);
+ 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(__pgdir_start);
phys_addr_t start, end;
phys_addr_t early_kfence_pool;
int flags = NO_EXEC_MAPPINGS;
@@ -1158,7 +1160,9 @@ static void __init map_mem(void)
* Note that contiguous mappings cannot be remapped in this way,
* so we should avoid them here.
*/
- __map_memblock(kernel_start, kernel_end, PAGE_KERNEL,
+ __map_memblock(kernel_start, init_begin, PAGE_KERNEL,
+ flags | NO_CONT_MAPPINGS);
+ __map_memblock(init_end, kernel_end, PAGE_KERNEL,
flags | NO_CONT_MAPPINGS);
/* map all the memory banks */
@@ -1172,6 +1176,8 @@ static void __init map_mem(void)
flags);
}
+ __map_memblock(init_end, kernel_end, PAGE_KERNEL_RO,
+ flags | NO_CONT_MAPPINGS);
arm64_kfence_map_pool(early_kfence_pool);
}
--
2.52.0.457.g6b5491de43-goog
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH v2 10/10] arm64: mm: Unmap kernel data/bss entirely from the linear map
2026-01-26 9:26 [PATCH v2 00/10] arm64: Unmap linear alias of kernel data/bss Ard Biesheuvel
` (8 preceding siblings ...)
2026-01-26 9:26 ` [PATCH v2 09/10] arm64: mm: Map the kernel data/bss read-only in the linear map Ard Biesheuvel
@ 2026-01-26 9:26 ` Ard Biesheuvel
2026-01-27 10:50 ` Ryan Roberts
9 siblings, 1 reply; 38+ messages in thread
From: Ard Biesheuvel @ 2026-01-26 9:26 UTC (permalink / raw)
To: linux-kernel
Cc: linux-arm-kernel, will, catalin.marinas, mark.rutland,
Ard Biesheuvel, Ryan Roberts, Anshuman Khandual, Liz Prucka,
Seth Jenkins, Kees Cook, linux-hardening
From: Ard Biesheuvel <ardb@kernel.org>
The linear aliases of the kernel text and rodata are mapped read-only in
the linear map as well. Given that the contents of these regions are
mostly identical to the version in the loadable image, mapping them
read-only and leaving their contents visible is a reasonable hardening
measure.
Data and bss, however, are now also mapped read-only but the contents of
these regions are more likely to contain data that we'd rather not leak.
So let's unmap these entirely in the linear map when the kernel is
running normally.
When going into hibernation or waking up from it, these regions need to
be mapped, so map the region initially, and toggle the valid bit so
map/unmap the region as needed.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/arm64/mm/mmu.c | 40 ++++++++++++++++++--
1 file changed, 37 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index fdbbb018adc5..06b2d11b4561 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -24,6 +24,7 @@
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/set_memory.h>
+#include <linux/suspend.h>
#include <linux/kfence.h>
#include <linux/pkeys.h>
#include <linux/mm_inline.h>
@@ -1027,6 +1028,31 @@ static void __init __map_memblock(phys_addr_t start, phys_addr_t end,
end - start, prot, early_pgtable_alloc, flags);
}
+static void remap_linear_data_alias(bool unmap)
+{
+ set_memory_valid((unsigned long)lm_alias(__init_end),
+ (unsigned long)(__pgdir_start - __init_end) / PAGE_SIZE,
+ !unmap);
+}
+
+static int arm64_hibernate_pm_notify(struct notifier_block *nb,
+ unsigned long mode, void *unused)
+{
+ switch (mode) {
+ default:
+ break;
+ case PM_POST_HIBERNATION:
+ case PM_POST_RESTORE:
+ remap_linear_data_alias(true);
+ break;
+ case PM_HIBERNATION_PREPARE:
+ case PM_RESTORE_PREPARE:
+ remap_linear_data_alias(false);
+ break;
+ }
+ return 0;
+}
+
void __init mark_linear_text_alias_ro(void)
{
/*
@@ -1035,6 +1061,16 @@ void __init mark_linear_text_alias_ro(void)
update_mapping_prot(__pa_symbol(_text), (unsigned long)lm_alias(_text),
(unsigned long)__init_begin - (unsigned long)_text,
PAGE_KERNEL_RO);
+
+ remap_linear_data_alias(true);
+
+ if (IS_ENABLED(CONFIG_HIBERNATION)) {
+ static struct notifier_block nb = {
+ .notifier_call = arm64_hibernate_pm_notify
+ };
+
+ register_pm_notifier(&nb);
+ }
}
#ifdef CONFIG_KFENCE
@@ -1163,7 +1199,7 @@ static void __init map_mem(void)
__map_memblock(kernel_start, init_begin, PAGE_KERNEL,
flags | NO_CONT_MAPPINGS);
__map_memblock(init_end, kernel_end, PAGE_KERNEL,
- flags | NO_CONT_MAPPINGS);
+ flags | NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS);
/* map all the memory banks */
for_each_mem_range(i, &start, &end) {
@@ -1176,8 +1212,6 @@ static void __init map_mem(void)
flags);
}
- __map_memblock(init_end, kernel_end, PAGE_KERNEL_RO,
- flags | NO_CONT_MAPPINGS);
arm64_kfence_map_pool(early_kfence_pool);
}
--
2.52.0.457.g6b5491de43-goog
^ permalink raw reply related [flat|nested] 38+ messages in thread
* Re: [PATCH v2 01/10] arm64: Move the zero page to rodata
2026-01-26 9:26 ` [PATCH v2 01/10] arm64: Move the zero page to rodata Ard Biesheuvel
@ 2026-01-27 9:34 ` Ryan Roberts
2026-01-27 9:49 ` Ard Biesheuvel
0 siblings, 1 reply; 38+ messages in thread
From: Ryan Roberts @ 2026-01-27 9:34 UTC (permalink / raw)
To: Ard Biesheuvel, linux-kernel
Cc: linux-arm-kernel, will, catalin.marinas, mark.rutland,
Ard Biesheuvel, Anshuman Khandual, Liz Prucka, Seth Jenkins,
Kees Cook, linux-hardening
On 26/01/2026 09:26, Ard Biesheuvel wrote:
> From: Ard Biesheuvel <ardb@kernel.org>
>
> The zero page should contain only zero bytes, and so mapping it
> read-write is unnecessary. Combine it with reserved_pg_dir, which lives
> in the read-only region of the kernel, and already serves a similar
> purpose.
>
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> ---
> arch/arm64/kernel/vmlinux.lds.S | 1 +
> arch/arm64/mm/mmu.c | 3 +--
> 2 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
> index ad6133b89e7a..b2a093f5b3fc 100644
> --- a/arch/arm64/kernel/vmlinux.lds.S
> +++ b/arch/arm64/kernel/vmlinux.lds.S
> @@ -229,6 +229,7 @@ SECTIONS
> #endif
>
> reserved_pg_dir = .;
> + empty_zero_page = .;
> . += PAGE_SIZE;
>
> swapper_pg_dir = .;
Isn't there a magic macro for getting from swapper to reserved? That will need
updating?
/*
* Open-coded (swapper_pg_dir - reserved_pg_dir) as this cannot be calculated
* until link time.
*/
#define RESERVED_SWAPPER_OFFSET (PAGE_SIZE)
> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> index 9ae7ce00a7ef..c36422a3fae2 100644
> --- a/arch/arm64/mm/mmu.c
> +++ b/arch/arm64/mm/mmu.c
> @@ -66,9 +66,8 @@ long __section(".mmuoff.data.write") __early_cpu_boot_status;
>
> /*
> * Empty_zero_page is a special page that is used for zero-initialized data
> - * and COW.
> + * and COW. Defined in the linker script.
> */
> -unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)] __page_aligned_bss;
> EXPORT_SYMBOL(empty_zero_page);
What's the benefit of giving it it's own place in the linker script vs just
declaring it as const and having it placed in the rodata?
Thanks,
Ryan
>
> static DEFINE_SPINLOCK(swapper_pgdir_lock);
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH v2 02/10] arm64: Move fixmap page tables to end of kernel image
2026-01-26 9:26 ` [PATCH v2 02/10] arm64: Move fixmap page tables to end of kernel image Ard Biesheuvel
@ 2026-01-27 9:42 ` Ryan Roberts
0 siblings, 0 replies; 38+ messages in thread
From: Ryan Roberts @ 2026-01-27 9:42 UTC (permalink / raw)
To: Ard Biesheuvel, linux-kernel
Cc: linux-arm-kernel, will, catalin.marinas, mark.rutland,
Ard Biesheuvel, Anshuman Khandual, Liz Prucka, Seth Jenkins,
Kees Cook, linux-hardening
On 26/01/2026 09:26, Ard Biesheuvel wrote:
> From: Ard Biesheuvel <ardb@kernel.org>
>
> Move the fixmap page tables out of the BSS section, and place them at
> the end of the image, right before the init_pg_dir section where some of
> the other statically allocated page tables live.
>
> These page tables are currently the only data objects in vmlinux that
> are meant to be accessed via the kernel image's linear alias, and so
> placing them together allows the remainder of the data/bss section to be
> remapped read-only or unmapped entirely.
>
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Reviewed-by: Ryan Roberts <ryan.roberts@arm.com>
> ---
> arch/arm64/kernel/vmlinux.lds.S | 5 +++++
> arch/arm64/mm/fixmap.c | 7 ++++---
> 2 files changed, 9 insertions(+), 3 deletions(-)
>
> diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
> index b2a093f5b3fc..c089b83308a5 100644
> --- a/arch/arm64/kernel/vmlinux.lds.S
> +++ b/arch/arm64/kernel/vmlinux.lds.S
> @@ -335,6 +335,11 @@ SECTIONS
> __pi___bss_start = __bss_start;
>
> . = ALIGN(PAGE_SIZE);
> + .pgdir : {
> + __pgdir_start = .;
> + *(.fixmap_bss)
> + }
Observing that this still gets zero-initialized:
/* Clear BSS and the initial page tables */
memset(__bss_start, 0, (char *)init_pg_end - (char *)__bss_start);
Thanks,
Ryan
> +
> __pi_init_pg_dir = .;
> . += INIT_DIR_SIZE;
> __pi_init_pg_end = .;
> diff --git a/arch/arm64/mm/fixmap.c b/arch/arm64/mm/fixmap.c
> index c5c5425791da..b649ea1a46e4 100644
> --- a/arch/arm64/mm/fixmap.c
> +++ b/arch/arm64/mm/fixmap.c
> @@ -31,9 +31,10 @@ 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] __page_aligned_bss;
> -static pmd_t bm_pmd[PTRS_PER_PMD] __page_aligned_bss __maybe_unused;
> -static pud_t bm_pud[PTRS_PER_PUD] __page_aligned_bss __maybe_unused;
> +#define __fixmap_bss __section(".fixmap_bss") __aligned(PAGE_SIZE)
> +static pte_t bm_pte[NR_BM_PTE_TABLES][PTRS_PER_PTE] __fixmap_bss;
> +static pmd_t bm_pmd[PTRS_PER_PMD] __fixmap_bss __maybe_unused;
> +static pud_t bm_pud[PTRS_PER_PUD] __fixmap_bss __maybe_unused;
>
> static inline pte_t *fixmap_pte(unsigned long addr)
> {
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH v2 03/10] arm64: mm: Permit contiguous descriptors to be rewritten
2026-01-26 9:26 ` [PATCH v2 03/10] arm64: mm: Permit contiguous descriptors to be rewritten Ard Biesheuvel
@ 2026-01-27 9:45 ` Ryan Roberts
2026-01-27 15:03 ` Ard Biesheuvel
0 siblings, 1 reply; 38+ messages in thread
From: Ryan Roberts @ 2026-01-27 9:45 UTC (permalink / raw)
To: Ard Biesheuvel, linux-kernel
Cc: linux-arm-kernel, will, catalin.marinas, mark.rutland,
Ard Biesheuvel, Anshuman Khandual, Liz Prucka, Seth Jenkins,
Kees Cook, linux-hardening
On 26/01/2026 09:26, Ard Biesheuvel wrote:
> From: Ard Biesheuvel <ardb@kernel.org>
>
> Currently, pgattr_change_is_safe() is overly pedantic when it comes to
> descriptors with the contiguous hint attribute set, as it rejects
> assignments even if the old and the new value are the same.
>
> So relax the check to allow that.
But why do we require the relaxation? Why are we re-writing a PTE in the first
place? Either the caller already knows it's the same in which case it can be
avoided, or it doesn't know in which case it is accidentally the same and couple
probably just as easily been accidentally different? So it's better to warn
regardless I would think?
I'm sure I'll get to the patch where this matters and change my mind :)
>
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> ---
> arch/arm64/mm/mmu.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> index c36422a3fae2..9d39de3cfe67 100644
> --- a/arch/arm64/mm/mmu.c
> +++ b/arch/arm64/mm/mmu.c
> @@ -141,7 +141,7 @@ bool pgattr_change_is_safe(pteval_t old, pteval_t new)
> return false;
>
> /* live contiguous mappings may not be manipulated at all */
> - if ((old | new) & PTE_CONT)
> + if ((old | new) & PTE_CONT && old != new)
> return false;
>
> /* Transitioning from Non-Global to Global is unsafe */
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH v2 01/10] arm64: Move the zero page to rodata
2026-01-27 9:34 ` Ryan Roberts
@ 2026-01-27 9:49 ` Ard Biesheuvel
2026-01-27 10:03 ` Ryan Roberts
0 siblings, 1 reply; 38+ messages in thread
From: Ard Biesheuvel @ 2026-01-27 9:49 UTC (permalink / raw)
To: Ryan Roberts
Cc: Ard Biesheuvel, linux-kernel, linux-arm-kernel, will,
catalin.marinas, mark.rutland, Anshuman Khandual, Liz Prucka,
Seth Jenkins, Kees Cook, linux-hardening
On Tue, 27 Jan 2026 at 10:34, Ryan Roberts <ryan.roberts@arm.com> wrote:
>
> On 26/01/2026 09:26, Ard Biesheuvel wrote:
> > From: Ard Biesheuvel <ardb@kernel.org>
> >
> > The zero page should contain only zero bytes, and so mapping it
> > read-write is unnecessary. Combine it with reserved_pg_dir, which lives
> > in the read-only region of the kernel, and already serves a similar
> > purpose.
> >
> > Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> > ---
> > arch/arm64/kernel/vmlinux.lds.S | 1 +
> > arch/arm64/mm/mmu.c | 3 +--
> > 2 files changed, 2 insertions(+), 2 deletions(-)
> >
> > diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
> > index ad6133b89e7a..b2a093f5b3fc 100644
> > --- a/arch/arm64/kernel/vmlinux.lds.S
> > +++ b/arch/arm64/kernel/vmlinux.lds.S
> > @@ -229,6 +229,7 @@ SECTIONS
> > #endif
> >
> > reserved_pg_dir = .;
> > + empty_zero_page = .;
> > . += PAGE_SIZE;
> >
> > swapper_pg_dir = .;
>
> Isn't there a magic macro for getting from swapper to reserved? That will need
> updating?
>
Why? This just adds an alias to refer to the same allocation.
> /*
> * Open-coded (swapper_pg_dir - reserved_pg_dir) as this cannot be calculated
> * until link time.
> */
> #define RESERVED_SWAPPER_OFFSET (PAGE_SIZE)
>
>
> > diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> > index 9ae7ce00a7ef..c36422a3fae2 100644
> > --- a/arch/arm64/mm/mmu.c
> > +++ b/arch/arm64/mm/mmu.c
> > @@ -66,9 +66,8 @@ long __section(".mmuoff.data.write") __early_cpu_boot_status;
> >
> > /*
> > * Empty_zero_page is a special page that is used for zero-initialized data
> > - * and COW.
> > + * and COW. Defined in the linker script.
> > */
> > -unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)] __page_aligned_bss;
> > EXPORT_SYMBOL(empty_zero_page);
>
> What's the benefit of giving it it's own place in the linker script vs just
> declaring it as const and having it placed in the rodata?
>
Because it collapses the two into one.
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH v2 04/10] arm64: mm: Preserve existing table mappings when mapping DRAM
2026-01-26 9:26 ` [PATCH v2 04/10] arm64: mm: Preserve existing table mappings when mapping DRAM Ard Biesheuvel
@ 2026-01-27 9:58 ` Ryan Roberts
0 siblings, 0 replies; 38+ messages in thread
From: Ryan Roberts @ 2026-01-27 9:58 UTC (permalink / raw)
To: Ard Biesheuvel, linux-kernel
Cc: linux-arm-kernel, will, catalin.marinas, mark.rutland,
Ard Biesheuvel, Anshuman Khandual, Liz Prucka, Seth Jenkins,
Kees Cook, linux-hardening
On 26/01/2026 09:26, Ard Biesheuvel wrote:
> From: Ard Biesheuvel <ardb@kernel.org>
>
> Instead of blindly overwriting an existing table entry when mapping DRAM
> regions, take care not to replace a pre-existing table entry with a
> block entry. This permits the logic of mapping the kernel's linear alias
> to be simplified in a subsequent patch.
>
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Reviewed-by: Ryan Roberts <ryan.roberts@arm.com>
> ---
> arch/arm64/mm/mmu.c | 6 ++++--
> 1 file changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> index 9d39de3cfe67..28cc3cda042c 100644
> --- a/arch/arm64/mm/mmu.c
> +++ b/arch/arm64/mm/mmu.c
> @@ -262,7 +262,8 @@ static int init_pmd(pmd_t *pmdp, unsigned long addr, unsigned long end,
>
> /* try section mapping first */
> if (((addr | next | phys) & ~PMD_MASK) == 0 &&
> - (flags & NO_BLOCK_MAPPINGS) == 0) {
> + (flags & NO_BLOCK_MAPPINGS) == 0 &&
> + !pmd_table(old_pmd)) {
> pmd_set_huge(pmdp, phys, prot);
>
> /*
> @@ -385,7 +386,8 @@ static int alloc_init_pud(p4d_t *p4dp, unsigned long addr, unsigned long end,
> */
> if (pud_sect_supported() &&
> ((addr | next | phys) & ~PUD_MASK) == 0 &&
> - (flags & NO_BLOCK_MAPPINGS) == 0) {
> + (flags & NO_BLOCK_MAPPINGS) == 0 &&
> + !pud_table(old_pud)) {
> pud_set_huge(pudp, phys, prot);
>
> /*
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH v2 05/10] arm64: mm: Preserve non-contiguous descriptors when mapping DRAM
2026-01-26 9:26 ` [PATCH v2 05/10] arm64: mm: Preserve non-contiguous descriptors " Ard Biesheuvel
@ 2026-01-27 9:58 ` Ryan Roberts
0 siblings, 0 replies; 38+ messages in thread
From: Ryan Roberts @ 2026-01-27 9:58 UTC (permalink / raw)
To: Ard Biesheuvel, linux-kernel
Cc: linux-arm-kernel, will, catalin.marinas, mark.rutland,
Ard Biesheuvel, Anshuman Khandual, Liz Prucka, Seth Jenkins,
Kees Cook, linux-hardening
On 26/01/2026 09:26, Ard Biesheuvel wrote:
> From: Ard Biesheuvel <ardb@kernel.org>
>
> Instead of blindly overwriting existing live entries with the contiguous
> bit cleared when mapping DRAM regions, check whether the contiguous
> region in question starts with a descriptor that has the valid bit set
> and the contiguous bit cleared, and in that case, leave the contiguous
> bit unset on the entire region. This permits the logic of mapping the
> kernel's linear alias to be simplified in a subsequent patch.
>
> Note that not setting the contiguous bit on any of the descriptors in
> the contiguous region can only result in an invalid configuration if it
> was already invalid to begin with.
>
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Reviewed-by: Ryan Roberts <ryan.roberts@arm.com>
> ---
> arch/arm64/include/asm/pgtable.h | 4 ++++
> arch/arm64/mm/mmu.c | 6 ++++--
> 2 files changed, 8 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
> index 64d5f1d9cce9..cb2c4525e49a 100644
> --- a/arch/arm64/include/asm/pgtable.h
> +++ b/arch/arm64/include/asm/pgtable.h
> @@ -224,6 +224,10 @@ static inline pteval_t __phys_to_pte_val(phys_addr_t phys)
> * Returns true if the pte is valid and has the contiguous bit set.
> */
> #define pte_valid_cont(pte) (pte_valid(pte) && pte_cont(pte))
> +/*
> + * Returns true if the pte is valid and has the contiguous bit cleared.
> + */
> +#define pte_valid_noncont(pte) (pte_valid(pte) && !pte_cont(pte))
> /*
> * Could the pte be present in the TLB? We must check mm_tlb_flush_pending
> * so that we don't erroneously return false for pages that have been
> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> index 28cc3cda042c..d7faa98f427c 100644
> --- a/arch/arm64/mm/mmu.c
> +++ b/arch/arm64/mm/mmu.c
> @@ -230,7 +230,8 @@ static int alloc_init_cont_pte(pmd_t *pmdp, unsigned long addr,
>
> /* use a contiguous mapping if the range is suitably aligned */
> if ((((addr | next | phys) & ~CONT_PTE_MASK) == 0) &&
> - (flags & NO_CONT_MAPPINGS) == 0)
> + (flags & NO_CONT_MAPPINGS) == 0 &&
> + !pte_valid_noncont(__ptep_get(ptep)))
> __prot = __pgprot(pgprot_val(prot) | PTE_CONT);
>
> init_pte(ptep, addr, next, phys, __prot);
> @@ -330,7 +331,8 @@ static int alloc_init_cont_pmd(pud_t *pudp, unsigned long addr,
>
> /* use a contiguous mapping if the range is suitably aligned */
> if ((((addr | next | phys) & ~CONT_PMD_MASK) == 0) &&
> - (flags & NO_CONT_MAPPINGS) == 0)
> + (flags & NO_CONT_MAPPINGS) == 0 &&
> + !pte_valid_noncont(pmd_pte(READ_ONCE(*pmdp))))
> __prot = __pgprot(pgprot_val(prot) | PTE_CONT);
>
> ret = init_pmd(pmdp, addr, next, phys, __prot, pgtable_alloc, flags);
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH v2 01/10] arm64: Move the zero page to rodata
2026-01-27 9:49 ` Ard Biesheuvel
@ 2026-01-27 10:03 ` Ryan Roberts
2026-01-27 10:50 ` Ard Biesheuvel
0 siblings, 1 reply; 38+ messages in thread
From: Ryan Roberts @ 2026-01-27 10:03 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: Ard Biesheuvel, linux-kernel, linux-arm-kernel, will,
catalin.marinas, mark.rutland, Anshuman Khandual, Liz Prucka,
Seth Jenkins, Kees Cook, linux-hardening
On 27/01/2026 09:49, Ard Biesheuvel wrote:
> On Tue, 27 Jan 2026 at 10:34, Ryan Roberts <ryan.roberts@arm.com> wrote:
>>
>> On 26/01/2026 09:26, Ard Biesheuvel wrote:
>>> From: Ard Biesheuvel <ardb@kernel.org>
>>>
>>> The zero page should contain only zero bytes, and so mapping it
>>> read-write is unnecessary. Combine it with reserved_pg_dir, which lives
>>> in the read-only region of the kernel, and already serves a similar
>>> purpose.
>>>
>>> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
>>> ---
>>> arch/arm64/kernel/vmlinux.lds.S | 1 +
>>> arch/arm64/mm/mmu.c | 3 +--
>>> 2 files changed, 2 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
>>> index ad6133b89e7a..b2a093f5b3fc 100644
>>> --- a/arch/arm64/kernel/vmlinux.lds.S
>>> +++ b/arch/arm64/kernel/vmlinux.lds.S
>>> @@ -229,6 +229,7 @@ SECTIONS
>>> #endif
>>>
>>> reserved_pg_dir = .;
>>> + empty_zero_page = .;
>>> . += PAGE_SIZE;
>>>
>>> swapper_pg_dir = .;
>>
>> Isn't there a magic macro for getting from swapper to reserved? That will need
>> updating?
>>
>
> Why? This just adds an alias to refer to the same allocation.
Oh yes, sorry I completely missed that. And you've even stated it in the commit
log...
I'm struggling to see where this gets zeroed though? I assume it must be zeroed
before the old empty_zero_page would have been so everything works fine?
Assuming yes, then:
Reviewed-by: Ryan Roberts <ryan.roberts@arm.com>
>
>> /*
>> * Open-coded (swapper_pg_dir - reserved_pg_dir) as this cannot be calculated
>> * until link time.
>> */
>> #define RESERVED_SWAPPER_OFFSET (PAGE_SIZE)
>>
>>
>>> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
>>> index 9ae7ce00a7ef..c36422a3fae2 100644
>>> --- a/arch/arm64/mm/mmu.c
>>> +++ b/arch/arm64/mm/mmu.c
>>> @@ -66,9 +66,8 @@ long __section(".mmuoff.data.write") __early_cpu_boot_status;
>>>
>>> /*
>>> * Empty_zero_page is a special page that is used for zero-initialized data
>>> - * and COW.
>>> + * and COW. Defined in the linker script.
>>> */
>>> -unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)] __page_aligned_bss;
>>> EXPORT_SYMBOL(empty_zero_page);
>>
>> What's the benefit of giving it it's own place in the linker script vs just
>> declaring it as const and having it placed in the rodata?
>>
>
> Because it collapses the two into one.
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH v2 06/10] arm64: mm: Remove bogus stop condition from map_mem() loop
2026-01-26 9:26 ` [PATCH v2 06/10] arm64: mm: Remove bogus stop condition from map_mem() loop Ard Biesheuvel
@ 2026-01-27 10:06 ` Ryan Roberts
0 siblings, 0 replies; 38+ messages in thread
From: Ryan Roberts @ 2026-01-27 10:06 UTC (permalink / raw)
To: Ard Biesheuvel, linux-kernel
Cc: linux-arm-kernel, will, catalin.marinas, mark.rutland,
Ard Biesheuvel, Anshuman Khandual, Liz Prucka, Seth Jenkins,
Kees Cook, linux-hardening
On 26/01/2026 09:26, Ard Biesheuvel wrote:
> From: Ard Biesheuvel <ardb@kernel.org>
>
> The memblock API guarantees that start is not greater than or equal to
> end, so there is no need to test it. And if were, it is doubtful that
> breaking out of the loop would be a reasonable course of action here
> (rather than attempting to map the remaining regions)
>
> So let's drop this check.
If start were greater than end, I think it's a pretty safe bet that
__map_memblock() would do something horrible.
But if memblock makes the guarantee you claim I agree it's preferable to
declutter the code:
Reviewed-by: Ryan Roberts <ryan.roberts@arm.com>
>
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> ---
> arch/arm64/mm/mmu.c | 2 --
> 1 file changed, 2 deletions(-)
>
> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> index d7faa98f427c..377bdc4d84a1 100644
> --- a/arch/arm64/mm/mmu.c
> +++ b/arch/arm64/mm/mmu.c
> @@ -1158,8 +1158,6 @@ static void __init map_mem(pgd_t *pgdp)
>
> /* map all the memory banks */
> for_each_mem_range(i, &start, &end) {
> - if (start >= end)
> - break;
> /*
> * The linear map must allow allocation tags reading/writing
> * if MTE is present. Otherwise, it has the same attributes as
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH v2 07/10] arm64: mm: Drop redundant pgd_t* argument from map_mem()
2026-01-26 9:26 ` [PATCH v2 07/10] arm64: mm: Drop redundant pgd_t* argument from map_mem() Ard Biesheuvel
@ 2026-01-27 10:10 ` Ryan Roberts
0 siblings, 0 replies; 38+ messages in thread
From: Ryan Roberts @ 2026-01-27 10:10 UTC (permalink / raw)
To: Ard Biesheuvel, linux-kernel
Cc: linux-arm-kernel, will, catalin.marinas, mark.rutland,
Ard Biesheuvel, Anshuman Khandual, Liz Prucka, Seth Jenkins,
Kees Cook, linux-hardening
On 26/01/2026 09:26, Ard Biesheuvel wrote:
> From: Ard Biesheuvel <ardb@kernel.org>
>
> __map_memblock() and map_mem() always operate on swapper_pg_dir, so
> there is no need to pass around a pgd_t pointer between them.
>
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
nice simplification:
Reviewed-by: Ryan Roberts <ryan.roberts@arm.com>
> ---
> arch/arm64/mm/mmu.c | 25 ++++++++++----------
> 1 file changed, 12 insertions(+), 13 deletions(-)
>
> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> index 377bdc4d84a1..80587cd47ce7 100644
> --- a/arch/arm64/mm/mmu.c
> +++ b/arch/arm64/mm/mmu.c
> @@ -1020,11 +1020,11 @@ static void update_mapping_prot(phys_addr_t phys, unsigned long virt,
> flush_tlb_kernel_range(virt, virt + size);
> }
>
> -static void __init __map_memblock(pgd_t *pgdp, phys_addr_t start,
> - phys_addr_t end, pgprot_t prot, int flags)
> +static void __init __map_memblock(phys_addr_t start, phys_addr_t end,
> + pgprot_t prot, int flags)
> {
> - early_create_pgd_mapping(pgdp, start, __phys_to_virt(start), end - start,
> - prot, early_pgtable_alloc, flags);
> + early_create_pgd_mapping(swapper_pg_dir, start, __phys_to_virt(start),
> + end - start, prot, early_pgtable_alloc, flags);
> }
>
> void __init mark_linear_text_alias_ro(void)
> @@ -1072,13 +1072,13 @@ static phys_addr_t __init arm64_kfence_alloc_pool(void)
> return kfence_pool;
> }
>
> -static void __init arm64_kfence_map_pool(phys_addr_t kfence_pool, pgd_t *pgdp)
> +static void __init arm64_kfence_map_pool(phys_addr_t kfence_pool)
> {
> if (!kfence_pool)
> return;
>
> /* KFENCE pool needs page-level mapping. */
> - __map_memblock(pgdp, kfence_pool, kfence_pool + KFENCE_POOL_SIZE,
> + __map_memblock(kfence_pool, kfence_pool + KFENCE_POOL_SIZE,
> pgprot_tagged(PAGE_KERNEL),
> NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS);
> memblock_clear_nomap(kfence_pool, KFENCE_POOL_SIZE);
> @@ -1114,11 +1114,11 @@ bool arch_kfence_init_pool(void)
> #else /* CONFIG_KFENCE */
>
> static inline phys_addr_t arm64_kfence_alloc_pool(void) { return 0; }
> -static inline void arm64_kfence_map_pool(phys_addr_t kfence_pool, pgd_t *pgdp) { }
> +static inline void arm64_kfence_map_pool(phys_addr_t kfence_pool) { }
>
> #endif /* CONFIG_KFENCE */
>
> -static void __init map_mem(pgd_t *pgdp)
> +static void __init map_mem(void)
> {
> static const u64 direct_map_end = _PAGE_END(VA_BITS_MIN);
> phys_addr_t kernel_start = __pa_symbol(_text);
> @@ -1163,7 +1163,7 @@ static void __init map_mem(pgd_t *pgdp)
> * if MTE is present. Otherwise, it has the same attributes as
> * PAGE_KERNEL.
> */
> - __map_memblock(pgdp, start, end, pgprot_tagged(PAGE_KERNEL),
> + __map_memblock(start, end, pgprot_tagged(PAGE_KERNEL),
> flags);
> }
>
> @@ -1177,10 +1177,9 @@ static void __init map_mem(pgd_t *pgdp)
> * Note that contiguous mappings cannot be remapped in this way,
> * so we should avoid them here.
> */
> - __map_memblock(pgdp, kernel_start, kernel_end,
> - PAGE_KERNEL, NO_CONT_MAPPINGS);
> + __map_memblock(kernel_start, kernel_end, PAGE_KERNEL, NO_CONT_MAPPINGS);
> memblock_clear_nomap(kernel_start, kernel_end - kernel_start);
> - arm64_kfence_map_pool(early_kfence_pool, pgdp);
> + arm64_kfence_map_pool(early_kfence_pool);
> }
>
> void mark_rodata_ro(void)
> @@ -1402,7 +1401,7 @@ static void __init create_idmap(void)
>
> void __init paging_init(void)
> {
> - map_mem(swapper_pg_dir);
> + map_mem();
>
> memblock_allow_resize();
>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH v2 08/10] arm64: mm: Don't abuse memblock NOMAP to check for overlaps
2026-01-26 9:26 ` [PATCH v2 08/10] arm64: mm: Don't abuse memblock NOMAP to check for overlaps Ard Biesheuvel
@ 2026-01-27 10:21 ` Ryan Roberts
2026-01-27 10:27 ` Ard Biesheuvel
0 siblings, 1 reply; 38+ messages in thread
From: Ryan Roberts @ 2026-01-27 10:21 UTC (permalink / raw)
To: Ard Biesheuvel, linux-kernel
Cc: linux-arm-kernel, will, catalin.marinas, mark.rutland,
Ard Biesheuvel, Anshuman Khandual, Liz Prucka, Seth Jenkins,
Kees Cook, linux-hardening
On 26/01/2026 09:26, Ard Biesheuvel wrote:
> From: Ard Biesheuvel <ardb@kernel.org>
>
> Now that the DRAM mapping routines respect existing table mappings and
> contiguous block and page mappings, it is no longer needed to fiddle
> with the memblock tables to set and clear the NOMAP attribute. Instead,
> map the kernel text and rodata alias first, avoiding contiguous
> mappings, so that they will not be added later when mapping the
> memblocks.
Should we do something similar for kfence? Currently we have
arm64_kfence_alloc_pool() which marks some memory NOMAP then
arm64_kfence_map_pool() which PTE-maps it and clears NOMAP. Presumably we could
rationalize into a single function that does it all, prior to mapping the bulk
of the linear map?
>
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> ---
> arch/arm64/mm/mmu.c | 27 ++++++++------------
> 1 file changed, 10 insertions(+), 17 deletions(-)
>
> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> index 80587cd47ce7..18415d4743bf 100644
> --- a/arch/arm64/mm/mmu.c
> +++ b/arch/arm64/mm/mmu.c
> @@ -1149,12 +1149,17 @@ static void __init map_mem(void)
> flags |= NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS;
>
> /*
> - * Take care not to create a writable alias for the
> - * read-only text and rodata sections of the kernel image.
> - * So temporarily mark them as NOMAP to skip mappings in
> - * the following for-loop
> + * Map the linear alias of the [_text, __init_begin) interval
> + * as non-executable now, and remove the write permission in
> + * mark_linear_text_alias_ro() above (which will be called after
> + * alternative patching has completed). This makes the contents
> + * of the region accessible to subsystems such as hibernate,
> + * but protects it from inadvertent modification or execution.
> + * Note that contiguous mappings cannot be remapped in this way,
> + * so we should avoid them here.
> */
> - memblock_mark_nomap(kernel_start, kernel_end - kernel_start);
> + __map_memblock(kernel_start, kernel_end, PAGE_KERNEL,
> + flags | NO_CONT_MAPPINGS);
So the reason to disallow cont mappings is because we need to modify the
permissions later? It _is_ safe to change permissions on a live contiguous
mapping in this way. That was clarified in the architecture a couple of years
back and we rely on it for contpte_wrprotect_ptes(); see comment there.
I think we could relax this?
Thanks,
Ryan
>
> /* map all the memory banks */
> for_each_mem_range(i, &start, &end) {
> @@ -1167,18 +1172,6 @@ static void __init map_mem(void)
> flags);
> }
>
> - /*
> - * Map the linear alias of the [_text, __init_begin) interval
> - * as non-executable now, and remove the write permission in
> - * mark_linear_text_alias_ro() below (which will be called after
> - * alternative patching has completed). This makes the contents
> - * of the region accessible to subsystems such as hibernate,
> - * but protects it from inadvertent modification or execution.
> - * Note that contiguous mappings cannot be remapped in this way,
> - * so we should avoid them here.
> - */
> - __map_memblock(kernel_start, kernel_end, PAGE_KERNEL, NO_CONT_MAPPINGS);
> - memblock_clear_nomap(kernel_start, kernel_end - kernel_start);
> arm64_kfence_map_pool(early_kfence_pool);
> }
>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH v2 08/10] arm64: mm: Don't abuse memblock NOMAP to check for overlaps
2026-01-27 10:21 ` Ryan Roberts
@ 2026-01-27 10:27 ` Ard Biesheuvel
2026-01-27 10:39 ` Ryan Roberts
0 siblings, 1 reply; 38+ messages in thread
From: Ard Biesheuvel @ 2026-01-27 10:27 UTC (permalink / raw)
To: Ryan Roberts
Cc: Ard Biesheuvel, linux-kernel, linux-arm-kernel, will,
catalin.marinas, mark.rutland, Anshuman Khandual, Liz Prucka,
Seth Jenkins, Kees Cook, linux-hardening
On Tue, 27 Jan 2026 at 11:21, Ryan Roberts <ryan.roberts@arm.com> wrote:
>
> On 26/01/2026 09:26, Ard Biesheuvel wrote:
> > From: Ard Biesheuvel <ardb@kernel.org>
> >
> > Now that the DRAM mapping routines respect existing table mappings and
> > contiguous block and page mappings, it is no longer needed to fiddle
> > with the memblock tables to set and clear the NOMAP attribute. Instead,
> > map the kernel text and rodata alias first, avoiding contiguous
> > mappings, so that they will not be added later when mapping the
> > memblocks.
>
> Should we do something similar for kfence? Currently we have
> arm64_kfence_alloc_pool() which marks some memory NOMAP then
> arm64_kfence_map_pool() which PTE-maps it and clears NOMAP. Presumably we could
> rationalize into a single function that does it all, prior to mapping the bulk
> of the linear map?
>
Yeah, good point - I did not spot that but I will address it in the
next revision.
> >
> > Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> > ---
> > arch/arm64/mm/mmu.c | 27 ++++++++------------
> > 1 file changed, 10 insertions(+), 17 deletions(-)
> >
> > diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> > index 80587cd47ce7..18415d4743bf 100644
> > --- a/arch/arm64/mm/mmu.c
> > +++ b/arch/arm64/mm/mmu.c
> > @@ -1149,12 +1149,17 @@ static void __init map_mem(void)
> > flags |= NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS;
> >
> > /*
> > - * Take care not to create a writable alias for the
> > - * read-only text and rodata sections of the kernel image.
> > - * So temporarily mark them as NOMAP to skip mappings in
> > - * the following for-loop
> > + * Map the linear alias of the [_text, __init_begin) interval
> > + * as non-executable now, and remove the write permission in
> > + * mark_linear_text_alias_ro() above (which will be called after
> > + * alternative patching has completed). This makes the contents
> > + * of the region accessible to subsystems such as hibernate,
> > + * but protects it from inadvertent modification or execution.
> > + * Note that contiguous mappings cannot be remapped in this way,
> > + * so we should avoid them here.
> > */
> > - memblock_mark_nomap(kernel_start, kernel_end - kernel_start);
> > + __map_memblock(kernel_start, kernel_end, PAGE_KERNEL,
> > + flags | NO_CONT_MAPPINGS);
>
> So the reason to disallow cont mappings is because we need to modify the
> permissions later? It _is_ safe to change permissions on a live contiguous
> mapping in this way. That was clarified in the architecture a couple of years
> back and we rely on it for contpte_wrprotect_ptes(); see comment there.
>
OK, good to know - I was hoping to get your take on this ...
> I think we could relax this?
>
OK, I suppose that means that we can drop the NO_CONT_MAPPINGS here,
but we still need to map the kernel text/rodata alias initially to
ensure that no block mappings are created that would need to broken
down, right?
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH v2 09/10] arm64: mm: Map the kernel data/bss read-only in the linear map
2026-01-26 9:26 ` [PATCH v2 09/10] arm64: mm: Map the kernel data/bss read-only in the linear map Ard Biesheuvel
@ 2026-01-27 10:33 ` Ryan Roberts
2026-01-27 10:36 ` Ard Biesheuvel
0 siblings, 1 reply; 38+ messages in thread
From: Ryan Roberts @ 2026-01-27 10:33 UTC (permalink / raw)
To: Ard Biesheuvel, linux-kernel
Cc: linux-arm-kernel, will, catalin.marinas, mark.rutland,
Ard Biesheuvel, Anshuman Khandual, Liz Prucka, Seth Jenkins,
Kees Cook, linux-hardening
On 26/01/2026 09:26, Ard Biesheuvel wrote:
> From: Ard Biesheuvel <ardb@kernel.org>
>
> On systems where the bootloader adheres to the original arm64 boot
> protocol, the placement of the kernel in the physical address space is
> highly predictable, and this makes the placement of its linear alias in
> the kernel virtual address space equally predictable, given the lack of
> randomization of the linear map.
>
> The linear aliases of the kernel text and rodata regions are already
> mapped read-only, but the kernel data and bss are mapped read-write in
> this region. This is not needed, so map them read-only as well.
>
> Note that the statically allocated kernel page tables do need to be
> modifiable via the linear map, so leave these mapped read-write.
>
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> ---
> arch/arm64/include/asm/sections.h | 1 +
> arch/arm64/mm/mmu.c | 10 ++++++++--
> 2 files changed, 9 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm64/include/asm/sections.h b/arch/arm64/include/asm/sections.h
> index 51b0d594239e..f7fe2bcbfd03 100644
> --- a/arch/arm64/include/asm/sections.h
> +++ b/arch/arm64/include/asm/sections.h
> @@ -23,6 +23,7 @@ extern char __irqentry_text_start[], __irqentry_text_end[];
> extern char __mmuoff_data_start[], __mmuoff_data_end[];
> extern char __entry_tramp_text_start[], __entry_tramp_text_end[];
> extern char __relocate_new_kernel_start[], __relocate_new_kernel_end[];
> +extern char __pgdir_start[];
>
> static inline size_t entry_tramp_text_size(void)
> {
> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> index 18415d4743bf..fdbbb018adc5 100644
> --- a/arch/arm64/mm/mmu.c
> +++ b/arch/arm64/mm/mmu.c
> @@ -1122,7 +1122,9 @@ static void __init map_mem(void)
> {
> static const u64 direct_map_end = _PAGE_END(VA_BITS_MIN);
> phys_addr_t kernel_start = __pa_symbol(_text);
> - phys_addr_t kernel_end = __pa_symbol(__init_begin);
> + 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(__pgdir_start);
> phys_addr_t start, end;
> phys_addr_t early_kfence_pool;
> int flags = NO_EXEC_MAPPINGS;
> @@ -1158,7 +1160,9 @@ static void __init map_mem(void)
> * Note that contiguous mappings cannot be remapped in this way,
> * so we should avoid them here.
> */
> - __map_memblock(kernel_start, kernel_end, PAGE_KERNEL,
> + __map_memblock(kernel_start, init_begin, PAGE_KERNEL,
> + flags | NO_CONT_MAPPINGS);
> + __map_memblock(init_end, kernel_end, PAGE_KERNEL,
> flags | NO_CONT_MAPPINGS);
I'm probably being dumb again... why map [init_end, kernel_end) RW here, only to
remap RO below? Why not just map RO here?
>
> /* map all the memory banks */
> @@ -1172,6 +1176,8 @@ static void __init map_mem(void)
> flags);
> }
>
> + __map_memblock(init_end, kernel_end, PAGE_KERNEL_RO,
> + flags | NO_CONT_MAPPINGS);
This seems iffy since __map_memblock() doesn't flush the tlb. If you want to
update an existing mapping you want to be calling update_mapping_prot() right?
Thanks,
Ryan
> arm64_kfence_map_pool(early_kfence_pool);
> }
>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH v2 09/10] arm64: mm: Map the kernel data/bss read-only in the linear map
2026-01-27 10:33 ` Ryan Roberts
@ 2026-01-27 10:36 ` Ard Biesheuvel
2026-01-27 10:41 ` Ryan Roberts
0 siblings, 1 reply; 38+ messages in thread
From: Ard Biesheuvel @ 2026-01-27 10:36 UTC (permalink / raw)
To: Ryan Roberts
Cc: Ard Biesheuvel, linux-kernel, linux-arm-kernel, will,
catalin.marinas, mark.rutland, Anshuman Khandual, Liz Prucka,
Seth Jenkins, Kees Cook, linux-hardening
On Tue, 27 Jan 2026 at 11:33, Ryan Roberts <ryan.roberts@arm.com> wrote:
>
> On 26/01/2026 09:26, Ard Biesheuvel wrote:
> > From: Ard Biesheuvel <ardb@kernel.org>
> >
> > On systems where the bootloader adheres to the original arm64 boot
> > protocol, the placement of the kernel in the physical address space is
> > highly predictable, and this makes the placement of its linear alias in
> > the kernel virtual address space equally predictable, given the lack of
> > randomization of the linear map.
> >
> > The linear aliases of the kernel text and rodata regions are already
> > mapped read-only, but the kernel data and bss are mapped read-write in
> > this region. This is not needed, so map them read-only as well.
> >
> > Note that the statically allocated kernel page tables do need to be
> > modifiable via the linear map, so leave these mapped read-write.
> >
> > Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> > ---
> > arch/arm64/include/asm/sections.h | 1 +
> > arch/arm64/mm/mmu.c | 10 ++++++++--
> > 2 files changed, 9 insertions(+), 2 deletions(-)
> >
> > diff --git a/arch/arm64/include/asm/sections.h b/arch/arm64/include/asm/sections.h
> > index 51b0d594239e..f7fe2bcbfd03 100644
> > --- a/arch/arm64/include/asm/sections.h
> > +++ b/arch/arm64/include/asm/sections.h
> > @@ -23,6 +23,7 @@ extern char __irqentry_text_start[], __irqentry_text_end[];
> > extern char __mmuoff_data_start[], __mmuoff_data_end[];
> > extern char __entry_tramp_text_start[], __entry_tramp_text_end[];
> > extern char __relocate_new_kernel_start[], __relocate_new_kernel_end[];
> > +extern char __pgdir_start[];
> >
> > static inline size_t entry_tramp_text_size(void)
> > {
> > diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> > index 18415d4743bf..fdbbb018adc5 100644
> > --- a/arch/arm64/mm/mmu.c
> > +++ b/arch/arm64/mm/mmu.c
> > @@ -1122,7 +1122,9 @@ static void __init map_mem(void)
> > {
> > static const u64 direct_map_end = _PAGE_END(VA_BITS_MIN);
> > phys_addr_t kernel_start = __pa_symbol(_text);
> > - phys_addr_t kernel_end = __pa_symbol(__init_begin);
> > + 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(__pgdir_start);
> > phys_addr_t start, end;
> > phys_addr_t early_kfence_pool;
> > int flags = NO_EXEC_MAPPINGS;
> > @@ -1158,7 +1160,9 @@ static void __init map_mem(void)
> > * Note that contiguous mappings cannot be remapped in this way,
> > * so we should avoid them here.
> > */
> > - __map_memblock(kernel_start, kernel_end, PAGE_KERNEL,
> > + __map_memblock(kernel_start, init_begin, PAGE_KERNEL,
> > + flags | NO_CONT_MAPPINGS);
> > + __map_memblock(init_end, kernel_end, PAGE_KERNEL,
> > flags | NO_CONT_MAPPINGS);
>
> I'm probably being dumb again... why map [init_end, kernel_end) RW here, only to
> remap RO below? Why not just map RO here?
>
Because the loop that iterates over the memblocks will remap it RW
again anyway, so whether we map RW or RO at this point is irrelevant.
This call just needs to occur here to ensure that no block mappings
needs to be broken up later.
> >
> > /* map all the memory banks */
> > @@ -1172,6 +1176,8 @@ static void __init map_mem(void)
> > flags);
> > }
> >
> > + __map_memblock(init_end, kernel_end, PAGE_KERNEL_RO,
> > + flags | NO_CONT_MAPPINGS);
>
> This seems iffy since __map_memblock() doesn't flush the tlb. If you want to
> update an existing mapping you want to be calling update_mapping_prot() right?
>
Fair enough - I'll use that here.
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH v2 08/10] arm64: mm: Don't abuse memblock NOMAP to check for overlaps
2026-01-27 10:27 ` Ard Biesheuvel
@ 2026-01-27 10:39 ` Ryan Roberts
2026-01-27 10:47 ` Ard Biesheuvel
0 siblings, 1 reply; 38+ messages in thread
From: Ryan Roberts @ 2026-01-27 10:39 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: Ard Biesheuvel, linux-kernel, linux-arm-kernel, will,
catalin.marinas, mark.rutland, Anshuman Khandual, Liz Prucka,
Seth Jenkins, Kees Cook, linux-hardening
On 27/01/2026 10:27, Ard Biesheuvel wrote:
> On Tue, 27 Jan 2026 at 11:21, Ryan Roberts <ryan.roberts@arm.com> wrote:
>>
>> On 26/01/2026 09:26, Ard Biesheuvel wrote:
>>> From: Ard Biesheuvel <ardb@kernel.org>
>>>
>>> Now that the DRAM mapping routines respect existing table mappings and
>>> contiguous block and page mappings, it is no longer needed to fiddle
>>> with the memblock tables to set and clear the NOMAP attribute. Instead,
>>> map the kernel text and rodata alias first, avoiding contiguous
>>> mappings, so that they will not be added later when mapping the
>>> memblocks.
>>
>> Should we do something similar for kfence? Currently we have
>> arm64_kfence_alloc_pool() which marks some memory NOMAP then
>> arm64_kfence_map_pool() which PTE-maps it and clears NOMAP. Presumably we could
>> rationalize into a single function that does it all, prior to mapping the bulk
>> of the linear map?
>>
>
> Yeah, good point - I did not spot that but I will address it in the
> next revision.
>
>>>
>>> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
>>> ---
>>> arch/arm64/mm/mmu.c | 27 ++++++++------------
>>> 1 file changed, 10 insertions(+), 17 deletions(-)
>>>
>>> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
>>> index 80587cd47ce7..18415d4743bf 100644
>>> --- a/arch/arm64/mm/mmu.c
>>> +++ b/arch/arm64/mm/mmu.c
>>> @@ -1149,12 +1149,17 @@ static void __init map_mem(void)
>>> flags |= NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS;
>>>
>>> /*
>>> - * Take care not to create a writable alias for the
>>> - * read-only text and rodata sections of the kernel image.
>>> - * So temporarily mark them as NOMAP to skip mappings in
>>> - * the following for-loop
>>> + * Map the linear alias of the [_text, __init_begin) interval
>>> + * as non-executable now, and remove the write permission in
>>> + * mark_linear_text_alias_ro() above (which will be called after
>>> + * alternative patching has completed). This makes the contents
>>> + * of the region accessible to subsystems such as hibernate,
>>> + * but protects it from inadvertent modification or execution.
>>> + * Note that contiguous mappings cannot be remapped in this way,
>>> + * so we should avoid them here.
>>> */
>>> - memblock_mark_nomap(kernel_start, kernel_end - kernel_start);
>>> + __map_memblock(kernel_start, kernel_end, PAGE_KERNEL,
>>> + flags | NO_CONT_MAPPINGS);
>>
>> So the reason to disallow cont mappings is because we need to modify the
>> permissions later? It _is_ safe to change permissions on a live contiguous
>> mapping in this way. That was clarified in the architecture a couple of years
>> back and we rely on it for contpte_wrprotect_ptes(); see comment there.
>>
>
> OK, good to know - I was hoping to get your take on this ...
>
>> I think we could relax this?
>>
>
> OK, I suppose that means that we can drop the NO_CONT_MAPPINGS here,
> but we still need to map the kernel text/rodata alias initially to
> ensure that no block mappings are created that would need to broken
> down, right?
Yes, but...
I think your intent is that the multiple __map_memblock() calls are just
controlling the allowed leaf mapping sizes. It becomes problematic if the 2
calls use different permissions... which they do.
PAGE_KERNEL vs pgprot_tagged(PAGE_KERNEL).
Is it possible that the text/rodata section ends up tagged, which is not intended?
Thanks,
Ryan
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH v2 09/10] arm64: mm: Map the kernel data/bss read-only in the linear map
2026-01-27 10:36 ` Ard Biesheuvel
@ 2026-01-27 10:41 ` Ryan Roberts
0 siblings, 0 replies; 38+ messages in thread
From: Ryan Roberts @ 2026-01-27 10:41 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: Ard Biesheuvel, linux-kernel, linux-arm-kernel, will,
catalin.marinas, mark.rutland, Anshuman Khandual, Liz Prucka,
Seth Jenkins, Kees Cook, linux-hardening
On 27/01/2026 10:36, Ard Biesheuvel wrote:
> On Tue, 27 Jan 2026 at 11:33, Ryan Roberts <ryan.roberts@arm.com> wrote:
>>
>> On 26/01/2026 09:26, Ard Biesheuvel wrote:
>>> From: Ard Biesheuvel <ardb@kernel.org>
>>>
>>> On systems where the bootloader adheres to the original arm64 boot
>>> protocol, the placement of the kernel in the physical address space is
>>> highly predictable, and this makes the placement of its linear alias in
>>> the kernel virtual address space equally predictable, given the lack of
>>> randomization of the linear map.
>>>
>>> The linear aliases of the kernel text and rodata regions are already
>>> mapped read-only, but the kernel data and bss are mapped read-write in
>>> this region. This is not needed, so map them read-only as well.
>>>
>>> Note that the statically allocated kernel page tables do need to be
>>> modifiable via the linear map, so leave these mapped read-write.
>>>
>>> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
>>> ---
>>> arch/arm64/include/asm/sections.h | 1 +
>>> arch/arm64/mm/mmu.c | 10 ++++++++--
>>> 2 files changed, 9 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/arch/arm64/include/asm/sections.h b/arch/arm64/include/asm/sections.h
>>> index 51b0d594239e..f7fe2bcbfd03 100644
>>> --- a/arch/arm64/include/asm/sections.h
>>> +++ b/arch/arm64/include/asm/sections.h
>>> @@ -23,6 +23,7 @@ extern char __irqentry_text_start[], __irqentry_text_end[];
>>> extern char __mmuoff_data_start[], __mmuoff_data_end[];
>>> extern char __entry_tramp_text_start[], __entry_tramp_text_end[];
>>> extern char __relocate_new_kernel_start[], __relocate_new_kernel_end[];
>>> +extern char __pgdir_start[];
>>>
>>> static inline size_t entry_tramp_text_size(void)
>>> {
>>> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
>>> index 18415d4743bf..fdbbb018adc5 100644
>>> --- a/arch/arm64/mm/mmu.c
>>> +++ b/arch/arm64/mm/mmu.c
>>> @@ -1122,7 +1122,9 @@ static void __init map_mem(void)
>>> {
>>> static const u64 direct_map_end = _PAGE_END(VA_BITS_MIN);
>>> phys_addr_t kernel_start = __pa_symbol(_text);
>>> - phys_addr_t kernel_end = __pa_symbol(__init_begin);
>>> + 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(__pgdir_start);
>>> phys_addr_t start, end;
>>> phys_addr_t early_kfence_pool;
>>> int flags = NO_EXEC_MAPPINGS;
>>> @@ -1158,7 +1160,9 @@ static void __init map_mem(void)
>>> * Note that contiguous mappings cannot be remapped in this way,
>>> * so we should avoid them here.
>>> */
>>> - __map_memblock(kernel_start, kernel_end, PAGE_KERNEL,
>>> + __map_memblock(kernel_start, init_begin, PAGE_KERNEL,
>>> + flags | NO_CONT_MAPPINGS);
>>> + __map_memblock(init_end, kernel_end, PAGE_KERNEL,
>>> flags | NO_CONT_MAPPINGS);
>>
>> I'm probably being dumb again... why map [init_end, kernel_end) RW here, only to
>> remap RO below? Why not just map RO here?
>>
>
> Because the loop that iterates over the memblocks will remap it RW
> again anyway, so whether we map RW or RO at this point is irrelevant.
> This call just needs to occur here to ensure that no block mappings
> needs to be broken up later.
Ahh yes, got it.
>
>
>>>
>>> /* map all the memory banks */
>>> @@ -1172,6 +1176,8 @@ static void __init map_mem(void)
>>> flags);
>>> }
>>>
>>> + __map_memblock(init_end, kernel_end, PAGE_KERNEL_RO,
>>> + flags | NO_CONT_MAPPINGS);
>>
>> This seems iffy since __map_memblock() doesn't flush the tlb. If you want to
>> update an existing mapping you want to be calling update_mapping_prot() right?
>>
>
> Fair enough - I'll use that here.
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH v2 08/10] arm64: mm: Don't abuse memblock NOMAP to check for overlaps
2026-01-27 10:39 ` Ryan Roberts
@ 2026-01-27 10:47 ` Ard Biesheuvel
2026-01-27 11:00 ` Ryan Roberts
0 siblings, 1 reply; 38+ messages in thread
From: Ard Biesheuvel @ 2026-01-27 10:47 UTC (permalink / raw)
To: Ryan Roberts
Cc: linux-kernel, linux-arm-kernel, will, catalin.marinas,
mark.rutland, Anshuman Khandual, Liz Prucka, Seth Jenkins,
Kees Cook, linux-hardening
On Tue, 27 Jan 2026 at 11:39, Ryan Roberts <ryan.roberts@arm.com> wrote:
>
> On 27/01/2026 10:27, Ard Biesheuvel wrote:
> > On Tue, 27 Jan 2026 at 11:21, Ryan Roberts <ryan.roberts@arm.com> wrote:
> >>
> >> On 26/01/2026 09:26, Ard Biesheuvel wrote:
> >>> From: Ard Biesheuvel <ardb@kernel.org>
> >>>
> >>> Now that the DRAM mapping routines respect existing table mappings and
> >>> contiguous block and page mappings, it is no longer needed to fiddle
> >>> with the memblock tables to set and clear the NOMAP attribute. Instead,
> >>> map the kernel text and rodata alias first, avoiding contiguous
> >>> mappings, so that they will not be added later when mapping the
> >>> memblocks.
> >>
> >> Should we do something similar for kfence? Currently we have
> >> arm64_kfence_alloc_pool() which marks some memory NOMAP then
> >> arm64_kfence_map_pool() which PTE-maps it and clears NOMAP. Presumably we could
> >> rationalize into a single function that does it all, prior to mapping the bulk
> >> of the linear map?
> >>
> >
> > Yeah, good point - I did not spot that but I will address it in the
> > next revision.
> >
> >>>
> >>> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> >>> ---
> >>> arch/arm64/mm/mmu.c | 27 ++++++++------------
> >>> 1 file changed, 10 insertions(+), 17 deletions(-)
> >>>
> >>> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> >>> index 80587cd47ce7..18415d4743bf 100644
> >>> --- a/arch/arm64/mm/mmu.c
> >>> +++ b/arch/arm64/mm/mmu.c
> >>> @@ -1149,12 +1149,17 @@ static void __init map_mem(void)
> >>> flags |= NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS;
> >>>
> >>> /*
> >>> - * Take care not to create a writable alias for the
> >>> - * read-only text and rodata sections of the kernel image.
> >>> - * So temporarily mark them as NOMAP to skip mappings in
> >>> - * the following for-loop
> >>> + * Map the linear alias of the [_text, __init_begin) interval
> >>> + * as non-executable now, and remove the write permission in
> >>> + * mark_linear_text_alias_ro() above (which will be called after
> >>> + * alternative patching has completed). This makes the contents
> >>> + * of the region accessible to subsystems such as hibernate,
> >>> + * but protects it from inadvertent modification or execution.
> >>> + * Note that contiguous mappings cannot be remapped in this way,
> >>> + * so we should avoid them here.
> >>> */
> >>> - memblock_mark_nomap(kernel_start, kernel_end - kernel_start);
> >>> + __map_memblock(kernel_start, kernel_end, PAGE_KERNEL,
> >>> + flags | NO_CONT_MAPPINGS);
> >>
> >> So the reason to disallow cont mappings is because we need to modify the
> >> permissions later? It _is_ safe to change permissions on a live contiguous
> >> mapping in this way. That was clarified in the architecture a couple of years
> >> back and we rely on it for contpte_wrprotect_ptes(); see comment there.
> >>
> >
> > OK, good to know - I was hoping to get your take on this ...
> >
> >> I think we could relax this?
> >>
> >
> > OK, I suppose that means that we can drop the NO_CONT_MAPPINGS here,
> > but we still need to map the kernel text/rodata alias initially to
> > ensure that no block mappings are created that would need to broken
> > down, right?
>
> Yes, but...
>
> I think your intent is that the multiple __map_memblock() calls are just
> controlling the allowed leaf mapping sizes.
Indeed.
> It becomes problematic if the 2
> calls use different permissions... which they do.
>
> PAGE_KERNEL vs pgprot_tagged(PAGE_KERNEL).
>
> Is it possible that the text/rodata section ends up tagged, which is not intended?
>
OK so toggling the R/O attribute on a live contiguous mapping is
permitted (provided that ultimately, the entire contiguous region is
updated accordingly) but the same doesn't apply to MT_NORMAL vs
MT_NORMAL_TAGGED, right?
So let's use just the same prot and flags for the initial mapping, and
use MT_NORMAL_TAGGED when we remap the text alias R/O.
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH v2 10/10] arm64: mm: Unmap kernel data/bss entirely from the linear map
2026-01-26 9:26 ` [PATCH v2 10/10] arm64: mm: Unmap kernel data/bss entirely from " Ard Biesheuvel
@ 2026-01-27 10:50 ` Ryan Roberts
2026-01-27 10:54 ` Ard Biesheuvel
0 siblings, 1 reply; 38+ messages in thread
From: Ryan Roberts @ 2026-01-27 10:50 UTC (permalink / raw)
To: Ard Biesheuvel, linux-kernel
Cc: linux-arm-kernel, will, catalin.marinas, mark.rutland,
Ard Biesheuvel, Anshuman Khandual, Liz Prucka, Seth Jenkins,
Kees Cook, linux-hardening
On 26/01/2026 09:26, Ard Biesheuvel wrote:
> From: Ard Biesheuvel <ardb@kernel.org>
>
> The linear aliases of the kernel text and rodata are mapped read-only in
> the linear map as well. Given that the contents of these regions are
> mostly identical to the version in the loadable image, mapping them
> read-only and leaving their contents visible is a reasonable hardening
> measure.
what about ro_after_init? Could that contain secrets that we don't want to leak?
What is the advantage of leaving text/rodata ro in the linear map vs just
umapping the whole lot?
>
> Data and bss, however, are now also mapped read-only but the contents of
> these regions are more likely to contain data that we'd rather not leak.
> So let's unmap these entirely in the linear map when the kernel is
> running normally.
>
> When going into hibernation or waking up from it, these regions need to
> be mapped, so map the region initially, and toggle the valid bit so
> map/unmap the region as needed.
>
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> ---
> arch/arm64/mm/mmu.c | 40 ++++++++++++++++++--
> 1 file changed, 37 insertions(+), 3 deletions(-)
>
> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> index fdbbb018adc5..06b2d11b4561 100644
> --- a/arch/arm64/mm/mmu.c
> +++ b/arch/arm64/mm/mmu.c
> @@ -24,6 +24,7 @@
> #include <linux/mm.h>
> #include <linux/vmalloc.h>
> #include <linux/set_memory.h>
> +#include <linux/suspend.h>
> #include <linux/kfence.h>
> #include <linux/pkeys.h>
> #include <linux/mm_inline.h>
> @@ -1027,6 +1028,31 @@ static void __init __map_memblock(phys_addr_t start, phys_addr_t end,
> end - start, prot, early_pgtable_alloc, flags);
> }
>
> +static void remap_linear_data_alias(bool unmap)
> +{
> + set_memory_valid((unsigned long)lm_alias(__init_end),
> + (unsigned long)(__pgdir_start - __init_end) / PAGE_SIZE,
> + !unmap);
> +}
> +
> +static int arm64_hibernate_pm_notify(struct notifier_block *nb,
> + unsigned long mode, void *unused)
> +{
> + switch (mode) {
> + default:
> + break;
> + case PM_POST_HIBERNATION:
> + case PM_POST_RESTORE:
> + remap_linear_data_alias(true);
> + break;
> + case PM_HIBERNATION_PREPARE:
> + case PM_RESTORE_PREPARE:
> + remap_linear_data_alias(false);
> + break;
> + }
> + return 0;
> +}
> +
> void __init mark_linear_text_alias_ro(void)
> {
> /*
> @@ -1035,6 +1061,16 @@ void __init mark_linear_text_alias_ro(void)
> update_mapping_prot(__pa_symbol(_text), (unsigned long)lm_alias(_text),
> (unsigned long)__init_begin - (unsigned long)_text,
> PAGE_KERNEL_RO);
> +
> + remap_linear_data_alias(true);
> +
> + if (IS_ENABLED(CONFIG_HIBERNATION)) {
> + static struct notifier_block nb = {
> + .notifier_call = arm64_hibernate_pm_notify
> + };
> +
> + register_pm_notifier(&nb);
> + }
> }
>
> #ifdef CONFIG_KFENCE
> @@ -1163,7 +1199,7 @@ static void __init map_mem(void)
> __map_memblock(kernel_start, init_begin, PAGE_KERNEL,
> flags | NO_CONT_MAPPINGS);
> __map_memblock(init_end, kernel_end, PAGE_KERNEL,
> - flags | NO_CONT_MAPPINGS);
> + flags | NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS);
>
> /* map all the memory banks */
> for_each_mem_range(i, &start, &end) {
> @@ -1176,8 +1212,6 @@ static void __init map_mem(void)
> flags);
> }
>
> - __map_memblock(init_end, kernel_end, PAGE_KERNEL_RO,
> - flags | NO_CONT_MAPPINGS);
In the previous patch, perhaps this should be moved to
mark_linear_text_alias_ro() and combined with the update_mapping_prot() there?
Thanks,
Ryan
> arm64_kfence_map_pool(early_kfence_pool);
> }
>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH v2 01/10] arm64: Move the zero page to rodata
2026-01-27 10:03 ` Ryan Roberts
@ 2026-01-27 10:50 ` Ard Biesheuvel
0 siblings, 0 replies; 38+ messages in thread
From: Ard Biesheuvel @ 2026-01-27 10:50 UTC (permalink / raw)
To: Ryan Roberts
Cc: Ard Biesheuvel, linux-kernel, linux-arm-kernel, will,
catalin.marinas, mark.rutland, Anshuman Khandual, Liz Prucka,
Seth Jenkins, Kees Cook, linux-hardening
On Tue, 27 Jan 2026 at 11:04, Ryan Roberts <ryan.roberts@arm.com> wrote:
>
> On 27/01/2026 09:49, Ard Biesheuvel wrote:
> > On Tue, 27 Jan 2026 at 10:34, Ryan Roberts <ryan.roberts@arm.com> wrote:
> >>
> >> On 26/01/2026 09:26, Ard Biesheuvel wrote:
> >>> From: Ard Biesheuvel <ardb@kernel.org>
> >>>
> >>> The zero page should contain only zero bytes, and so mapping it
> >>> read-write is unnecessary. Combine it with reserved_pg_dir, which lives
> >>> in the read-only region of the kernel, and already serves a similar
> >>> purpose.
> >>>
> >>> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> >>> ---
> >>> arch/arm64/kernel/vmlinux.lds.S | 1 +
> >>> arch/arm64/mm/mmu.c | 3 +--
> >>> 2 files changed, 2 insertions(+), 2 deletions(-)
> >>>
> >>> diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
> >>> index ad6133b89e7a..b2a093f5b3fc 100644
> >>> --- a/arch/arm64/kernel/vmlinux.lds.S
> >>> +++ b/arch/arm64/kernel/vmlinux.lds.S
> >>> @@ -229,6 +229,7 @@ SECTIONS
> >>> #endif
> >>>
> >>> reserved_pg_dir = .;
> >>> + empty_zero_page = .;
> >>> . += PAGE_SIZE;
> >>>
> >>> swapper_pg_dir = .;
> >>
> >> Isn't there a magic macro for getting from swapper to reserved? That will need
> >> updating?
> >>
> >
> > Why? This just adds an alias to refer to the same allocation.
>
> Oh yes, sorry I completely missed that. And you've even stated it in the commit
> log...
>
> I'm struggling to see where this gets zeroed though? I assume it must be zeroed
> before the old empty_zero_page would have been so everything works fine?
>
It is statically zero initialized in the image.
> Assuming yes, then:
>
> Reviewed-by: Ryan Roberts <ryan.roberts@arm.com>
>
Thanks!
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH v2 10/10] arm64: mm: Unmap kernel data/bss entirely from the linear map
2026-01-27 10:50 ` Ryan Roberts
@ 2026-01-27 10:54 ` Ard Biesheuvel
2026-01-27 11:02 ` Ryan Roberts
0 siblings, 1 reply; 38+ messages in thread
From: Ard Biesheuvel @ 2026-01-27 10:54 UTC (permalink / raw)
To: Ryan Roberts
Cc: Ard Biesheuvel, linux-kernel, linux-arm-kernel, will,
catalin.marinas, mark.rutland, Anshuman Khandual, Liz Prucka,
Seth Jenkins, Kees Cook, linux-hardening
On Tue, 27 Jan 2026 at 11:50, Ryan Roberts <ryan.roberts@arm.com> wrote:
>
> On 26/01/2026 09:26, Ard Biesheuvel wrote:
> > From: Ard Biesheuvel <ardb@kernel.org>
> >
> > The linear aliases of the kernel text and rodata are mapped read-only in
> > the linear map as well. Given that the contents of these regions are
> > mostly identical to the version in the loadable image, mapping them
> > read-only and leaving their contents visible is a reasonable hardening
> > measure.
>
> what about ro_after_init? Could that contain secrets that we don't want to leak?
> What is the advantage of leaving text/rodata ro in the linear map vs just
> umapping the whole lot?
>
Unmapping it would be preferred, but there are some pieces (such as
the zero page and swapper_pg_dir) that are expected to be visible via
the linear map.
> >
> > Data and bss, however, are now also mapped read-only but the contents of
> > these regions are more likely to contain data that we'd rather not leak.
> > So let's unmap these entirely in the linear map when the kernel is
> > running normally.
> >
> > When going into hibernation or waking up from it, these regions need to
> > be mapped, so map the region initially, and toggle the valid bit so
> > map/unmap the region as needed.
> >
> > Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> > ---
> > arch/arm64/mm/mmu.c | 40 ++++++++++++++++++--
> > 1 file changed, 37 insertions(+), 3 deletions(-)
> >
> > diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> > index fdbbb018adc5..06b2d11b4561 100644
> > --- a/arch/arm64/mm/mmu.c
> > +++ b/arch/arm64/mm/mmu.c
> > @@ -24,6 +24,7 @@
> > #include <linux/mm.h>
> > #include <linux/vmalloc.h>
> > #include <linux/set_memory.h>
> > +#include <linux/suspend.h>
> > #include <linux/kfence.h>
> > #include <linux/pkeys.h>
> > #include <linux/mm_inline.h>
> > @@ -1027,6 +1028,31 @@ static void __init __map_memblock(phys_addr_t start, phys_addr_t end,
> > end - start, prot, early_pgtable_alloc, flags);
> > }
> >
> > +static void remap_linear_data_alias(bool unmap)
> > +{
> > + set_memory_valid((unsigned long)lm_alias(__init_end),
> > + (unsigned long)(__pgdir_start - __init_end) / PAGE_SIZE,
> > + !unmap);
> > +}
> > +
> > +static int arm64_hibernate_pm_notify(struct notifier_block *nb,
> > + unsigned long mode, void *unused)
> > +{
> > + switch (mode) {
> > + default:
> > + break;
> > + case PM_POST_HIBERNATION:
> > + case PM_POST_RESTORE:
> > + remap_linear_data_alias(true);
> > + break;
> > + case PM_HIBERNATION_PREPARE:
> > + case PM_RESTORE_PREPARE:
> > + remap_linear_data_alias(false);
> > + break;
> > + }
> > + return 0;
> > +}
> > +
> > void __init mark_linear_text_alias_ro(void)
> > {
> > /*
> > @@ -1035,6 +1061,16 @@ void __init mark_linear_text_alias_ro(void)
> > update_mapping_prot(__pa_symbol(_text), (unsigned long)lm_alias(_text),
> > (unsigned long)__init_begin - (unsigned long)_text,
> > PAGE_KERNEL_RO);
> > +
> > + remap_linear_data_alias(true);
> > +
> > + if (IS_ENABLED(CONFIG_HIBERNATION)) {
> > + static struct notifier_block nb = {
> > + .notifier_call = arm64_hibernate_pm_notify
> > + };
> > +
> > + register_pm_notifier(&nb);
> > + }
> > }
> >
> > #ifdef CONFIG_KFENCE
> > @@ -1163,7 +1199,7 @@ static void __init map_mem(void)
> > __map_memblock(kernel_start, init_begin, PAGE_KERNEL,
> > flags | NO_CONT_MAPPINGS);
> > __map_memblock(init_end, kernel_end, PAGE_KERNEL,
> > - flags | NO_CONT_MAPPINGS);
> > + flags | NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS);
> >
> > /* map all the memory banks */
> > for_each_mem_range(i, &start, &end) {
> > @@ -1176,8 +1212,6 @@ static void __init map_mem(void)
> > flags);
> > }
> >
> > - __map_memblock(init_end, kernel_end, PAGE_KERNEL_RO,
> > - flags | NO_CONT_MAPPINGS);
>
> In the previous patch, perhaps this should be moved to
> mark_linear_text_alias_ro() and combined with the update_mapping_prot() there?
>
Why? Isn't it better to just remap it r/o from the outset if it never
needs to be mapped r/w to begin with?
The same applies to the rodata region but -again- it is the root page
tables that are manipulated via the writable linear alias during boot.
I'll try to address all of that in the next rev - thanks.
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH v2 08/10] arm64: mm: Don't abuse memblock NOMAP to check for overlaps
2026-01-27 10:47 ` Ard Biesheuvel
@ 2026-01-27 11:00 ` Ryan Roberts
2026-01-27 11:03 ` Ard Biesheuvel
0 siblings, 1 reply; 38+ messages in thread
From: Ryan Roberts @ 2026-01-27 11:00 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: linux-kernel, linux-arm-kernel, will, catalin.marinas,
mark.rutland, Anshuman Khandual, Liz Prucka, Seth Jenkins,
Kees Cook, linux-hardening
On 27/01/2026 10:47, Ard Biesheuvel wrote:
> On Tue, 27 Jan 2026 at 11:39, Ryan Roberts <ryan.roberts@arm.com> wrote:
>>
>> On 27/01/2026 10:27, Ard Biesheuvel wrote:
>>> On Tue, 27 Jan 2026 at 11:21, Ryan Roberts <ryan.roberts@arm.com> wrote:
>>>>
>>>> On 26/01/2026 09:26, Ard Biesheuvel wrote:
>>>>> From: Ard Biesheuvel <ardb@kernel.org>
>>>>>
>>>>> Now that the DRAM mapping routines respect existing table mappings and
>>>>> contiguous block and page mappings, it is no longer needed to fiddle
>>>>> with the memblock tables to set and clear the NOMAP attribute. Instead,
>>>>> map the kernel text and rodata alias first, avoiding contiguous
>>>>> mappings, so that they will not be added later when mapping the
>>>>> memblocks.
>>>>
>>>> Should we do something similar for kfence? Currently we have
>>>> arm64_kfence_alloc_pool() which marks some memory NOMAP then
>>>> arm64_kfence_map_pool() which PTE-maps it and clears NOMAP. Presumably we could
>>>> rationalize into a single function that does it all, prior to mapping the bulk
>>>> of the linear map?
>>>>
>>>
>>> Yeah, good point - I did not spot that but I will address it in the
>>> next revision.
>>>
>>>>>
>>>>> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
>>>>> ---
>>>>> arch/arm64/mm/mmu.c | 27 ++++++++------------
>>>>> 1 file changed, 10 insertions(+), 17 deletions(-)
>>>>>
>>>>> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
>>>>> index 80587cd47ce7..18415d4743bf 100644
>>>>> --- a/arch/arm64/mm/mmu.c
>>>>> +++ b/arch/arm64/mm/mmu.c
>>>>> @@ -1149,12 +1149,17 @@ static void __init map_mem(void)
>>>>> flags |= NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS;
>>>>>
>>>>> /*
>>>>> - * Take care not to create a writable alias for the
>>>>> - * read-only text and rodata sections of the kernel image.
>>>>> - * So temporarily mark them as NOMAP to skip mappings in
>>>>> - * the following for-loop
>>>>> + * Map the linear alias of the [_text, __init_begin) interval
>>>>> + * as non-executable now, and remove the write permission in
>>>>> + * mark_linear_text_alias_ro() above (which will be called after
>>>>> + * alternative patching has completed). This makes the contents
>>>>> + * of the region accessible to subsystems such as hibernate,
>>>>> + * but protects it from inadvertent modification or execution.
>>>>> + * Note that contiguous mappings cannot be remapped in this way,
>>>>> + * so we should avoid them here.
>>>>> */
>>>>> - memblock_mark_nomap(kernel_start, kernel_end - kernel_start);
>>>>> + __map_memblock(kernel_start, kernel_end, PAGE_KERNEL,
>>>>> + flags | NO_CONT_MAPPINGS);
>>>>
>>>> So the reason to disallow cont mappings is because we need to modify the
>>>> permissions later? It _is_ safe to change permissions on a live contiguous
>>>> mapping in this way. That was clarified in the architecture a couple of years
>>>> back and we rely on it for contpte_wrprotect_ptes(); see comment there.
>>>>
>>>
>>> OK, good to know - I was hoping to get your take on this ...
>>>
>>>> I think we could relax this?
>>>>
>>>
>>> OK, I suppose that means that we can drop the NO_CONT_MAPPINGS here,
>>> but we still need to map the kernel text/rodata alias initially to
>>> ensure that no block mappings are created that would need to broken
>>> down, right?
>>
>> Yes, but...
>>
>> I think your intent is that the multiple __map_memblock() calls are just
>> controlling the allowed leaf mapping sizes.
>
> Indeed.
>
>> It becomes problematic if the 2
>> calls use different permissions... which they do.
>>
>> PAGE_KERNEL vs pgprot_tagged(PAGE_KERNEL).
>>
>> Is it possible that the text/rodata section ends up tagged, which is not intended?
>>
>
>
> OK so toggling the R/O attribute on a live contiguous mapping is
> permitted (provided that ultimately, the entire contiguous region is
> updated accordingly) but the same doesn't apply to MT_NORMAL vs
> MT_NORMAL_TAGGED, right?
This is the rule:
RJQQTC
For a TLB lookup in a contiguous region mapped by translation table entries that
have consistent values for the Contiguous bit, but have the OA, attributes, or
permissions misprogrammed, that TLB lookup is permitted to produce an OA, access
permissions, and memory attributes that are consistent with any one of the
programmed translation table values.
So, yes, it is fine to modify the attributes (and I assume the memory type
counts as attributes) on the live mapping...
>
> So let's use just the same prot and flags for the initial mapping, and
> use MT_NORMAL_TAGGED when we remap the text alias R/O.
...but that wasn't my point. I belive the intent is that all of the linear map
uses MT_NORMAL_TAGGED except for the kernel text and rodata, which uses
MT_NORMAL. In some configs (e.g. force_pte_mapping() == true), your change will
result in all the linear map, including text and rodata being MT_NORMAL_TAGGED.
Thanks,
Ryan
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH v2 10/10] arm64: mm: Unmap kernel data/bss entirely from the linear map
2026-01-27 10:54 ` Ard Biesheuvel
@ 2026-01-27 11:02 ` Ryan Roberts
0 siblings, 0 replies; 38+ messages in thread
From: Ryan Roberts @ 2026-01-27 11:02 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: Ard Biesheuvel, linux-kernel, linux-arm-kernel, will,
catalin.marinas, mark.rutland, Anshuman Khandual, Liz Prucka,
Seth Jenkins, Kees Cook, linux-hardening
On 27/01/2026 10:54, Ard Biesheuvel wrote:
> On Tue, 27 Jan 2026 at 11:50, Ryan Roberts <ryan.roberts@arm.com> wrote:
>>
>> On 26/01/2026 09:26, Ard Biesheuvel wrote:
>>> From: Ard Biesheuvel <ardb@kernel.org>
>>>
>>> The linear aliases of the kernel text and rodata are mapped read-only in
>>> the linear map as well. Given that the contents of these regions are
>>> mostly identical to the version in the loadable image, mapping them
>>> read-only and leaving their contents visible is a reasonable hardening
>>> measure.
>>
>> what about ro_after_init? Could that contain secrets that we don't want to leak?
>> What is the advantage of leaving text/rodata ro in the linear map vs just
>> umapping the whole lot?
>>
>
> Unmapping it would be preferred, but there are some pieces (such as
> the zero page and swapper_pg_dir) that are expected to be visible via
> the linear map.
>
>>>
>>> Data and bss, however, are now also mapped read-only but the contents of
>>> these regions are more likely to contain data that we'd rather not leak.
>>> So let's unmap these entirely in the linear map when the kernel is
>>> running normally.
>>>
>>> When going into hibernation or waking up from it, these regions need to
>>> be mapped, so map the region initially, and toggle the valid bit so
>>> map/unmap the region as needed.
>>>
>>> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
>>> ---
>>> arch/arm64/mm/mmu.c | 40 ++++++++++++++++++--
>>> 1 file changed, 37 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
>>> index fdbbb018adc5..06b2d11b4561 100644
>>> --- a/arch/arm64/mm/mmu.c
>>> +++ b/arch/arm64/mm/mmu.c
>>> @@ -24,6 +24,7 @@
>>> #include <linux/mm.h>
>>> #include <linux/vmalloc.h>
>>> #include <linux/set_memory.h>
>>> +#include <linux/suspend.h>
>>> #include <linux/kfence.h>
>>> #include <linux/pkeys.h>
>>> #include <linux/mm_inline.h>
>>> @@ -1027,6 +1028,31 @@ static void __init __map_memblock(phys_addr_t start, phys_addr_t end,
>>> end - start, prot, early_pgtable_alloc, flags);
>>> }
>>>
>>> +static void remap_linear_data_alias(bool unmap)
>>> +{
>>> + set_memory_valid((unsigned long)lm_alias(__init_end),
>>> + (unsigned long)(__pgdir_start - __init_end) / PAGE_SIZE,
>>> + !unmap);
>>> +}
>>> +
>>> +static int arm64_hibernate_pm_notify(struct notifier_block *nb,
>>> + unsigned long mode, void *unused)
>>> +{
>>> + switch (mode) {
>>> + default:
>>> + break;
>>> + case PM_POST_HIBERNATION:
>>> + case PM_POST_RESTORE:
>>> + remap_linear_data_alias(true);
>>> + break;
>>> + case PM_HIBERNATION_PREPARE:
>>> + case PM_RESTORE_PREPARE:
>>> + remap_linear_data_alias(false);
>>> + break;
>>> + }
>>> + return 0;
>>> +}
>>> +
>>> void __init mark_linear_text_alias_ro(void)
>>> {
>>> /*
>>> @@ -1035,6 +1061,16 @@ void __init mark_linear_text_alias_ro(void)
>>> update_mapping_prot(__pa_symbol(_text), (unsigned long)lm_alias(_text),
>>> (unsigned long)__init_begin - (unsigned long)_text,
>>> PAGE_KERNEL_RO);
>>> +
>>> + remap_linear_data_alias(true);
>>> +
>>> + if (IS_ENABLED(CONFIG_HIBERNATION)) {
>>> + static struct notifier_block nb = {
>>> + .notifier_call = arm64_hibernate_pm_notify
>>> + };
>>> +
>>> + register_pm_notifier(&nb);
>>> + }
>>> }
>>>
>>> #ifdef CONFIG_KFENCE
>>> @@ -1163,7 +1199,7 @@ static void __init map_mem(void)
>>> __map_memblock(kernel_start, init_begin, PAGE_KERNEL,
>>> flags | NO_CONT_MAPPINGS);
>>> __map_memblock(init_end, kernel_end, PAGE_KERNEL,
>>> - flags | NO_CONT_MAPPINGS);
>>> + flags | NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS);
>>>
>>> /* map all the memory banks */
>>> for_each_mem_range(i, &start, &end) {
>>> @@ -1176,8 +1212,6 @@ static void __init map_mem(void)
>>> flags);
>>> }
>>>
>>> - __map_memblock(init_end, kernel_end, PAGE_KERNEL_RO,
>>> - flags | NO_CONT_MAPPINGS);
>>
>> In the previous patch, perhaps this should be moved to
>> mark_linear_text_alias_ro() and combined with the update_mapping_prot() there?
>>
>
> Why? Isn't it better to just remap it r/o from the outset if it never
> needs to be mapped r/w to begin with?
>
> The same applies to the rodata region but -again- it is the root page
> tables that are manipulated via the writable linear alias during boot.
>
> I'll try to address all of that in the next rev - thanks.
Cool, I'll look out for it.
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH v2 08/10] arm64: mm: Don't abuse memblock NOMAP to check for overlaps
2026-01-27 11:00 ` Ryan Roberts
@ 2026-01-27 11:03 ` Ard Biesheuvel
2026-01-27 11:09 ` Ryan Roberts
0 siblings, 1 reply; 38+ messages in thread
From: Ard Biesheuvel @ 2026-01-27 11:03 UTC (permalink / raw)
To: Ryan Roberts
Cc: linux-kernel, linux-arm-kernel, will, catalin.marinas,
mark.rutland, Anshuman Khandual, Liz Prucka, Seth Jenkins,
Kees Cook, linux-hardening
On Tue, 27 Jan 2026 at 12:00, Ryan Roberts <ryan.roberts@arm.com> wrote:
>
> On 27/01/2026 10:47, Ard Biesheuvel wrote:
> > On Tue, 27 Jan 2026 at 11:39, Ryan Roberts <ryan.roberts@arm.com> wrote:
> >>
> >> On 27/01/2026 10:27, Ard Biesheuvel wrote:
> >>> On Tue, 27 Jan 2026 at 11:21, Ryan Roberts <ryan.roberts@arm.com> wrote:
> >>>>
> >>>> On 26/01/2026 09:26, Ard Biesheuvel wrote:
> >>>>> From: Ard Biesheuvel <ardb@kernel.org>
> >>>>>
> >>>>> Now that the DRAM mapping routines respect existing table mappings and
> >>>>> contiguous block and page mappings, it is no longer needed to fiddle
> >>>>> with the memblock tables to set and clear the NOMAP attribute. Instead,
> >>>>> map the kernel text and rodata alias first, avoiding contiguous
> >>>>> mappings, so that they will not be added later when mapping the
> >>>>> memblocks.
> >>>>
> >>>> Should we do something similar for kfence? Currently we have
> >>>> arm64_kfence_alloc_pool() which marks some memory NOMAP then
> >>>> arm64_kfence_map_pool() which PTE-maps it and clears NOMAP. Presumably we could
> >>>> rationalize into a single function that does it all, prior to mapping the bulk
> >>>> of the linear map?
> >>>>
> >>>
> >>> Yeah, good point - I did not spot that but I will address it in the
> >>> next revision.
> >>>
> >>>>>
> >>>>> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> >>>>> ---
> >>>>> arch/arm64/mm/mmu.c | 27 ++++++++------------
> >>>>> 1 file changed, 10 insertions(+), 17 deletions(-)
> >>>>>
> >>>>> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> >>>>> index 80587cd47ce7..18415d4743bf 100644
> >>>>> --- a/arch/arm64/mm/mmu.c
> >>>>> +++ b/arch/arm64/mm/mmu.c
> >>>>> @@ -1149,12 +1149,17 @@ static void __init map_mem(void)
> >>>>> flags |= NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS;
> >>>>>
> >>>>> /*
> >>>>> - * Take care not to create a writable alias for the
> >>>>> - * read-only text and rodata sections of the kernel image.
> >>>>> - * So temporarily mark them as NOMAP to skip mappings in
> >>>>> - * the following for-loop
> >>>>> + * Map the linear alias of the [_text, __init_begin) interval
> >>>>> + * as non-executable now, and remove the write permission in
> >>>>> + * mark_linear_text_alias_ro() above (which will be called after
> >>>>> + * alternative patching has completed). This makes the contents
> >>>>> + * of the region accessible to subsystems such as hibernate,
> >>>>> + * but protects it from inadvertent modification or execution.
> >>>>> + * Note that contiguous mappings cannot be remapped in this way,
> >>>>> + * so we should avoid them here.
> >>>>> */
> >>>>> - memblock_mark_nomap(kernel_start, kernel_end - kernel_start);
> >>>>> + __map_memblock(kernel_start, kernel_end, PAGE_KERNEL,
> >>>>> + flags | NO_CONT_MAPPINGS);
> >>>>
> >>>> So the reason to disallow cont mappings is because we need to modify the
> >>>> permissions later? It _is_ safe to change permissions on a live contiguous
> >>>> mapping in this way. That was clarified in the architecture a couple of years
> >>>> back and we rely on it for contpte_wrprotect_ptes(); see comment there.
> >>>>
> >>>
> >>> OK, good to know - I was hoping to get your take on this ...
> >>>
> >>>> I think we could relax this?
> >>>>
> >>>
> >>> OK, I suppose that means that we can drop the NO_CONT_MAPPINGS here,
> >>> but we still need to map the kernel text/rodata alias initially to
> >>> ensure that no block mappings are created that would need to broken
> >>> down, right?
> >>
> >> Yes, but...
> >>
> >> I think your intent is that the multiple __map_memblock() calls are just
> >> controlling the allowed leaf mapping sizes.
> >
> > Indeed.
> >
> >> It becomes problematic if the 2
> >> calls use different permissions... which they do.
> >>
> >> PAGE_KERNEL vs pgprot_tagged(PAGE_KERNEL).
> >>
> >> Is it possible that the text/rodata section ends up tagged, which is not intended?
> >>
> >
> >
> > OK so toggling the R/O attribute on a live contiguous mapping is
> > permitted (provided that ultimately, the entire contiguous region is
> > updated accordingly) but the same doesn't apply to MT_NORMAL vs
> > MT_NORMAL_TAGGED, right?
>
> This is the rule:
>
> RJQQTC
> For a TLB lookup in a contiguous region mapped by translation table entries that
> have consistent values for the Contiguous bit, but have the OA, attributes, or
> permissions misprogrammed, that TLB lookup is permitted to produce an OA, access
> permissions, and memory attributes that are consistent with any one of the
> programmed translation table values.
>
> So, yes, it is fine to modify the attributes (and I assume the memory type
> counts as attributes) on the live mapping...
>
OK.
> >
> > So let's use just the same prot and flags for the initial mapping, and
> > use MT_NORMAL_TAGGED when we remap the text alias R/O.
>
> ...but that wasn't my point. I belive the intent is that all of the linear map
> uses MT_NORMAL_TAGGED except for the kernel text and rodata, which uses
> MT_NORMAL. In some configs (e.g. force_pte_mapping() == true), your change will
> result in all the linear map, including text and rodata being MT_NORMAL_TAGGED.
>
I didn't think that would matter tbh. But if it does, are we fine as
long as we change it back to MT_NORMAL by the time we remap the region
read-only?
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH v2 08/10] arm64: mm: Don't abuse memblock NOMAP to check for overlaps
2026-01-27 11:03 ` Ard Biesheuvel
@ 2026-01-27 11:09 ` Ryan Roberts
0 siblings, 0 replies; 38+ messages in thread
From: Ryan Roberts @ 2026-01-27 11:09 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: linux-kernel, linux-arm-kernel, will, catalin.marinas,
mark.rutland, Anshuman Khandual, Liz Prucka, Seth Jenkins,
Kees Cook, linux-hardening
On 27/01/2026 11:03, Ard Biesheuvel wrote:
> On Tue, 27 Jan 2026 at 12:00, Ryan Roberts <ryan.roberts@arm.com> wrote:
>>
>> On 27/01/2026 10:47, Ard Biesheuvel wrote:
>>> On Tue, 27 Jan 2026 at 11:39, Ryan Roberts <ryan.roberts@arm.com> wrote:
>>>>
>>>> On 27/01/2026 10:27, Ard Biesheuvel wrote:
>>>>> On Tue, 27 Jan 2026 at 11:21, Ryan Roberts <ryan.roberts@arm.com> wrote:
>>>>>>
>>>>>> On 26/01/2026 09:26, Ard Biesheuvel wrote:
>>>>>>> From: Ard Biesheuvel <ardb@kernel.org>
>>>>>>>
>>>>>>> Now that the DRAM mapping routines respect existing table mappings and
>>>>>>> contiguous block and page mappings, it is no longer needed to fiddle
>>>>>>> with the memblock tables to set and clear the NOMAP attribute. Instead,
>>>>>>> map the kernel text and rodata alias first, avoiding contiguous
>>>>>>> mappings, so that they will not be added later when mapping the
>>>>>>> memblocks.
>>>>>>
>>>>>> Should we do something similar for kfence? Currently we have
>>>>>> arm64_kfence_alloc_pool() which marks some memory NOMAP then
>>>>>> arm64_kfence_map_pool() which PTE-maps it and clears NOMAP. Presumably we could
>>>>>> rationalize into a single function that does it all, prior to mapping the bulk
>>>>>> of the linear map?
>>>>>>
>>>>>
>>>>> Yeah, good point - I did not spot that but I will address it in the
>>>>> next revision.
>>>>>
>>>>>>>
>>>>>>> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
>>>>>>> ---
>>>>>>> arch/arm64/mm/mmu.c | 27 ++++++++------------
>>>>>>> 1 file changed, 10 insertions(+), 17 deletions(-)
>>>>>>>
>>>>>>> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
>>>>>>> index 80587cd47ce7..18415d4743bf 100644
>>>>>>> --- a/arch/arm64/mm/mmu.c
>>>>>>> +++ b/arch/arm64/mm/mmu.c
>>>>>>> @@ -1149,12 +1149,17 @@ static void __init map_mem(void)
>>>>>>> flags |= NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS;
>>>>>>>
>>>>>>> /*
>>>>>>> - * Take care not to create a writable alias for the
>>>>>>> - * read-only text and rodata sections of the kernel image.
>>>>>>> - * So temporarily mark them as NOMAP to skip mappings in
>>>>>>> - * the following for-loop
>>>>>>> + * Map the linear alias of the [_text, __init_begin) interval
>>>>>>> + * as non-executable now, and remove the write permission in
>>>>>>> + * mark_linear_text_alias_ro() above (which will be called after
>>>>>>> + * alternative patching has completed). This makes the contents
>>>>>>> + * of the region accessible to subsystems such as hibernate,
>>>>>>> + * but protects it from inadvertent modification or execution.
>>>>>>> + * Note that contiguous mappings cannot be remapped in this way,
>>>>>>> + * so we should avoid them here.
>>>>>>> */
>>>>>>> - memblock_mark_nomap(kernel_start, kernel_end - kernel_start);
>>>>>>> + __map_memblock(kernel_start, kernel_end, PAGE_KERNEL,
>>>>>>> + flags | NO_CONT_MAPPINGS);
>>>>>>
>>>>>> So the reason to disallow cont mappings is because we need to modify the
>>>>>> permissions later? It _is_ safe to change permissions on a live contiguous
>>>>>> mapping in this way. That was clarified in the architecture a couple of years
>>>>>> back and we rely on it for contpte_wrprotect_ptes(); see comment there.
>>>>>>
>>>>>
>>>>> OK, good to know - I was hoping to get your take on this ...
>>>>>
>>>>>> I think we could relax this?
>>>>>>
>>>>>
>>>>> OK, I suppose that means that we can drop the NO_CONT_MAPPINGS here,
>>>>> but we still need to map the kernel text/rodata alias initially to
>>>>> ensure that no block mappings are created that would need to broken
>>>>> down, right?
>>>>
>>>> Yes, but...
>>>>
>>>> I think your intent is that the multiple __map_memblock() calls are just
>>>> controlling the allowed leaf mapping sizes.
>>>
>>> Indeed.
>>>
>>>> It becomes problematic if the 2
>>>> calls use different permissions... which they do.
>>>>
>>>> PAGE_KERNEL vs pgprot_tagged(PAGE_KERNEL).
>>>>
>>>> Is it possible that the text/rodata section ends up tagged, which is not intended?
>>>>
>>>
>>>
>>> OK so toggling the R/O attribute on a live contiguous mapping is
>>> permitted (provided that ultimately, the entire contiguous region is
>>> updated accordingly) but the same doesn't apply to MT_NORMAL vs
>>> MT_NORMAL_TAGGED, right?
>>
>> This is the rule:
>>
>> RJQQTC
>> For a TLB lookup in a contiguous region mapped by translation table entries that
>> have consistent values for the Contiguous bit, but have the OA, attributes, or
>> permissions misprogrammed, that TLB lookup is permitted to produce an OA, access
>> permissions, and memory attributes that are consistent with any one of the
>> programmed translation table values.
>>
>> So, yes, it is fine to modify the attributes (and I assume the memory type
>> counts as attributes) on the live mapping...
>>
>
> OK.
>
>>>
>>> So let's use just the same prot and flags for the initial mapping, and
>>> use MT_NORMAL_TAGGED when we remap the text alias R/O.
>>
>> ...but that wasn't my point. I belive the intent is that all of the linear map
>> uses MT_NORMAL_TAGGED except for the kernel text and rodata, which uses
>> MT_NORMAL. In some configs (e.g. force_pte_mapping() == true), your change will
>> result in all the linear map, including text and rodata being MT_NORMAL_TAGGED.
>>
>
> I didn't think that would matter tbh. But if it does, are we fine as
> long as we change it back to MT_NORMAL by the time we remap the region
> read-only?
I have no idea. I worry MT_NORMAL_TAGGED on the text might imply a performance
cost? But not sure about functional... Will ask around.
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH v2 03/10] arm64: mm: Permit contiguous descriptors to be rewritten
2026-01-27 9:45 ` Ryan Roberts
@ 2026-01-27 15:03 ` Ard Biesheuvel
2026-01-27 16:59 ` Ryan Roberts
0 siblings, 1 reply; 38+ messages in thread
From: Ard Biesheuvel @ 2026-01-27 15:03 UTC (permalink / raw)
To: Ryan Roberts
Cc: Ard Biesheuvel, linux-kernel, linux-arm-kernel, will,
catalin.marinas, mark.rutland, Anshuman Khandual, Liz Prucka,
Seth Jenkins, Kees Cook, linux-hardening
On Tue, 27 Jan 2026 at 10:45, Ryan Roberts <ryan.roberts@arm.com> wrote:
>
> On 26/01/2026 09:26, Ard Biesheuvel wrote:
> > From: Ard Biesheuvel <ardb@kernel.org>
> >
> > Currently, pgattr_change_is_safe() is overly pedantic when it comes to
> > descriptors with the contiguous hint attribute set, as it rejects
> > assignments even if the old and the new value are the same.
> >
> > So relax the check to allow that.
>
> But why do we require the relaxation? Why are we re-writing a PTE in the first
> place? Either the caller already knows it's the same in which case it can be
> avoided, or it doesn't know in which case it is accidentally the same and couple
> probably just as easily been accidentally different? So it's better to warn
> regardless I would think?
>
Based on rule RJQQTC in your reply to another patch in this series, my
conclusion here is that we can drop this check entirely.
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH v2 03/10] arm64: mm: Permit contiguous descriptors to be rewritten
2026-01-27 15:03 ` Ard Biesheuvel
@ 2026-01-27 16:59 ` Ryan Roberts
2026-01-27 17:02 ` Ard Biesheuvel
0 siblings, 1 reply; 38+ messages in thread
From: Ryan Roberts @ 2026-01-27 16:59 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: Ard Biesheuvel, linux-kernel, linux-arm-kernel, will,
catalin.marinas, mark.rutland, Anshuman Khandual, Liz Prucka,
Seth Jenkins, Kees Cook, linux-hardening
On 27/01/2026 15:03, Ard Biesheuvel wrote:
> On Tue, 27 Jan 2026 at 10:45, Ryan Roberts <ryan.roberts@arm.com> wrote:
>>
>> On 26/01/2026 09:26, Ard Biesheuvel wrote:
>>> From: Ard Biesheuvel <ardb@kernel.org>
>>>
>>> Currently, pgattr_change_is_safe() is overly pedantic when it comes to
>>> descriptors with the contiguous hint attribute set, as it rejects
>>> assignments even if the old and the new value are the same.
>>>
>>> So relax the check to allow that.
>>
>> But why do we require the relaxation? Why are we re-writing a PTE in the first
>> place? Either the caller already knows it's the same in which case it can be
>> avoided, or it doesn't know in which case it is accidentally the same and couple
>> probably just as easily been accidentally different? So it's better to warn
>> regardless I would think?
>>
>
> Based on rule RJQQTC in your reply to another patch in this series, my
> conclusion here is that we can drop this check entirely.
Hmm, I don't think that would be quite right; The rule permits _some_ bits of
the PTE to change in a live mapping as long as the CONT bit remains unchanged.
If you change the CONT bit on a live mapping, you could end up with overlapping
TLB entries which would not go well on a system without bbml2.
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH v2 03/10] arm64: mm: Permit contiguous descriptors to be rewritten
2026-01-27 16:59 ` Ryan Roberts
@ 2026-01-27 17:02 ` Ard Biesheuvel
2026-01-27 17:37 ` Ryan Roberts
0 siblings, 1 reply; 38+ messages in thread
From: Ard Biesheuvel @ 2026-01-27 17:02 UTC (permalink / raw)
To: Ryan Roberts
Cc: linux-kernel, linux-arm-kernel, will, catalin.marinas,
mark.rutland, Anshuman Khandual, Liz Prucka, Seth Jenkins,
Kees Cook, linux-hardening
On Tue, 27 Jan 2026, at 17:59, Ryan Roberts wrote:
> On 27/01/2026 15:03, Ard Biesheuvel wrote:
>> On Tue, 27 Jan 2026 at 10:45, Ryan Roberts <ryan.roberts@arm.com> wrote:
>>>
>>> On 26/01/2026 09:26, Ard Biesheuvel wrote:
>>>> From: Ard Biesheuvel <ardb@kernel.org>
>>>>
>>>> Currently, pgattr_change_is_safe() is overly pedantic when it comes to
>>>> descriptors with the contiguous hint attribute set, as it rejects
>>>> assignments even if the old and the new value are the same.
>>>>
>>>> So relax the check to allow that.
>>>
>>> But why do we require the relaxation? Why are we re-writing a PTE in the first
>>> place? Either the caller already knows it's the same in which case it can be
>>> avoided, or it doesn't know in which case it is accidentally the same and couple
>>> probably just as easily been accidentally different? So it's better to warn
>>> regardless I would think?
>>>
>>
>> Based on rule RJQQTC in your reply to another patch in this series, my
>> conclusion here is that we can drop this check entirely.
>
> Hmm, I don't think that would be quite right; The rule permits _some_ bits of
> the PTE to change in a live mapping as long as the CONT bit remains unchanged.
> If you change the CONT bit on a live mapping, you could end up with overlapping
> TLB entries which would not go well on a system without bbml2.
I'm not suggesting we add it to 'mask', just to remove the check that forbids any manipulation of an entry that has PTE_CONT set. So toggling PTE_CONT itself would still be caught by the check.
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH v2 03/10] arm64: mm: Permit contiguous descriptors to be rewritten
2026-01-27 17:02 ` Ard Biesheuvel
@ 2026-01-27 17:37 ` Ryan Roberts
0 siblings, 0 replies; 38+ messages in thread
From: Ryan Roberts @ 2026-01-27 17:37 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: linux-kernel, linux-arm-kernel, will, catalin.marinas,
mark.rutland, Anshuman Khandual, Liz Prucka, Seth Jenkins,
Kees Cook, linux-hardening
On 27/01/2026 17:02, Ard Biesheuvel wrote:
>
>
> On Tue, 27 Jan 2026, at 17:59, Ryan Roberts wrote:
>> On 27/01/2026 15:03, Ard Biesheuvel wrote:
>>> On Tue, 27 Jan 2026 at 10:45, Ryan Roberts <ryan.roberts@arm.com> wrote:
>>>>
>>>> On 26/01/2026 09:26, Ard Biesheuvel wrote:
>>>>> From: Ard Biesheuvel <ardb@kernel.org>
>>>>>
>>>>> Currently, pgattr_change_is_safe() is overly pedantic when it comes to
>>>>> descriptors with the contiguous hint attribute set, as it rejects
>>>>> assignments even if the old and the new value are the same.
>>>>>
>>>>> So relax the check to allow that.
>>>>
>>>> But why do we require the relaxation? Why are we re-writing a PTE in the first
>>>> place? Either the caller already knows it's the same in which case it can be
>>>> avoided, or it doesn't know in which case it is accidentally the same and couple
>>>> probably just as easily been accidentally different? So it's better to warn
>>>> regardless I would think?
>>>>
>>>
>>> Based on rule RJQQTC in your reply to another patch in this series, my
>>> conclusion here is that we can drop this check entirely.
>>
>> Hmm, I don't think that would be quite right; The rule permits _some_ bits of
>> the PTE to change in a live mapping as long as the CONT bit remains unchanged.
>> If you change the CONT bit on a live mapping, you could end up with overlapping
>> TLB entries which would not go well on a system without bbml2.
>
> I'm not suggesting we add it to 'mask', just to remove the check that forbids any manipulation of an entry that has PTE_CONT set. So toggling PTE_CONT itself would still be caught by the check.
Ahh, sorry, wasn't looking at the whole function. Yes,I agree that makes sense then.
Now that I'm looking at the function, I find it odd that PTE_UXN and PTE_USER
are not included in the mask. These bits are used (along with PTE_PXN and
PTE_WRITE, which are in the mask) to form the PI index, when PI is enabled.
Seems odd that we can change some bits of the index but not others... But that
is probably for another day.
^ permalink raw reply [flat|nested] 38+ messages in thread
end of thread, other threads:[~2026-01-27 17:37 UTC | newest]
Thread overview: 38+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-26 9:26 [PATCH v2 00/10] arm64: Unmap linear alias of kernel data/bss Ard Biesheuvel
2026-01-26 9:26 ` [PATCH v2 01/10] arm64: Move the zero page to rodata Ard Biesheuvel
2026-01-27 9:34 ` Ryan Roberts
2026-01-27 9:49 ` Ard Biesheuvel
2026-01-27 10:03 ` Ryan Roberts
2026-01-27 10:50 ` Ard Biesheuvel
2026-01-26 9:26 ` [PATCH v2 02/10] arm64: Move fixmap page tables to end of kernel image Ard Biesheuvel
2026-01-27 9:42 ` Ryan Roberts
2026-01-26 9:26 ` [PATCH v2 03/10] arm64: mm: Permit contiguous descriptors to be rewritten Ard Biesheuvel
2026-01-27 9:45 ` Ryan Roberts
2026-01-27 15:03 ` Ard Biesheuvel
2026-01-27 16:59 ` Ryan Roberts
2026-01-27 17:02 ` Ard Biesheuvel
2026-01-27 17:37 ` Ryan Roberts
2026-01-26 9:26 ` [PATCH v2 04/10] arm64: mm: Preserve existing table mappings when mapping DRAM Ard Biesheuvel
2026-01-27 9:58 ` Ryan Roberts
2026-01-26 9:26 ` [PATCH v2 05/10] arm64: mm: Preserve non-contiguous descriptors " Ard Biesheuvel
2026-01-27 9:58 ` Ryan Roberts
2026-01-26 9:26 ` [PATCH v2 06/10] arm64: mm: Remove bogus stop condition from map_mem() loop Ard Biesheuvel
2026-01-27 10:06 ` Ryan Roberts
2026-01-26 9:26 ` [PATCH v2 07/10] arm64: mm: Drop redundant pgd_t* argument from map_mem() Ard Biesheuvel
2026-01-27 10:10 ` Ryan Roberts
2026-01-26 9:26 ` [PATCH v2 08/10] arm64: mm: Don't abuse memblock NOMAP to check for overlaps Ard Biesheuvel
2026-01-27 10:21 ` Ryan Roberts
2026-01-27 10:27 ` Ard Biesheuvel
2026-01-27 10:39 ` Ryan Roberts
2026-01-27 10:47 ` Ard Biesheuvel
2026-01-27 11:00 ` Ryan Roberts
2026-01-27 11:03 ` Ard Biesheuvel
2026-01-27 11:09 ` Ryan Roberts
2026-01-26 9:26 ` [PATCH v2 09/10] arm64: mm: Map the kernel data/bss read-only in the linear map Ard Biesheuvel
2026-01-27 10:33 ` Ryan Roberts
2026-01-27 10:36 ` Ard Biesheuvel
2026-01-27 10:41 ` Ryan Roberts
2026-01-26 9:26 ` [PATCH v2 10/10] arm64: mm: Unmap kernel data/bss entirely from " Ard Biesheuvel
2026-01-27 10:50 ` Ryan Roberts
2026-01-27 10:54 ` Ard Biesheuvel
2026-01-27 11:02 ` Ryan Roberts
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox