]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
arm64: mm: Map the kernel data/bss read-only in the linear map
authorArd Biesheuvel <ardb@kernel.org>
Fri, 29 May 2026 15:02:05 +0000 (17:02 +0200)
committerWill Deacon <will@kernel.org>
Tue, 2 Jun 2026 15:29:16 +0000 (16:29 +0100)
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.

Reviewed-by: Kevin Brodsky <kevin.brodsky@arm.com>
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Will Deacon <will@kernel.org>
arch/arm64/mm/mmu.c

index 6b6b2dac41f521651f7ceb2d928c031f096962ef..7f7693a5dfff8557c0bcc454d61062b685b12fcb 100644 (file)
@@ -1138,7 +1138,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(__bss_stop);
        phys_addr_t start, end;
        int flags = NO_EXEC_MAPPINGS;
        u64 i;
@@ -1173,7 +1175,11 @@ static void __init map_mem(void)
         * contents of the region accessible to subsystems such as hibernate,
         * but protects it from inadvertent modification or execution.
         */
-       __map_memblock(kernel_start, kernel_end, pgprot_tagged(PAGE_KERNEL),
+       __map_memblock(kernel_start, init_begin, pgprot_tagged(PAGE_KERNEL),
+                      flags);
+
+       /* Map the kernel data/bss so it can be remapped later */
+       __map_memblock(init_end, kernel_end, pgprot_tagged(PAGE_KERNEL),
                       flags);
 
        /* map all the memory banks */
@@ -1186,6 +1192,11 @@ static void __init map_mem(void)
                __map_memblock(start, end, pgprot_tagged(PAGE_KERNEL),
                               flags);
        }
+
+       /* Map the kernel data/bss read-only in the linear map */
+       __map_memblock(init_end, kernel_end, PAGE_KERNEL_RO, flags);
+       flush_tlb_kernel_range((unsigned long)lm_alias(__init_end),
+                              (unsigned long)lm_alias(__bss_stop));
 }
 
 void mark_rodata_ro(void)