]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
s390: add proper __ro_after_init support
authorHeiko Carstens <heiko.carstens@de.ibm.com>
Tue, 7 Jun 2016 08:12:55 +0000 (10:12 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Mon, 13 Jun 2016 13:58:23 +0000 (15:58 +0200)
On s390 __ro_after_init is currently mapped to __read_mostly which
means that data marked as __ro_after_init will not be protected.

Reason for this is that the common code __ro_after_init implementation
is x86 centric: the ro_after_init data section was added to rodata,
since x86 enables write protection to kernel text and rodata very
late. On s390 we have write protection for these sections enabled with
the initial page tables. So adding the ro_after_init data section to
rodata does not work on s390.

In order to make __ro_after_init work properly on s390 move the
ro_after_init data, right behind rodata. Unlike the rodata section it
will be marked read-only later after all init calls happened.

This s390 specific implementation adds new __start_ro_after_init and
__end_ro_after_init labels. Everything in between will be marked
read-only after the init calls happened. In addition to the
__ro_after_init data move also the exception table there, since from a
practical point of view it fits the __ro_after_init requirements.

Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/include/asm/cache.h
arch/s390/include/asm/sections.h
arch/s390/kernel/vmlinux.lds.S
arch/s390/mm/init.c
arch/s390/mm/vmem.c

index 22da3b34c6557dcb979d6187ed9424769a17464e..4d7ccac5fd1d693e3875f2eac011d46ff3750a0e 100644 (file)
@@ -15,7 +15,4 @@
 
 #define __read_mostly __attribute__((__section__(".data..read_mostly")))
 
-/* Read-only memory is marked before mark_rodata_ro() is called. */
-#define __ro_after_init __read_mostly
-
 #endif
index fbd9116eb17bf2c73d80952af2108eecdf4db1ed..5ce29fe100baaa0ee0dcaa987901691fb76e4044 100644 (file)
@@ -4,5 +4,6 @@
 #include <asm-generic/sections.h>
 
 extern char _eshared[], _ehead[];
+extern char __start_ro_after_init[], __end_ro_after_init[];
 
 #endif
index 0656f7cc7fb476f02cf637b4daaf58bcf5c35364..429bfd1119612caa93fbbcf390768d9eaeedc7fe 100644 (file)
@@ -11,6 +11,9 @@
  */
 #define BSS_FIRST_SECTIONS *(.bss..swapper_pg_dir)
 
+/* Handle ro_after_init data on our own. */
+#define RO_AFTER_INIT_DATA
+
 #include <asm-generic/vmlinux.lds.h>
 
 OUTPUT_FORMAT("elf64-s390", "elf64-s390", "elf64-s390")
@@ -56,7 +59,14 @@ SECTIONS
        _eshared = .;           /* End of shareable data */
        _sdata = .;             /* Start of data section */
 
-       EXCEPTION_TABLE(16) :data
+       . = ALIGN(PAGE_SIZE);
+       __start_ro_after_init = .;
+       .data..ro_after_init : {
+                *(.data..ro_after_init)
+       }
+       EXCEPTION_TABLE(16)
+       . = ALIGN(PAGE_SIZE);
+       __end_ro_after_init = .;
 
        RW_DATA_SECTION(0x100, PAGE_SIZE, THREAD_SIZE)
 
index de2cdf4fbb9a9d9fae49d71cf290d86b2cb7acfc..f56a39bd8ba688afbc29832b63305fa32b3e725d 100644 (file)
@@ -111,9 +111,10 @@ void __init paging_init(void)
 
 void mark_rodata_ro(void)
 {
-       /* Text and rodata are already protected. Nothing to do here. */
-       pr_info("Write protecting the kernel read-only data: %luk\n",
-               ((unsigned long)&_eshared - (unsigned long)&_stext) >> 10);
+       unsigned long size = __end_ro_after_init - __start_ro_after_init;
+
+       set_memory_ro((unsigned long)__start_ro_after_init, size >> PAGE_SHIFT);
+       pr_info("Write protected read-only-after-init data: %luk\n", size >> 10);
 }
 
 void __init mem_init(void)
index a1e7c0b207e6e0533cde952d7c881307af8c9422..1848292766ef136868419e40aa2ca256249c9530 100644 (file)
@@ -373,14 +373,13 @@ out:
  */
 void __init vmem_map_init(void)
 {
-       unsigned long ro_start, ro_end;
+       unsigned long size = _eshared - _stext;
        struct memblock_region *reg;
 
        for_each_memblock(memory, reg)
                vmem_add_mem(reg->base, reg->size);
-       ro_start = PFN_ALIGN((unsigned long)&_stext);
-       ro_end = (unsigned long)&_eshared & PAGE_MASK;
-       set_memory_ro(ro_start, (ro_end - ro_start) >> PAGE_SHIFT);
+       set_memory_ro((unsigned long)_stext, size >> PAGE_SHIFT);
+       pr_info("Write protected kernel read-only data: %luk\n", size >> 10);
 }
 
 /*