mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 12:42:02 +00:00
powerpc/32s: Implement Kernel Userspace Execution Prevention.
To implement Kernel Userspace Execution Prevention, this patch sets NX bit on all user segments on kernel entry and clears NX bit on all user segments on kernel exit. Note that powerpc 601 doesn't have the NX bit, so KUEP will not work on it. A warning is displayed at startup. Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
This commit is contained in:
parent
2679f9bd0a
commit
31ed2b13c4
42
arch/powerpc/include/asm/book3s/32/kup.h
Normal file
42
arch/powerpc/include/asm/book3s/32/kup.h
Normal file
@ -0,0 +1,42 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_POWERPC_BOOK3S_32_KUP_H
|
||||
#define _ASM_POWERPC_BOOK3S_32_KUP_H
|
||||
|
||||
#include <asm/book3s/32/mmu-hash.h>
|
||||
|
||||
#ifdef __ASSEMBLY__
|
||||
|
||||
.macro kuep_update_sr gpr1, gpr2 /* NEVER use r0 as gpr2 due to addis */
|
||||
101: mtsrin \gpr1, \gpr2
|
||||
addi \gpr1, \gpr1, 0x111 /* next VSID */
|
||||
rlwinm \gpr1, \gpr1, 0, 0xf0ffffff /* clear VSID overflow */
|
||||
addis \gpr2, \gpr2, 0x1000 /* address of next segment */
|
||||
bdnz 101b
|
||||
isync
|
||||
.endm
|
||||
|
||||
.macro kuep_lock gpr1, gpr2
|
||||
#ifdef CONFIG_PPC_KUEP
|
||||
li \gpr1, NUM_USER_SEGMENTS
|
||||
li \gpr2, 0
|
||||
mtctr \gpr1
|
||||
mfsrin \gpr1, \gpr2
|
||||
oris \gpr1, \gpr1, SR_NX@h /* set Nx */
|
||||
kuep_update_sr \gpr1, \gpr2
|
||||
#endif
|
||||
.endm
|
||||
|
||||
.macro kuep_unlock gpr1, gpr2
|
||||
#ifdef CONFIG_PPC_KUEP
|
||||
li \gpr1, NUM_USER_SEGMENTS
|
||||
li \gpr2, 0
|
||||
mtctr \gpr1
|
||||
mfsrin \gpr1, \gpr2
|
||||
rlwinm \gpr1, \gpr1, 0, ~SR_NX /* Clear Nx */
|
||||
kuep_update_sr \gpr1, \gpr2
|
||||
#endif
|
||||
.endm
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif /* _ASM_POWERPC_BOOK3S_32_KUP_H */
|
@ -63,6 +63,9 @@ typedef pte_t *pgtable_t;
|
||||
#define PP_RWRW 2 /* Supervisor read/write, User read/write */
|
||||
#define PP_RXRX 3 /* Supervisor read, User read */
|
||||
|
||||
/* Values for Segment Registers */
|
||||
#define SR_NX 0x10000000 /* No Execute */
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
/*
|
||||
|
@ -8,6 +8,9 @@
|
||||
#ifdef CONFIG_PPC_8xx
|
||||
#include <asm/nohash/32/kup-8xx.h>
|
||||
#endif
|
||||
#ifdef CONFIG_PPC_BOOK3S_32
|
||||
#include <asm/book3s/32/kup.h>
|
||||
#endif
|
||||
|
||||
#ifdef __ASSEMBLY__
|
||||
#ifndef CONFIG_PPC_KUAP
|
||||
|
@ -162,6 +162,9 @@ transfer_to_handler:
|
||||
andis. r12,r12,DBCR0_IDM@h
|
||||
#endif
|
||||
ACCOUNT_CPU_USER_ENTRY(r2, r11, r12)
|
||||
#ifdef CONFIG_PPC_BOOK3S_32
|
||||
kuep_lock r11, r12
|
||||
#endif
|
||||
#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
|
||||
beq+ 3f
|
||||
/* From user and task is ptraced - load up global dbcr0 */
|
||||
@ -427,6 +430,9 @@ BEGIN_FTR_SECTION
|
||||
END_FTR_SECTION_IFSET(CPU_FTR_NEED_PAIRED_STWCX)
|
||||
stwcx. r0,0,r1 /* to clear the reservation */
|
||||
ACCOUNT_CPU_USER_EXIT(r2, r5, r7)
|
||||
#ifdef CONFIG_PPC_BOOK3S_32
|
||||
kuep_unlock r5, r7
|
||||
#endif
|
||||
kuap_check r2, r4
|
||||
lwz r4,_LINK(r1)
|
||||
lwz r5,_CCR(r1)
|
||||
@ -821,6 +827,9 @@ restore_user:
|
||||
bnel- load_dbcr0
|
||||
#endif
|
||||
ACCOUNT_CPU_USER_EXIT(r2, r10, r11)
|
||||
#ifdef CONFIG_PPC_BOOK3S_32
|
||||
kuep_unlock r10, r11
|
||||
#endif
|
||||
|
||||
b restore
|
||||
|
||||
|
@ -896,14 +896,24 @@ load_up_mmu:
|
||||
tophys(r6,r6)
|
||||
lwz r6,_SDR1@l(r6)
|
||||
mtspr SPRN_SDR1,r6
|
||||
li r0,16 /* load up segment register values */
|
||||
li r0, NUM_USER_SEGMENTS /* load up segment register values */
|
||||
mtctr r0 /* for context 0 */
|
||||
lis r3,0x2000 /* Ku = 1, VSID = 0 */
|
||||
#ifdef CONFIG_PPC_KUEP
|
||||
oris r3, r3, SR_NX@h /* Set Nx */
|
||||
#endif
|
||||
li r4,0
|
||||
3: mtsrin r3,r4
|
||||
addi r3,r3,0x111 /* increment VSID */
|
||||
addis r4,r4,0x1000 /* address of next segment */
|
||||
bdnz 3b
|
||||
li r0, 16 - NUM_USER_SEGMENTS /* load up kernel segment registers */
|
||||
mtctr r0 /* for context 0 */
|
||||
rlwinm r3, r3, 0, ~SR_NX /* Nx = 0 */
|
||||
3: mtsrin r3, r4
|
||||
addi r3, r3, 0x111 /* increment VSID */
|
||||
addis r4, r4, 0x1000 /* address of next segment */
|
||||
bdnz 3b
|
||||
|
||||
/* Load the BAT registers with the values set up by MMU_init.
|
||||
MMU_init takes care of whether we're on a 601 or not. */
|
||||
@ -1007,6 +1017,9 @@ _ENTRY(switch_mmu_context)
|
||||
mulli r3,r3,897 /* multiply context by skew factor */
|
||||
rlwinm r3,r3,4,8,27 /* VSID = (context & 0xfffff) << 4 */
|
||||
addis r3,r3,0x6000 /* Set Ks, Ku bits */
|
||||
#ifdef CONFIG_PPC_KUEP
|
||||
oris r3, r3, SR_NX@h /* Set Nx */
|
||||
#endif
|
||||
li r0,NUM_USER_SEGMENTS
|
||||
mtctr r0
|
||||
|
||||
|
@ -394,3 +394,16 @@ void setup_initial_memory_limit(phys_addr_t first_memblock_base,
|
||||
else /* Anything else has 256M mapped */
|
||||
memblock_set_current_limit(min_t(u64, first_memblock_size, 0x10000000));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PPC_KUEP
|
||||
void __init setup_kuep(bool disabled)
|
||||
{
|
||||
pr_info("Activating Kernel Userspace Execution Prevention\n");
|
||||
|
||||
if (cpu_has_feature(CPU_FTR_601))
|
||||
pr_warn("KUEP is not working on powerpc 601 (No NX bit in Seg Regs)\n");
|
||||
|
||||
if (disabled)
|
||||
pr_warn("KUEP cannot be disabled yet on 6xx when compiled in\n");
|
||||
}
|
||||
#endif
|
||||
|
@ -25,6 +25,7 @@ config PPC_BOOK3S_32
|
||||
bool "512x/52xx/6xx/7xx/74xx/82xx/83xx/86xx"
|
||||
select PPC_FPU
|
||||
select PPC_HAVE_PMU_SUPPORT
|
||||
select PPC_HAVE_KUEP
|
||||
|
||||
config PPC_85xx
|
||||
bool "Freescale 85xx"
|
||||
|
Loading…
Reference in New Issue
Block a user