powerpc/mm: Mark __init memory no-execute when STRICT_KERNEL_RWX=y
authorMichael Ellerman <mpe@ellerman.id.au>
Fri, 14 Jul 2017 06:51:23 +0000 (16:51 +1000)
committerMichael Ellerman <mpe@ellerman.id.au>
Tue, 18 Jul 2017 09:54:24 +0000 (19:54 +1000)
Currently even with STRICT_KERNEL_RWX we leave the __init text marked
executable after init, which is bad.

Add a hook to mark it NX (no-execute) before we free it, and implement
it for radix and hash.

Note that we use __init_end as the end address, not _einittext,
because overlaps_kernel_text() uses __init_end, because there are
additional executable sections other than .init.text between
__init_begin and __init_end.

Tested on radix and hash with:

  0:mon> p $__init_begin
  *** 400 exception occurred

Fixes: 1e0fc9d1eb2b ("powerpc/Kconfig: Enable STRICT_KERNEL_RWX for some configs")
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/include/asm/book3s/64/hash.h
arch/powerpc/include/asm/book3s/64/pgtable.h
arch/powerpc/include/asm/book3s/64/radix.h
arch/powerpc/include/asm/pgtable.h
arch/powerpc/mm/mem.c
arch/powerpc/mm/pgtable-hash64.c
arch/powerpc/mm/pgtable-radix.c
arch/powerpc/mm/pgtable_64.c

index 0ce513f2926f12680ce1570266550eb8b2b09eeb..36fc7bfe9e1140d1e5eabc781199851a6445d51a 100644 (file)
@@ -91,6 +91,7 @@ static inline int hash__pgd_bad(pgd_t pgd)
 }
 #ifdef CONFIG_STRICT_KERNEL_RWX
 extern void hash__mark_rodata_ro(void);
+extern void hash__mark_initmem_nx(void);
 #endif
 
 extern void hpte_need_flush(struct mm_struct *mm, unsigned long addr,
index c0737c86a36272b1df213a41c4c75426c16d9178..d1da415e283cd270d8d2d089508558d369c7cf98 100644 (file)
@@ -1192,5 +1192,6 @@ static inline const int pud_pfn(pud_t pud)
        BUILD_BUG();
        return 0;
 }
+
 #endif /* __ASSEMBLY__ */
 #endif /* _ASM_POWERPC_BOOK3S_64_PGTABLE_H_ */
index 487709ff6875bd61d6b6cc7c8652c7e27f8404a2..544440b5aff395c1d00076af87dec8b15628dd77 100644 (file)
 
 #ifdef CONFIG_STRICT_KERNEL_RWX
 extern void radix__mark_rodata_ro(void);
+extern void radix__mark_initmem_nx(void);
 #endif
 
 static inline unsigned long __radix_pte_update(pte_t *ptep, unsigned long clr,
index dd01212935acacd32504e0ab2783b6670674f744..afae9a336136a4916c9912d3fd7f8c8f268406f2 100644 (file)
@@ -80,6 +80,13 @@ unsigned long vmalloc_to_phys(void *vmalloc_addr);
 
 void pgtable_cache_add(unsigned shift, void (*ctor)(void *));
 void pgtable_cache_init(void);
+
+#ifdef CONFIG_STRICT_KERNEL_RWX
+void mark_initmem_nx(void);
+#else
+static inline void mark_initmem_nx(void) { }
+#endif
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* _ASM_POWERPC_PGTABLE_H */
index 8541f18694a4a6d8003b32ad29f7c192f190ef6e..46b4e67d2372328231b47c7e225af6d780fde022 100644 (file)
@@ -402,6 +402,7 @@ void __init mem_init(void)
 void free_initmem(void)
 {
        ppc_md.progress = ppc_printk_progress;
+       mark_initmem_nx();
        free_initmem_default(POISON_FREE_INITMEM);
 }
 
index 73019c52141ff8c11c55822b162307575e5d7b53..443a2c66a30467d7bea260d6a7d01df19d55c33a 100644 (file)
@@ -460,4 +460,16 @@ void hash__mark_rodata_ro(void)
 
        WARN_ON(!hash__change_memory_range(start, end, PP_RXXX));
 }
+
+void hash__mark_initmem_nx(void)
+{
+       unsigned long start, end, pp;
+
+       start = (unsigned long)__init_begin;
+       end = (unsigned long)__init_end;
+
+       pp = htab_convert_pte_flags(pgprot_val(PAGE_KERNEL));
+
+       WARN_ON(!hash__change_memory_range(start, end, pp));
+}
 #endif
index 336e52ec652cf59129532e801d3696827eee20b3..5cc50d47ce3f99f4bf331a4b6a4c4be18c46379e 100644 (file)
@@ -162,6 +162,14 @@ void radix__mark_rodata_ro(void)
 
        radix__change_memory_range(start, end, _PAGE_WRITE);
 }
+
+void radix__mark_initmem_nx(void)
+{
+       unsigned long start = (unsigned long)__init_begin;
+       unsigned long end = (unsigned long)__init_end;
+
+       radix__change_memory_range(start, end, _PAGE_EXEC);
+}
 #endif /* CONFIG_STRICT_KERNEL_RWX */
 
 static inline void __meminit print_mapping(unsigned long start,
index 5c0b795d656c4298fc36aaac72d15d58359f23e7..0736e94c7615a67b2efd8bd39e237bb757a8e74c 100644 (file)
@@ -505,4 +505,12 @@ void mark_rodata_ro(void)
        else
                hash__mark_rodata_ro();
 }
+
+void mark_initmem_nx(void)
+{
+       if (radix_enabled())
+               radix__mark_initmem_nx();
+       else
+               hash__mark_initmem_nx();
+}
 #endif