Commit c239c83e authored by Sven Schnelle's avatar Sven Schnelle Committed by Heiko Carstens
Browse files

s390/entry: add CIF_SIE flag and remove sie64a() address check



When a program check, interrupt or machine check is triggered, the
PSW address is compared to a certain range of the sie64a() function
to figure out whether SIE was interrupted and a cleanup of SIE is
needed.

This doesn't work with kprobes: If kprobes probes an instruction, it
copies the instruction to the kprobes instruction page and overwrites the
original instruction with an undefind instruction (Opcode 00). When this
instruction is hit later, kprobes single-steps the instruction on the
kprobes_instruction page.

However, if this instruction is a relative branch instruction it will now
point to a different location in memory due to being moved to the kprobes
instruction page. If the new branch target points into sie64a() the kernel
assumes it interrupted SIE when processing the breakpoint and will crash
trying to access the SIE control block.

Instead of comparing the address, introduce a new CIF_SIE flag which
indicates whether SIE was interrupted.

Signed-off-by: default avatarSven Schnelle <svens@linux.ibm.com>
Suggested-by: default avatarHeiko Carstens <hca@linux.ibm.com>
Reviewed-by: default avatarHeiko Carstens <hca@linux.ibm.com>
Signed-off-by: default avatarHeiko Carstens <hca@linux.ibm.com>
parent 481ec3b3
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -14,11 +14,13 @@

#include <linux/bits.h>

#define CIF_SIE			0	/* CPU needs SIE exit cleanup */
#define CIF_NOHZ_DELAY		2	/* delay HZ disable for a tick */
#define CIF_ENABLED_WAIT	5	/* in enabled wait state */
#define CIF_MCCK_GUEST		6	/* machine check happening in guest */
#define CIF_DEDICATED_CPU	7	/* this CPU is dedicated */

#define _CIF_SIE		BIT(CIF_SIE)
#define _CIF_NOHZ_DELAY		BIT(CIF_NOHZ_DELAY)
#define _CIF_ENABLED_WAIT	BIT(CIF_ENABLED_WAIT)
#define _CIF_MCCK_GUEST		BIT(CIF_MCCK_GUEST)
+14 −3
Original line number Diff line number Diff line
@@ -146,6 +146,7 @@ _LPP_OFFSET = __LC_LPP
	lg	%r9,__SF_SIE_CONTROL(%r15)	# get control block pointer
	ni	__SIE_PROG0C+3(%r9),0xfe	# no longer in SIE
	lctlg	%c1,%c1,__LC_KERNEL_ASCE	# load primary asce
	ni	__LC_CPU_FLAGS+7,255-_CIF_SIE
	larl	%r9,sie_exit			# skip forward to sie_exit
	.endm
#endif
@@ -214,6 +215,7 @@ SYM_FUNC_START(__sie64a)
	lg	%r14,__LC_GMAP			# get gmap pointer
	ltgr	%r14,%r14
	jz	.Lsie_gmap
	oi	__LC_CPU_FLAGS+7,_CIF_SIE
	lctlg	%c1,%c1,__GMAP_ASCE(%r14)	# load primary asce
.Lsie_gmap:
	lg	%r14,__SF_SIE_CONTROL(%r15)	# get control block pointer
@@ -235,6 +237,7 @@ SYM_FUNC_START(__sie64a)
	ni	__SIE_PROG0C+3(%r14),0xfe	# no longer in SIE
	lctlg	%c1,%c1,__LC_KERNEL_ASCE	# load primary asce
.Lsie_done:
	ni	__LC_CPU_FLAGS+7,255-_CIF_SIE
# some program checks are suppressing. C code (e.g. do_protection_exception)
# will rewind the PSW by the ILC, which is often 4 bytes in case of SIE. There
# are some corner cases (e.g. runtime instrumentation) where ILC is unpredictable.
@@ -346,7 +349,8 @@ SYM_CODE_START(pgm_check_handler)
.Lpgm_skip_asce:
#if IS_ENABLED(CONFIG_KVM)
	# cleanup critical section for program checks in __sie64a
	OUTSIDE	%r9,.Lsie_gmap,.Lsie_done,1f
	TSTMSK	__LC_CPU_FLAGS,_CIF_SIE
	jz	1f
	BPENTER	__SF_SIE_FLAGS(%r15),_TIF_ISOLATE_BP_GUEST
	SIEEXIT
	lghi	%r10,_PIF_GUEST_FAULT
@@ -416,7 +420,8 @@ SYM_CODE_START(\name)
	tmhh	%r8,0x0001			# interrupting from user ?
	jnz	1f
#if IS_ENABLED(CONFIG_KVM)
	OUTSIDE	%r9,.Lsie_gmap,.Lsie_done,0f
	TSTMSK	__LC_CPU_FLAGS,_CIF_SIE
	jz	0f
	BPENTER	__SF_SIE_FLAGS(%r15),_TIF_ISOLATE_BP_GUEST
	SIEEXIT
#endif
@@ -513,7 +518,13 @@ SYM_CODE_START(mcck_int_handler)
	TSTMSK	__LC_MCCK_CODE,MCCK_CODE_PSW_IA_VALID
	jno	.Lmcck_panic
#if IS_ENABLED(CONFIG_KVM)
	OUTSIDE	%r9,.Lsie_gmap,.Lsie_done,.Lmcck_user
	TSTMSK	__LC_CPU_FLAGS,_CIF_SIE
	jz	.Lmcck_user
	# Need to compare the address instead of a CIF_SIE* flag.
	# Otherwise there would be a race between setting the flag
	# and entering SIE (or leaving and clearing the flag). This
	# would cause machine checks targeted at the guest to be
	# handled by the host.
	OUTSIDE	%r9,.Lsie_entry,.Lsie_leave,4f
	oi	__LC_CPU_FLAGS+7, _CIF_MCCK_GUEST
4:	BPENTER	__SF_SIE_FLAGS(%r15),_TIF_ISOLATE_BP_GUEST