Skip to content

Commit 7614ff3

Browse files
bsingharorampe
authored andcommitted
powerpc/mm/radix: Implement STRICT_RWX/mark_rodata_ro() for Radix
The Radix linear mapping code (create_physical_mapping()) tries to use the largest page size it can at each step. Currently the only reason it steps down to a smaller page size is if the start addr is unaligned (never happens in practice), or the end of memory is not aligned to a huge page boundary. To support STRICT_RWX we need to break the mapping at __init_begin, so that the text and rodata prior to that can be marked R_X and the regular pages after can be marked RW. Having done that we can now implement mark_rodata_ro() for Radix, knowing that we won't need to split any mappings. Signed-off-by: Balbir Singh <[email protected]> [mpe: Split down to PAGE_SIZE, not 2MB, rewrite change log] Signed-off-by: Michael Ellerman <[email protected]>
1 parent cd65d69 commit 7614ff3

File tree

2 files changed

+69
-2
lines changed

2 files changed

+69
-2
lines changed

arch/powerpc/mm/pgtable-radix.c

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <linux/sched/mm.h>
1212
#include <linux/memblock.h>
1313
#include <linux/of_fdt.h>
14+
#include <linux/mm.h>
1415

1516
#include <asm/pgtable.h>
1617
#include <asm/pgalloc.h>
@@ -110,6 +111,49 @@ int radix__map_kernel_page(unsigned long ea, unsigned long pa,
110111
return 0;
111112
}
112113

114+
#ifdef CONFIG_STRICT_KERNEL_RWX
115+
void radix__mark_rodata_ro(void)
116+
{
117+
unsigned long start = (unsigned long)_stext;
118+
unsigned long end = (unsigned long)__init_begin;
119+
unsigned long idx;
120+
pgd_t *pgdp;
121+
pud_t *pudp;
122+
pmd_t *pmdp;
123+
pte_t *ptep;
124+
125+
start = ALIGN_DOWN(start, PAGE_SIZE);
126+
end = PAGE_ALIGN(end); // aligns up
127+
128+
pr_devel("marking ro start %lx, end %lx\n", start, end);
129+
130+
for (idx = start; idx < end; idx += PAGE_SIZE) {
131+
pgdp = pgd_offset_k(idx);
132+
pudp = pud_alloc(&init_mm, pgdp, idx);
133+
if (!pudp)
134+
continue;
135+
if (pud_huge(*pudp)) {
136+
ptep = (pte_t *)pudp;
137+
goto update_the_pte;
138+
}
139+
pmdp = pmd_alloc(&init_mm, pudp, idx);
140+
if (!pmdp)
141+
continue;
142+
if (pmd_huge(*pmdp)) {
143+
ptep = pmdp_ptep(pmdp);
144+
goto update_the_pte;
145+
}
146+
ptep = pte_alloc_kernel(pmdp, idx);
147+
if (!ptep)
148+
continue;
149+
update_the_pte:
150+
radix__pte_update(&init_mm, idx, ptep, _PAGE_WRITE, 0, 0);
151+
}
152+
153+
radix__flush_tlb_kernel_range(start, end);
154+
}
155+
#endif /* CONFIG_STRICT_KERNEL_RWX */
156+
113157
static inline void __meminit print_mapping(unsigned long start,
114158
unsigned long end,
115159
unsigned long size)
@@ -125,6 +169,12 @@ static int __meminit create_physical_mapping(unsigned long start,
125169
{
126170
unsigned long vaddr, addr, mapping_size = 0;
127171
pgprot_t prot;
172+
unsigned long max_mapping_size;
173+
#ifdef CONFIG_STRICT_KERNEL_RWX
174+
int split_text_mapping = 1;
175+
#else
176+
int split_text_mapping = 0;
177+
#endif
128178

129179
start = _ALIGN_UP(start, PAGE_SIZE);
130180
for (addr = start; addr < end; addr += mapping_size) {
@@ -133,16 +183,31 @@ static int __meminit create_physical_mapping(unsigned long start,
133183

134184
gap = end - addr;
135185
previous_size = mapping_size;
186+
max_mapping_size = PUD_SIZE;
136187

188+
retry:
137189
if (IS_ALIGNED(addr, PUD_SIZE) && gap >= PUD_SIZE &&
138-
mmu_psize_defs[MMU_PAGE_1G].shift)
190+
mmu_psize_defs[MMU_PAGE_1G].shift &&
191+
PUD_SIZE <= max_mapping_size)
139192
mapping_size = PUD_SIZE;
140193
else if (IS_ALIGNED(addr, PMD_SIZE) && gap >= PMD_SIZE &&
141194
mmu_psize_defs[MMU_PAGE_2M].shift)
142195
mapping_size = PMD_SIZE;
143196
else
144197
mapping_size = PAGE_SIZE;
145198

199+
if (split_text_mapping && (mapping_size == PUD_SIZE) &&
200+
(addr <= __pa_symbol(__init_begin)) &&
201+
(addr + mapping_size) >= __pa_symbol(_stext)) {
202+
max_mapping_size = PMD_SIZE;
203+
goto retry;
204+
}
205+
206+
if (split_text_mapping && (mapping_size == PMD_SIZE) &&
207+
(addr <= __pa_symbol(__init_begin)) &&
208+
(addr + mapping_size) >= __pa_symbol(_stext))
209+
mapping_size = PAGE_SIZE;
210+
146211
if (mapping_size != previous_size) {
147212
print_mapping(start, addr, previous_size);
148213
start = addr;

arch/powerpc/mm/pgtable_64.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,9 @@ void mark_rodata_ro(void)
500500
return;
501501
}
502502

503-
if (!radix_enabled())
503+
if (radix_enabled())
504+
radix__mark_rodata_ro();
505+
else
504506
hash__mark_rodata_ro();
505507
}
506508
#endif

0 commit comments

Comments
 (0)