Commit 31ed2b13 authored by Christophe Leroy's avatar Christophe Leroy Committed by Michael Ellerman
Browse files

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: default avatarChristophe Leroy <christophe.leroy@c-s.fr>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 2679f9bd
Loading
Loading
Loading
Loading
+42 −0
Original line number Diff line number Diff line
/* 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 */
+3 −0
Original line number Diff line number Diff line
@@ -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__

/*
+3 −0
Original line number Diff line number Diff line
@@ -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
+9 −0
Original line number Diff line number Diff line
@@ -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

+14 −1
Original line number Diff line number Diff line
@@ -896,10 +896,20 @@ 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 */
@@ -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

Loading