diff options
author | Michael Ellerman <mpe@ellerman.id.au> | 2017-07-14 02:51:23 -0400 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2017-07-18 05:54:24 -0400 |
commit | 029d9252b116fa52a95150819e62af1f6e420fe5 (patch) | |
tree | 6f7832ca67de31a117dbb1b3346bfae3ec1a348e | |
parent | fa7f9189e017213bad63b93a76de5c715cd62a96 (diff) |
powerpc/mm: Mark __init memory no-execute when STRICT_KERNEL_RWX=y
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>
-rw-r--r-- | arch/powerpc/include/asm/book3s/64/hash.h | 1 | ||||
-rw-r--r-- | arch/powerpc/include/asm/book3s/64/pgtable.h | 1 | ||||
-rw-r--r-- | arch/powerpc/include/asm/book3s/64/radix.h | 1 | ||||
-rw-r--r-- | arch/powerpc/include/asm/pgtable.h | 7 | ||||
-rw-r--r-- | arch/powerpc/mm/mem.c | 1 | ||||
-rw-r--r-- | arch/powerpc/mm/pgtable-hash64.c | 12 | ||||
-rw-r--r-- | arch/powerpc/mm/pgtable-radix.c | 8 | ||||
-rw-r--r-- | arch/powerpc/mm/pgtable_64.c | 8 |
8 files changed, 39 insertions, 0 deletions
diff --git a/arch/powerpc/include/asm/book3s/64/hash.h b/arch/powerpc/include/asm/book3s/64/hash.h index 0ce513f2926f..36fc7bfe9e11 100644 --- a/arch/powerpc/include/asm/book3s/64/hash.h +++ b/arch/powerpc/include/asm/book3s/64/hash.h | |||
@@ -91,6 +91,7 @@ static inline int hash__pgd_bad(pgd_t pgd) | |||
91 | } | 91 | } |
92 | #ifdef CONFIG_STRICT_KERNEL_RWX | 92 | #ifdef CONFIG_STRICT_KERNEL_RWX |
93 | extern void hash__mark_rodata_ro(void); | 93 | extern void hash__mark_rodata_ro(void); |
94 | extern void hash__mark_initmem_nx(void); | ||
94 | #endif | 95 | #endif |
95 | 96 | ||
96 | extern void hpte_need_flush(struct mm_struct *mm, unsigned long addr, | 97 | extern void hpte_need_flush(struct mm_struct *mm, unsigned long addr, |
diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h index c0737c86a362..d1da415e283c 100644 --- a/arch/powerpc/include/asm/book3s/64/pgtable.h +++ b/arch/powerpc/include/asm/book3s/64/pgtable.h | |||
@@ -1192,5 +1192,6 @@ static inline const int pud_pfn(pud_t pud) | |||
1192 | BUILD_BUG(); | 1192 | BUILD_BUG(); |
1193 | return 0; | 1193 | return 0; |
1194 | } | 1194 | } |
1195 | |||
1195 | #endif /* __ASSEMBLY__ */ | 1196 | #endif /* __ASSEMBLY__ */ |
1196 | #endif /* _ASM_POWERPC_BOOK3S_64_PGTABLE_H_ */ | 1197 | #endif /* _ASM_POWERPC_BOOK3S_64_PGTABLE_H_ */ |
diff --git a/arch/powerpc/include/asm/book3s/64/radix.h b/arch/powerpc/include/asm/book3s/64/radix.h index 487709ff6875..544440b5aff3 100644 --- a/arch/powerpc/include/asm/book3s/64/radix.h +++ b/arch/powerpc/include/asm/book3s/64/radix.h | |||
@@ -118,6 +118,7 @@ | |||
118 | 118 | ||
119 | #ifdef CONFIG_STRICT_KERNEL_RWX | 119 | #ifdef CONFIG_STRICT_KERNEL_RWX |
120 | extern void radix__mark_rodata_ro(void); | 120 | extern void radix__mark_rodata_ro(void); |
121 | extern void radix__mark_initmem_nx(void); | ||
121 | #endif | 122 | #endif |
122 | 123 | ||
123 | static inline unsigned long __radix_pte_update(pte_t *ptep, unsigned long clr, | 124 | static inline unsigned long __radix_pte_update(pte_t *ptep, unsigned long clr, |
diff --git a/arch/powerpc/include/asm/pgtable.h b/arch/powerpc/include/asm/pgtable.h index dd01212935ac..afae9a336136 100644 --- a/arch/powerpc/include/asm/pgtable.h +++ b/arch/powerpc/include/asm/pgtable.h | |||
@@ -80,6 +80,13 @@ unsigned long vmalloc_to_phys(void *vmalloc_addr); | |||
80 | 80 | ||
81 | void pgtable_cache_add(unsigned shift, void (*ctor)(void *)); | 81 | void pgtable_cache_add(unsigned shift, void (*ctor)(void *)); |
82 | void pgtable_cache_init(void); | 82 | void pgtable_cache_init(void); |
83 | |||
84 | #ifdef CONFIG_STRICT_KERNEL_RWX | ||
85 | void mark_initmem_nx(void); | ||
86 | #else | ||
87 | static inline void mark_initmem_nx(void) { } | ||
88 | #endif | ||
89 | |||
83 | #endif /* __ASSEMBLY__ */ | 90 | #endif /* __ASSEMBLY__ */ |
84 | 91 | ||
85 | #endif /* _ASM_POWERPC_PGTABLE_H */ | 92 | #endif /* _ASM_POWERPC_PGTABLE_H */ |
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 8541f18694a4..46b4e67d2372 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c | |||
@@ -402,6 +402,7 @@ void __init mem_init(void) | |||
402 | void free_initmem(void) | 402 | void free_initmem(void) |
403 | { | 403 | { |
404 | ppc_md.progress = ppc_printk_progress; | 404 | ppc_md.progress = ppc_printk_progress; |
405 | mark_initmem_nx(); | ||
405 | free_initmem_default(POISON_FREE_INITMEM); | 406 | free_initmem_default(POISON_FREE_INITMEM); |
406 | } | 407 | } |
407 | 408 | ||
diff --git a/arch/powerpc/mm/pgtable-hash64.c b/arch/powerpc/mm/pgtable-hash64.c index 73019c52141f..443a2c66a304 100644 --- a/arch/powerpc/mm/pgtable-hash64.c +++ b/arch/powerpc/mm/pgtable-hash64.c | |||
@@ -460,4 +460,16 @@ void hash__mark_rodata_ro(void) | |||
460 | 460 | ||
461 | WARN_ON(!hash__change_memory_range(start, end, PP_RXXX)); | 461 | WARN_ON(!hash__change_memory_range(start, end, PP_RXXX)); |
462 | } | 462 | } |
463 | |||
464 | void hash__mark_initmem_nx(void) | ||
465 | { | ||
466 | unsigned long start, end, pp; | ||
467 | |||
468 | start = (unsigned long)__init_begin; | ||
469 | end = (unsigned long)__init_end; | ||
470 | |||
471 | pp = htab_convert_pte_flags(pgprot_val(PAGE_KERNEL)); | ||
472 | |||
473 | WARN_ON(!hash__change_memory_range(start, end, pp)); | ||
474 | } | ||
463 | #endif | 475 | #endif |
diff --git a/arch/powerpc/mm/pgtable-radix.c b/arch/powerpc/mm/pgtable-radix.c index 336e52ec652c..5cc50d47ce3f 100644 --- a/arch/powerpc/mm/pgtable-radix.c +++ b/arch/powerpc/mm/pgtable-radix.c | |||
@@ -162,6 +162,14 @@ void radix__mark_rodata_ro(void) | |||
162 | 162 | ||
163 | radix__change_memory_range(start, end, _PAGE_WRITE); | 163 | radix__change_memory_range(start, end, _PAGE_WRITE); |
164 | } | 164 | } |
165 | |||
166 | void radix__mark_initmem_nx(void) | ||
167 | { | ||
168 | unsigned long start = (unsigned long)__init_begin; | ||
169 | unsigned long end = (unsigned long)__init_end; | ||
170 | |||
171 | radix__change_memory_range(start, end, _PAGE_EXEC); | ||
172 | } | ||
165 | #endif /* CONFIG_STRICT_KERNEL_RWX */ | 173 | #endif /* CONFIG_STRICT_KERNEL_RWX */ |
166 | 174 | ||
167 | static inline void __meminit print_mapping(unsigned long start, | 175 | static inline void __meminit print_mapping(unsigned long start, |
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c index 5c0b795d656c..0736e94c7615 100644 --- a/arch/powerpc/mm/pgtable_64.c +++ b/arch/powerpc/mm/pgtable_64.c | |||
@@ -505,4 +505,12 @@ void mark_rodata_ro(void) | |||
505 | else | 505 | else |
506 | hash__mark_rodata_ro(); | 506 | hash__mark_rodata_ro(); |
507 | } | 507 | } |
508 | |||
509 | void mark_initmem_nx(void) | ||
510 | { | ||
511 | if (radix_enabled()) | ||
512 | radix__mark_initmem_nx(); | ||
513 | else | ||
514 | hash__mark_initmem_nx(); | ||
515 | } | ||
508 | #endif | 516 | #endif |