Skip to content

Commit

Permalink
powerpc: Handle error in mark_rodata_ro() and mark_initmem_nx()
Browse files Browse the repository at this point in the history
mark_rodata_ro() and mark_initmem_nx() use functions that can
fail like set_memory_nx() and set_memory_ro(), leading to a not
protected kernel.

In case of failure, panic.

Link: KSPP#7
Signed-off-by: Christophe Leroy <[email protected]>
Signed-off-by: Michael Ellerman <[email protected]>
Link: https://msgid.link/836f75710daef12dfea55f8fb6055d7fdaf716e3.1708078577.git.christophe.leroy@csgroup.eu
  • Loading branch information
chleroy authored and mpe committed Feb 22, 2024
1 parent f7f18e3 commit 8f17bd2
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 32 deletions.
7 changes: 5 additions & 2 deletions arch/powerpc/mm/book3s32/mmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ static bool is_module_segment(unsigned long addr)
return true;
}

void mmu_mark_initmem_nx(void)
int mmu_mark_initmem_nx(void)
{
int nb = mmu_has_feature(MMU_FTR_USE_HIGH_BATS) ? 8 : 4;
int i;
Expand Down Expand Up @@ -230,9 +230,10 @@ void mmu_mark_initmem_nx(void)

mtsr(mfsr(i << 28) | 0x10000000, i << 28);
}
return 0;
}

void mmu_mark_rodata_ro(void)
int mmu_mark_rodata_ro(void)
{
int nb = mmu_has_feature(MMU_FTR_USE_HIGH_BATS) ? 8 : 4;
int i;
Expand All @@ -245,6 +246,8 @@ void mmu_mark_rodata_ro(void)
}

update_bats();

return 0;
}

/*
Expand Down
8 changes: 4 additions & 4 deletions arch/powerpc/mm/mmu_decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,11 +160,11 @@ static inline unsigned long p_block_mapped(phys_addr_t pa) { return 0; }
#endif

#if defined(CONFIG_PPC_BOOK3S_32) || defined(CONFIG_PPC_8xx) || defined(CONFIG_PPC_E500)
void mmu_mark_initmem_nx(void);
void mmu_mark_rodata_ro(void);
int mmu_mark_initmem_nx(void);
int mmu_mark_rodata_ro(void);
#else
static inline void mmu_mark_initmem_nx(void) { }
static inline void mmu_mark_rodata_ro(void) { }
static inline int mmu_mark_initmem_nx(void) { return 0; }
static inline int mmu_mark_rodata_ro(void) { return 0; }
#endif

#ifdef CONFIG_PPC_8xx
Expand Down
33 changes: 21 additions & 12 deletions arch/powerpc/mm/nohash/8xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,23 +119,26 @@ void __init mmu_mapin_immr(void)
PAGE_KERNEL_NCG, MMU_PAGE_512K, true);
}

static void mmu_mapin_ram_chunk(unsigned long offset, unsigned long top,
pgprot_t prot, bool new)
static int mmu_mapin_ram_chunk(unsigned long offset, unsigned long top,
pgprot_t prot, bool new)
{
unsigned long v = PAGE_OFFSET + offset;
unsigned long p = offset;
int err = 0;

WARN_ON(!IS_ALIGNED(offset, SZ_512K) || !IS_ALIGNED(top, SZ_512K));

for (; p < ALIGN(p, SZ_8M) && p < top; p += SZ_512K, v += SZ_512K)
__early_map_kernel_hugepage(v, p, prot, MMU_PAGE_512K, new);
for (; p < ALIGN_DOWN(top, SZ_8M) && p < top; p += SZ_8M, v += SZ_8M)
__early_map_kernel_hugepage(v, p, prot, MMU_PAGE_8M, new);
for (; p < ALIGN_DOWN(top, SZ_512K) && p < top; p += SZ_512K, v += SZ_512K)
__early_map_kernel_hugepage(v, p, prot, MMU_PAGE_512K, new);
for (; p < ALIGN(p, SZ_8M) && p < top && !err; p += SZ_512K, v += SZ_512K)
err = __early_map_kernel_hugepage(v, p, prot, MMU_PAGE_512K, new);
for (; p < ALIGN_DOWN(top, SZ_8M) && p < top && !err; p += SZ_8M, v += SZ_8M)
err = __early_map_kernel_hugepage(v, p, prot, MMU_PAGE_8M, new);
for (; p < ALIGN_DOWN(top, SZ_512K) && p < top && !err; p += SZ_512K, v += SZ_512K)
err = __early_map_kernel_hugepage(v, p, prot, MMU_PAGE_512K, new);

if (!new)
flush_tlb_kernel_range(PAGE_OFFSET + v, PAGE_OFFSET + top);

return err;
}

unsigned long __init mmu_mapin_ram(unsigned long base, unsigned long top)
Expand Down Expand Up @@ -166,27 +169,33 @@ unsigned long __init mmu_mapin_ram(unsigned long base, unsigned long top)
return top;
}

void mmu_mark_initmem_nx(void)
int mmu_mark_initmem_nx(void)
{
unsigned long etext8 = ALIGN(__pa(_etext), SZ_8M);
unsigned long sinittext = __pa(_sinittext);
unsigned long boundary = strict_kernel_rwx_enabled() ? sinittext : etext8;
unsigned long einittext8 = ALIGN(__pa(_einittext), SZ_8M);
int err = 0;

if (!debug_pagealloc_enabled_or_kfence())
mmu_mapin_ram_chunk(boundary, einittext8, PAGE_KERNEL, false);
err = mmu_mapin_ram_chunk(boundary, einittext8, PAGE_KERNEL, false);

mmu_pin_tlb(block_mapped_ram, false);

return err;
}

#ifdef CONFIG_STRICT_KERNEL_RWX
void mmu_mark_rodata_ro(void)
int mmu_mark_rodata_ro(void)
{
unsigned long sinittext = __pa(_sinittext);
int err;

mmu_mapin_ram_chunk(0, sinittext, PAGE_KERNEL_ROX, false);
err = mmu_mapin_ram_chunk(0, sinittext, PAGE_KERNEL_ROX, false);
if (IS_ENABLED(CONFIG_PIN_TLB_DATA))
mmu_pin_tlb(block_mapped_ram, true);

return err;
}
#endif

Expand Down
10 changes: 7 additions & 3 deletions arch/powerpc/mm/nohash/e500.c
Original file line number Diff line number Diff line change
Expand Up @@ -285,19 +285,23 @@ void __init adjust_total_lowmem(void)
}

#ifdef CONFIG_STRICT_KERNEL_RWX
void mmu_mark_rodata_ro(void)
int mmu_mark_rodata_ro(void)
{
unsigned long remapped;

remapped = map_mem_in_cams(__max_low_memory, CONFIG_LOWMEM_CAM_NUM, false, false);

WARN_ON(__max_low_memory != remapped);
if (WARN_ON(__max_low_memory != remapped))
return -EINVAL;

return 0;
}
#endif

void mmu_mark_initmem_nx(void)
int mmu_mark_initmem_nx(void)
{
/* Everything is done in mmu_mark_rodata_ro() */
return 0;
}

void setup_initial_memory_limit(phys_addr_t first_memblock_base,
Expand Down
39 changes: 28 additions & 11 deletions arch/powerpc/mm/pgtable_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,32 +130,41 @@ void __init mapin_ram(void)
}
}

void mark_initmem_nx(void)
static int __mark_initmem_nx(void)
{
unsigned long numpages = PFN_UP((unsigned long)_einittext) -
PFN_DOWN((unsigned long)_sinittext);
int err;

mmu_mark_initmem_nx();
err = mmu_mark_initmem_nx();

if (!v_block_mapped((unsigned long)_sinittext)) {
set_memory_nx((unsigned long)_sinittext, numpages);
set_memory_rw((unsigned long)_sinittext, numpages);
err = set_memory_nx((unsigned long)_sinittext, numpages);
if (err)
return err;
err = set_memory_rw((unsigned long)_sinittext, numpages);
}
return err;
}

void mark_initmem_nx(void)
{
int err = __mark_initmem_nx();

if (err)
panic("%s() failed, err = %d\n", __func__, err);
}

#ifdef CONFIG_STRICT_KERNEL_RWX
void mark_rodata_ro(void)
static int __mark_rodata_ro(void)
{
unsigned long numpages;

if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX) && mmu_has_feature(MMU_FTR_HPTE_TABLE))
pr_warn("This platform has HASH MMU, STRICT_MODULE_RWX won't work\n");

if (v_block_mapped((unsigned long)_stext + 1)) {
mmu_mark_rodata_ro();
ptdump_check_wx();
return;
}
if (v_block_mapped((unsigned long)_stext + 1))
return mmu_mark_rodata_ro();

/*
* mark text and rodata as read only. __end_rodata is set by
Expand All @@ -165,7 +174,15 @@ void mark_rodata_ro(void)
numpages = PFN_UP((unsigned long)__end_rodata) -
PFN_DOWN((unsigned long)_stext);

set_memory_ro((unsigned long)_stext, numpages);
return set_memory_ro((unsigned long)_stext, numpages);
}

void mark_rodata_ro(void)
{
int err = __mark_rodata_ro();

if (err)
panic("%s() failed, err = %d\n", __func__, err);

// mark_initmem_nx() should have already run by now
ptdump_check_wx();
Expand Down

0 comments on commit 8f17bd2

Please sign in to comment.