arm64: mmu: apply strict permissions to .init.text and .init.data
authorArd Biesheuvel <ard.biesheuvel@linaro.org>
Thu, 9 Mar 2017 20:52:03 +0000 (21:52 +0100)
committerCatalin Marinas <catalin.marinas@arm.com>
Thu, 23 Mar 2017 13:54:50 +0000 (13:54 +0000)
To avoid having mappings that are writable and executable at the same
time, split the init region into a .init.text region that is mapped
read-only, and a .init.data region that is mapped non-executable.

This is possible now that the alternative patching occurs via the linear
mapping, and the linear alias of the init region is always mapped writable
(but never executable).

Since the alternatives descriptions themselves are read-only data, move
those into the .init.text region.

Reviewed-by: Laura Abbott <labbott@redhat.com>
Reviewed-by: Mark Rutland <mark.rutland@arm.com>
Tested-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
arch/arm64/include/asm/sections.h
arch/arm64/kernel/vmlinux.lds.S
arch/arm64/mm/mmu.c

index 4e7e7067afdb048d464d9287f42f16ebc26aeb7b..941267caa39c2b2389ec56af670342ae431c4a2d 100644 (file)
@@ -24,6 +24,8 @@ extern char __hibernate_exit_text_start[], __hibernate_exit_text_end[];
 extern char __hyp_idmap_text_start[], __hyp_idmap_text_end[];
 extern char __hyp_text_start[], __hyp_text_end[];
 extern char __idmap_text_start[], __idmap_text_end[];
+extern char __initdata_begin[], __initdata_end[];
+extern char __inittext_begin[], __inittext_end[];
 extern char __irqentry_text_start[], __irqentry_text_end[];
 extern char __mmuoff_data_start[], __mmuoff_data_end[];
 
index b8deffa9e1bf3ec06d9411afb7849695df27d6d2..2c93d259046c330497ff77c4e4be421fd6604859 100644 (file)
@@ -143,12 +143,27 @@ SECTIONS
 
        . = ALIGN(SEGMENT_ALIGN);
        __init_begin = .;
+       __inittext_begin = .;
 
        INIT_TEXT_SECTION(8)
        .exit.text : {
                ARM_EXIT_KEEP(EXIT_TEXT)
        }
 
+       . = ALIGN(4);
+       .altinstructions : {
+               __alt_instructions = .;
+               *(.altinstructions)
+               __alt_instructions_end = .;
+       }
+       .altinstr_replacement : {
+               *(.altinstr_replacement)
+       }
+
+       . = ALIGN(PAGE_SIZE);
+       __inittext_end = .;
+       __initdata_begin = .;
+
        .init.data : {
                INIT_DATA
                INIT_SETUP(16)
@@ -164,15 +179,6 @@ SECTIONS
 
        PERCPU_SECTION(L1_CACHE_BYTES)
 
-       . = ALIGN(4);
-       .altinstructions : {
-               __alt_instructions = .;
-               *(.altinstructions)
-               __alt_instructions_end = .;
-       }
-       .altinstr_replacement : {
-               *(.altinstr_replacement)
-       }
        .rela : ALIGN(8) {
                *(.rela .rela*)
        }
@@ -181,6 +187,7 @@ SECTIONS
        __rela_size     = SIZEOF(.rela);
 
        . = ALIGN(SEGMENT_ALIGN);
+       __initdata_end = .;
        __init_end = .;
 
        _data = .;
index 300e98e8cd63870cf7fad2ba0c59865b660d6495..75e21c33caff1a76ac6ba5c0f8df8c72eb1fcc3e 100644 (file)
@@ -459,7 +459,8 @@ early_param("rodata", parse_rodata);
  */
 static void __init map_kernel(pgd_t *pgd)
 {
-       static struct vm_struct vmlinux_text, vmlinux_rodata, vmlinux_init, vmlinux_data;
+       static struct vm_struct vmlinux_text, vmlinux_rodata, vmlinux_inittext,
+                               vmlinux_initdata, vmlinux_data;
 
        /*
         * External debuggers may need to write directly to the text
@@ -469,9 +470,12 @@ static void __init map_kernel(pgd_t *pgd)
        pgprot_t text_prot = rodata_enabled ? PAGE_KERNEL_ROX : PAGE_KERNEL_EXEC;
 
        map_kernel_segment(pgd, _text, _etext, text_prot, &vmlinux_text);
-       map_kernel_segment(pgd, __start_rodata, __init_begin, PAGE_KERNEL, &vmlinux_rodata);
-       map_kernel_segment(pgd, __init_begin, __init_end, PAGE_KERNEL_EXEC,
-                          &vmlinux_init);
+       map_kernel_segment(pgd, __start_rodata, __inittext_begin, PAGE_KERNEL,
+                          &vmlinux_rodata);
+       map_kernel_segment(pgd, __inittext_begin, __inittext_end, text_prot,
+                          &vmlinux_inittext);
+       map_kernel_segment(pgd, __initdata_begin, __initdata_end, PAGE_KERNEL,
+                          &vmlinux_initdata);
        map_kernel_segment(pgd, _data, _end, PAGE_KERNEL, &vmlinux_data);
 
        if (!pgd_val(*pgd_offset_raw(pgd, FIXADDR_START))) {