s390/entry: compare gmap asce to determine guest/host fault
With the current implementation, there are some cornercases where a host fault would be treated as a guest fault, for example when the sie instruction causes a program check. Therefore store the gmap asce in ptregs, and use that to compare the primary asce from the fault instead of matching instruction addresses. Suggested-by: Heiko Carstens <hca@linux.ibm.com> Signed-off-by: Sven Schnelle <svens@linux.ibm.com> Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
This commit is contained in:
parent
29e5bc0f02
commit
64c3431808
3 changed files with 18 additions and 19 deletions
|
@ -14,13 +14,11 @@
|
||||||
#define PIF_SYSCALL 0 /* inside a system call */
|
#define PIF_SYSCALL 0 /* inside a system call */
|
||||||
#define PIF_EXECVE_PGSTE_RESTART 1 /* restart execve for PGSTE binaries */
|
#define PIF_EXECVE_PGSTE_RESTART 1 /* restart execve for PGSTE binaries */
|
||||||
#define PIF_SYSCALL_RET_SET 2 /* return value was set via ptrace */
|
#define PIF_SYSCALL_RET_SET 2 /* return value was set via ptrace */
|
||||||
#define PIF_GUEST_FAULT 3 /* indicates program check in sie64a */
|
|
||||||
#define PIF_FTRACE_FULL_REGS 4 /* all register contents valid (ftrace) */
|
#define PIF_FTRACE_FULL_REGS 4 /* all register contents valid (ftrace) */
|
||||||
|
|
||||||
#define _PIF_SYSCALL BIT(PIF_SYSCALL)
|
#define _PIF_SYSCALL BIT(PIF_SYSCALL)
|
||||||
#define _PIF_EXECVE_PGSTE_RESTART BIT(PIF_EXECVE_PGSTE_RESTART)
|
#define _PIF_EXECVE_PGSTE_RESTART BIT(PIF_EXECVE_PGSTE_RESTART)
|
||||||
#define _PIF_SYSCALL_RET_SET BIT(PIF_SYSCALL_RET_SET)
|
#define _PIF_SYSCALL_RET_SET BIT(PIF_SYSCALL_RET_SET)
|
||||||
#define _PIF_GUEST_FAULT BIT(PIF_GUEST_FAULT)
|
|
||||||
#define _PIF_FTRACE_FULL_REGS BIT(PIF_FTRACE_FULL_REGS)
|
#define _PIF_FTRACE_FULL_REGS BIT(PIF_FTRACE_FULL_REGS)
|
||||||
|
|
||||||
#define PSW32_MASK_PER _AC(0x40000000, UL)
|
#define PSW32_MASK_PER _AC(0x40000000, UL)
|
||||||
|
|
|
@ -119,8 +119,8 @@ _LPP_OFFSET = __LC_LPP
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_KVM)
|
#if IS_ENABLED(CONFIG_KVM)
|
||||||
.macro SIEEXIT
|
.macro SIEEXIT sie_control
|
||||||
lg %r9,__SF_SIE_CONTROL(%r15) # get control block pointer
|
lg %r9,\sie_control # get control block pointer
|
||||||
ni __SIE_PROG0C+3(%r9),0xfe # no longer in SIE
|
ni __SIE_PROG0C+3(%r9),0xfe # no longer in SIE
|
||||||
lctlg %c1,%c1,__LC_KERNEL_ASCE # load primary asce
|
lctlg %c1,%c1,__LC_KERNEL_ASCE # load primary asce
|
||||||
ni __LC_CPU_FLAGS+7,255-_CIF_SIE
|
ni __LC_CPU_FLAGS+7,255-_CIF_SIE
|
||||||
|
@ -316,21 +316,13 @@ SYM_CODE_START(pgm_check_handler)
|
||||||
stpt __LC_SYS_ENTER_TIMER
|
stpt __LC_SYS_ENTER_TIMER
|
||||||
BPOFF
|
BPOFF
|
||||||
stmg %r8,%r15,__LC_SAVE_AREA_SYNC
|
stmg %r8,%r15,__LC_SAVE_AREA_SYNC
|
||||||
lghi %r10,0
|
lgr %r10,%r15
|
||||||
lmg %r8,%r9,__LC_PGM_OLD_PSW
|
lmg %r8,%r9,__LC_PGM_OLD_PSW
|
||||||
tmhh %r8,0x0001 # coming from user space?
|
tmhh %r8,0x0001 # coming from user space?
|
||||||
jno .Lpgm_skip_asce
|
jno .Lpgm_skip_asce
|
||||||
lctlg %c1,%c1,__LC_KERNEL_ASCE
|
lctlg %c1,%c1,__LC_KERNEL_ASCE
|
||||||
j 3f # -> fault in user space
|
j 3f # -> fault in user space
|
||||||
.Lpgm_skip_asce:
|
.Lpgm_skip_asce:
|
||||||
#if IS_ENABLED(CONFIG_KVM)
|
|
||||||
# cleanup critical section for program checks in __sie64a
|
|
||||||
TSTMSK __LC_CPU_FLAGS,_CIF_SIE
|
|
||||||
jz 1f
|
|
||||||
BPENTER __SF_SIE_FLAGS(%r15),_TIF_ISOLATE_BP_GUEST
|
|
||||||
SIEEXIT
|
|
||||||
lghi %r10,_PIF_GUEST_FAULT
|
|
||||||
#endif
|
|
||||||
1: tmhh %r8,0x4000 # PER bit set in old PSW ?
|
1: tmhh %r8,0x4000 # PER bit set in old PSW ?
|
||||||
jnz 2f # -> enabled, can't be a double fault
|
jnz 2f # -> enabled, can't be a double fault
|
||||||
tm __LC_PGM_ILC+3,0x80 # check for per exception
|
tm __LC_PGM_ILC+3,0x80 # check for per exception
|
||||||
|
@ -341,13 +333,20 @@ SYM_CODE_START(pgm_check_handler)
|
||||||
CHECK_VMAP_STACK __LC_SAVE_AREA_SYNC,4f
|
CHECK_VMAP_STACK __LC_SAVE_AREA_SYNC,4f
|
||||||
3: lg %r15,__LC_KERNEL_STACK
|
3: lg %r15,__LC_KERNEL_STACK
|
||||||
4: la %r11,STACK_FRAME_OVERHEAD(%r15)
|
4: la %r11,STACK_FRAME_OVERHEAD(%r15)
|
||||||
stg %r10,__PT_FLAGS(%r11)
|
xc __PT_FLAGS(8,%r11),__PT_FLAGS(%r11)
|
||||||
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
|
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
|
||||||
stmg %r0,%r7,__PT_R0(%r11)
|
stmg %r0,%r7,__PT_R0(%r11)
|
||||||
mvc __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC
|
mvc __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC
|
||||||
mvc __PT_LAST_BREAK(8,%r11),__LC_PGM_LAST_BREAK
|
mvc __PT_LAST_BREAK(8,%r11),__LC_PGM_LAST_BREAK
|
||||||
stmg %r8,%r9,__PT_PSW(%r11)
|
stctg %c1,%c1,__PT_CR1(%r11)
|
||||||
|
#if IS_ENABLED(CONFIG_KVM)
|
||||||
|
lg %r12,__LC_GMAP
|
||||||
|
clc __GMAP_ASCE(8,%r12), __PT_CR1(%r11)
|
||||||
|
jne 5f
|
||||||
|
BPENTER __SF_SIE_FLAGS(%r10),_TIF_ISOLATE_BP_GUEST
|
||||||
|
SIEEXIT __SF_SIE_CONTROL(%r10)
|
||||||
|
#endif
|
||||||
|
5: stmg %r8,%r9,__PT_PSW(%r11)
|
||||||
# clear user controlled registers to prevent speculative use
|
# clear user controlled registers to prevent speculative use
|
||||||
xgr %r0,%r0
|
xgr %r0,%r0
|
||||||
xgr %r1,%r1
|
xgr %r1,%r1
|
||||||
|
@ -399,7 +398,7 @@ SYM_CODE_START(\name)
|
||||||
TSTMSK __LC_CPU_FLAGS,_CIF_SIE
|
TSTMSK __LC_CPU_FLAGS,_CIF_SIE
|
||||||
jz 0f
|
jz 0f
|
||||||
BPENTER __SF_SIE_FLAGS(%r15),_TIF_ISOLATE_BP_GUEST
|
BPENTER __SF_SIE_FLAGS(%r15),_TIF_ISOLATE_BP_GUEST
|
||||||
SIEEXIT
|
SIEEXIT __SF_SIE_CONTROL(%r15)
|
||||||
#endif
|
#endif
|
||||||
0: CHECK_STACK __LC_SAVE_AREA_ASYNC
|
0: CHECK_STACK __LC_SAVE_AREA_ASYNC
|
||||||
aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
|
aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
|
||||||
|
@ -507,7 +506,7 @@ SYM_CODE_START(mcck_int_handler)
|
||||||
clgrjhe %r9,%r14, 4f
|
clgrjhe %r9,%r14, 4f
|
||||||
oi __LC_CPU_FLAGS+7, _CIF_MCCK_GUEST
|
oi __LC_CPU_FLAGS+7, _CIF_MCCK_GUEST
|
||||||
4: BPENTER __SF_SIE_FLAGS(%r15),_TIF_ISOLATE_BP_GUEST
|
4: BPENTER __SF_SIE_FLAGS(%r15),_TIF_ISOLATE_BP_GUEST
|
||||||
SIEEXIT
|
SIEEXIT __SF_SIE_CONTROL(%r15)
|
||||||
#endif
|
#endif
|
||||||
.Lmcck_user:
|
.Lmcck_user:
|
||||||
lg %r15,__LC_MCCK_STACK
|
lg %r15,__LC_MCCK_STACK
|
||||||
|
|
|
@ -67,13 +67,15 @@ early_initcall(fault_init);
|
||||||
static enum fault_type get_fault_type(struct pt_regs *regs)
|
static enum fault_type get_fault_type(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
union teid teid = { .val = regs->int_parm_long };
|
union teid teid = { .val = regs->int_parm_long };
|
||||||
|
struct gmap *gmap;
|
||||||
|
|
||||||
if (likely(teid.as == PSW_BITS_AS_PRIMARY)) {
|
if (likely(teid.as == PSW_BITS_AS_PRIMARY)) {
|
||||||
if (user_mode(regs))
|
if (user_mode(regs))
|
||||||
return USER_FAULT;
|
return USER_FAULT;
|
||||||
if (!IS_ENABLED(CONFIG_PGSTE))
|
if (!IS_ENABLED(CONFIG_PGSTE))
|
||||||
return KERNEL_FAULT;
|
return KERNEL_FAULT;
|
||||||
if (test_pt_regs_flag(regs, PIF_GUEST_FAULT))
|
gmap = (struct gmap *)S390_lowcore.gmap;
|
||||||
|
if (regs->cr1 == gmap->asce)
|
||||||
return GMAP_FAULT;
|
return GMAP_FAULT;
|
||||||
return KERNEL_FAULT;
|
return KERNEL_FAULT;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue