BACKPORT: arm64: mm: Mark .rodata as RO
authorJeremy Linton <jeremy.linton@arm.com>
Fri, 19 Feb 2016 17:50:32 +0000 (11:50 -0600)
committerSami Tolvanen <samitolvanen@google.com>
Wed, 5 Oct 2016 15:09:05 +0000 (08:09 -0700)
Currently the .rodata section is actually still executable when DEBUG_RODATA
is enabled. This changes that so the .rodata is actually read only, no execute.
It also adds the .rodata section to the mem_init banner.

Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
Acked-by: Mark Rutland <mark.rutland@arm.com>
[catalin.marinas@arm.com: added vm_struct vmlinux_rodata in map_kernel()]
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Bug: 31374226
Change-Id: I6fd95beaf814fc91805da12c5329a57ce9008fd7
(cherry picked from commit 2f39b5f91eb4bccd786d194e70db1dccad784755)
Signed-off-by: Sami Tolvanen <samitolvanen@google.com>
arch/arm64/kernel/vmlinux.lds.S
arch/arm64/mm/init.c
arch/arm64/mm/mmu.c

index 87fd0556a1bd8330b3610308cc3fffd61a28b32e..f1d6c49dcc5fdda4d10b6f3f2035bff73ff69aa8 100644 (file)
@@ -114,14 +114,14 @@ SECTIONS
                *(.got)                 /* Global offset table          */
        }
 
+       ALIGN_DEBUG_RO_MIN(PAGE_SIZE)
        _etext = .;                     /* End of text section */
 
-       RO_DATA(PAGE_SIZE)
-       EXCEPTION_TABLE(8)
+       RO_DATA(PAGE_SIZE)              /* everything from this point to     */
+       EXCEPTION_TABLE(8)              /* __init_begin will be marked RO NX */
        NOTES
 
        ALIGN_DEBUG_RO_MIN(PAGE_SIZE)
-       _etext = .;                     /* End of text and rodata section */
        __init_begin = .;
 
        INIT_TEXT_SECTION(8)
index 0db12e9e8765adee7d71b5a19660d23596fbebc7..6788780779963d078c3ec611b1f870d500b1737f 100644 (file)
@@ -376,6 +376,7 @@ void __init mem_init(void)
                  "    vmalloc : 0x%16lx - 0x%16lx   (%6ld GB)\n"
                  "      .init : 0x%p" " - 0x%p" "   (%6ld KB)\n"
                  "      .text : 0x%p" " - 0x%p" "   (%6ld KB)\n"
+                 "    .rodata : 0x%p" " - 0x%p" "   (%6ld KB)\n"
                  "      .data : 0x%p" " - 0x%p" "   (%6ld KB)\n"
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
                  "    vmemmap : 0x%16lx - 0x%16lx   (%6ld GB maximum)\n"
@@ -391,6 +392,7 @@ void __init mem_init(void)
                  MLG(VMALLOC_START, VMALLOC_END),
                  MLK_ROUNDUP(__init_begin, __init_end),
                  MLK_ROUNDUP(_text, _etext),
+                 MLK_ROUNDUP(__start_rodata, __init_begin),
                  MLK_ROUNDUP(_sdata, _edata),
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
                  MLG(VMEMMAP_START,
index 9dafcfde7c26f8202262bccf726473bf38b432c5..4b38f6b8806e0a73af6dc093a23d423d337cb63b 100644 (file)
@@ -386,14 +386,14 @@ static void create_mapping_late(phys_addr_t phys, unsigned long virt,
 static void __init __map_memblock(pgd_t *pgd, phys_addr_t start, phys_addr_t end)
 {
        unsigned long kernel_start = __pa(_stext);
-       unsigned long kernel_end = __pa(_etext);
+       unsigned long kernel_end = __pa(__init_begin);
 
        /*
         * Take care not to create a writable alias for the
         * read-only text and rodata sections of the kernel image.
         */
 
-       /* No overlap with the kernel text */
+       /* No overlap with the kernel text/rodata */
        if (end < kernel_start || start >= kernel_end) {
                __create_pgd_mapping(pgd, start, __phys_to_virt(start),
                                     end - start, PAGE_KERNEL,
@@ -402,7 +402,7 @@ static void __init __map_memblock(pgd_t *pgd, phys_addr_t start, phys_addr_t end
        }
 
        /*
-        * This block overlaps the kernel text mapping.
+        * This block overlaps the kernel text/rodata mapping.
         * Map the portion(s) which don't overlap.
         */
        if (start < kernel_start)
@@ -417,7 +417,7 @@ static void __init __map_memblock(pgd_t *pgd, phys_addr_t start, phys_addr_t end
                                     early_pgtable_alloc);
 
        /*
-        * Map the linear alias of the [_stext, _etext) interval as
+        * Map the linear alias of the [_stext, __init_begin) interval as
         * read-only/non-executable. This makes the contents of the
         * region accessible to subsystems such as hibernate, but
         * protects it from inadvertent modification or execution.
@@ -447,12 +447,18 @@ static void __init map_mem(pgd_t *pgd)
 
 void mark_rodata_ro(void)
 {
-       if (!IS_ENABLED(CONFIG_DEBUG_RODATA))
-               return;
+       unsigned long section_size;
 
+       section_size = (unsigned long)_etext - (unsigned long)_stext;
        create_mapping_late(__pa(_stext), (unsigned long)_stext,
-                               (unsigned long)__init_begin - (unsigned long)_stext,
-                               PAGE_KERNEL_ROX);
+                           section_size, PAGE_KERNEL_ROX);
+       /*
+        * mark .rodata as read only. Use __init_begin rather than __end_rodata
+        * to cover NOTES and EXCEPTION_TABLE.
+        */
+       section_size = (unsigned long)__init_begin - (unsigned long)__start_rodata;
+       create_mapping_late(__pa(__start_rodata), (unsigned long)__start_rodata,
+                           section_size, PAGE_KERNEL_RO);
 }
 
 void fixup_init(void)
@@ -491,9 +497,10 @@ static void __init map_kernel_chunk(pgd_t *pgd, void *va_start, void *va_end,
  */
 static void __init map_kernel(pgd_t *pgd)
 {
-       static struct vm_struct vmlinux_text, vmlinux_init, vmlinux_data;
+       static struct vm_struct vmlinux_text, vmlinux_rodata, vmlinux_init, vmlinux_data;
 
        map_kernel_chunk(pgd, _stext, _etext, PAGE_KERNEL_EXEC, &vmlinux_text);
+       map_kernel_chunk(pgd, __start_rodata, __init_begin, PAGE_KERNEL, &vmlinux_rodata);
        map_kernel_chunk(pgd, __init_begin, __init_end, PAGE_KERNEL_EXEC,
                         &vmlinux_init);
        map_kernel_chunk(pgd, _data, _end, PAGE_KERNEL, &vmlinux_data);