arm64 kvm: inject sError to trigger sigbus

Use an sErr injection to trigger sigbus when we receive EFAULT from the
run ioctl.

After applying this patch, mmap_test_runsc_kvm will be passed on
Arm64.

Signed-off-by: Bin Lu <bin.lu@arm.com>
COPYBARA_INTEGRATE_REVIEW=https://github.com/google/gvisor/pull/4542 from lubinszARM:pr_kvm_mmap_1 f81bd42466d1d60a581e5fb34de18b78878c68c1
PiperOrigin-RevId: 340461239
This commit is contained in:
lubinszARM 2020-11-03 09:32:22 -08:00 committed by gVisor bot
parent 1a3f417f4a
commit 0e96f8065e
9 changed files with 132 additions and 73 deletions

View File

@ -79,6 +79,18 @@ func bluepillStopGuest(c *vCPU) {
c.runData.requestInterruptWindow = 0
}
// bluepillSigBus is reponsible for injecting NMI to trigger sigbus.
//
//go:nosplit
func bluepillSigBus(c *vCPU) {
if _, _, errno := syscall.RawSyscall( // escapes: no.
syscall.SYS_IOCTL,
uintptr(c.fd),
_KVM_NMI, 0); errno != 0 {
throw("NMI injection failed")
}
}
// bluepillReadyStopGuest checks whether the current vCPU is ready for interrupt injection.
//
//go:nosplit

View File

@ -27,15 +27,20 @@ var (
// The action for bluepillSignal is changed by sigaction().
bluepillSignal = syscall.SIGILL
// vcpuSErr is the event of system error.
vcpuSErr = kvmVcpuEvents{
// vcpuSErrBounce is the event of system error for bouncing KVM.
vcpuSErrBounce = kvmVcpuEvents{
exception: exception{
sErrPending: 1,
sErrHasEsr: 0,
pad: [6]uint8{0, 0, 0, 0, 0, 0},
sErrEsr: 1,
},
rsvd: [12]uint32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
}
// vcpuSErrNMI is the event of system error to trigger sigbus.
vcpuSErrNMI = kvmVcpuEvents{
exception: exception{
sErrPending: 1,
sErrHasEsr: 1,
sErrEsr: _ESR_ELx_SERR_NMI,
},
}
)

View File

@ -80,11 +80,24 @@ func getHypercallID(addr uintptr) int {
//
//go:nosplit
func bluepillStopGuest(c *vCPU) {
if _, _, errno := syscall.RawSyscall(
if _, _, errno := syscall.RawSyscall( // escapes: no.
syscall.SYS_IOCTL,
uintptr(c.fd),
_KVM_SET_VCPU_EVENTS,
uintptr(unsafe.Pointer(&vcpuSErr))); errno != 0 {
uintptr(unsafe.Pointer(&vcpuSErrBounce))); errno != 0 {
throw("sErr injection failed")
}
}
// bluepillSigBus is reponsible for injecting sError to trigger sigbus.
//
//go:nosplit
func bluepillSigBus(c *vCPU) {
if _, _, errno := syscall.RawSyscall( // escapes: no.
syscall.SYS_IOCTL,
uintptr(c.fd),
_KVM_SET_VCPU_EVENTS,
uintptr(unsafe.Pointer(&vcpuSErrNMI))); errno != 0 {
throw("sErr injection failed")
}
}

View File

@ -146,12 +146,7 @@ func bluepillHandler(context unsafe.Pointer) {
// MMIO exit we receive EFAULT from the run ioctl. We
// always inject an NMI here since we may be in kernel
// mode and have interrupts disabled.
if _, _, errno := syscall.RawSyscall( // escapes: no.
syscall.SYS_IOCTL,
uintptr(c.fd),
_KVM_NMI, 0); errno != 0 {
throw("NMI injection failed")
}
bluepillSigBus(c)
continue // Rerun vCPU.
default:
throw("run failed")

View File

@ -151,6 +151,9 @@ const (
_ESR_SEGV_PEMERR_L1 = 0xd
_ESR_SEGV_PEMERR_L2 = 0xe
_ESR_SEGV_PEMERR_L3 = 0xf
// Custom ISS field definitions for system error.
_ESR_ELx_SERR_NMI = 0x1
)
// Arm64: MMIO base address used to dispatch hypercalls.

View File

@ -257,11 +257,13 @@ func (c *vCPU) SwitchToUser(switchOpts ring0.SwitchOpts, info *arch.SignalInfo)
case ring0.PageFault:
return c.fault(int32(syscall.SIGSEGV), info)
case ring0.El0ErrNMI:
return c.fault(int32(syscall.SIGBUS), info)
case ring0.Vector(bounce): // ring0.VirtualizationException
return usermem.NoAccess, platform.ErrContextInterrupt
case ring0.El0Sync_undef:
case ring0.El0SyncUndef:
return c.fault(int32(syscall.SIGILL), info)
case ring0.El1Sync_undef:
case ring0.El1SyncUndef:
*info = arch.SignalInfo{
Signo: int32(syscall.SIGILL),
Code: 1, // ILL_ILLOPC (illegal opcode).

View File

@ -58,46 +58,55 @@ type Vector uintptr
// Exception vectors.
const (
El1SyncInvalid = iota
El1IrqInvalid
El1FiqInvalid
El1ErrorInvalid
El1InvSync = iota
El1InvIrq
El1InvFiq
El1InvError
El1Sync
El1Irq
El1Fiq
El1Error
El1Err
El0Sync
El0Irq
El0Fiq
El0Error
El0Sync_invalid
El0Irq_invalid
El0Fiq_invalid
El0Error_invalid
El1Sync_da
El1Sync_ia
El1Sync_sp_pc
El1Sync_undef
El1Sync_dbg
El1Sync_inv
El0Sync_svc
El0Sync_da
El0Sync_ia
El0Sync_fpsimd_acc
El0Sync_sve_acc
El0Sync_sys
El0Sync_sp_pc
El0Sync_undef
El0Sync_dbg
El0Sync_inv
El0Err
El0InvSync
El0InvIrq
El0InvFiq
El0InvErr
El1SyncDa
El1SyncIa
El1SyncSpPc
El1SyncUndef
El1SyncDbg
El1SyncInv
El0SyncSVC
El0SyncDa
El0SyncIa
El0SyncFpsimdAcc
El0SyncSveAcc
El0SyncSys
El0SyncSpPc
El0SyncUndef
El0SyncDbg
El0SyncInv
El0ErrNMI
El0ErrBounce
_NR_INTERRUPTS
)
// System call vectors.
const (
Syscall Vector = El0Sync_svc
PageFault Vector = El0Sync_da
VirtualizationException Vector = El0Error
Syscall Vector = El0SyncSVC
PageFault Vector = El0SyncDa
VirtualizationException Vector = El0ErrBounce
)
// VirtualAddressBits returns the number bits available for virtual addresses.

View File

@ -288,6 +288,10 @@
#define ESR_ELx_WFx_ISS_WFE (UL(1) << 0)
#define ESR_ELx_xVC_IMM_MASK ((1UL << 16) - 1)
/* ISS field definitions for system error */
#define ESR_ELx_SERR_MASK (0x1)
#define ESR_ELx_SERR_NMI (0x1)
// LOAD_KERNEL_ADDRESS loads a kernel address.
#define LOAD_KERNEL_ADDRESS(from, to) \
MOVD from, to; \
@ -691,7 +695,7 @@ el0_sp_pc:
B ·Shutdown(SB)
el0_undef:
EXCEPTION_WITH_ERROR(1, El0Sync_undef)
EXCEPTION_WITH_ERROR(1, El0SyncUndef)
el0_dbg:
B ·Shutdown(SB)
@ -707,6 +711,29 @@ TEXT ·El0_fiq(SB),NOSPLIT,$0
TEXT ·El0_error(SB),NOSPLIT,$0
KERNEL_ENTRY_FROM_EL0
WORD $0xd5385219 // MRS ESR_EL1, R25
AND $ESR_ELx_SERR_MASK, R25, R24
CMP $ESR_ELx_SERR_NMI, R24
BEQ el0_nmi
B el0_bounce
el0_nmi:
WORD $0xd538d092 //MRS TPIDR_EL1, R18
WORD $0xd538601a //MRS FAR_EL1, R26
MOVD R26, CPU_FAULT_ADDR(RSV_REG)
MOVD $1, R3
MOVD R3, CPU_ERROR_TYPE(RSV_REG) // Set error type to user.
MOVD $El0ErrNMI, R3
MOVD R3, CPU_VECTOR_CODE(RSV_REG)
MRS ESR_EL1, R3
MOVD R3, CPU_ERROR_CODE(RSV_REG)
B ·kernelExitToEl1(SB)
el0_bounce:
WORD $0xd538d092 //MRS TPIDR_EL1, R18
WORD $0xd538601a //MRS FAR_EL1, R26
@ -718,7 +745,7 @@ TEXT ·El0_error(SB),NOSPLIT,$0
MOVD $VirtualizationException, R3
MOVD R3, CPU_VECTOR_CODE(RSV_REG)
B ·HaltAndResume(SB)
B ·kernelExitToEl1(SB)
TEXT ·El0_sync_invalid(SB),NOSPLIT,$0
B ·Shutdown(SB)

View File

@ -47,43 +47,36 @@ func Emit(w io.Writer) {
fmt.Fprintf(w, "#define _KERNEL_FLAGS 0x%02x\n", KernelFlagsSet)
fmt.Fprintf(w, "\n// Vectors.\n")
fmt.Fprintf(w, "#define El1SyncInvalid 0x%02x\n", El1SyncInvalid)
fmt.Fprintf(w, "#define El1IrqInvalid 0x%02x\n", El1IrqInvalid)
fmt.Fprintf(w, "#define El1FiqInvalid 0x%02x\n", El1FiqInvalid)
fmt.Fprintf(w, "#define El1ErrorInvalid 0x%02x\n", El1ErrorInvalid)
fmt.Fprintf(w, "#define El1Sync 0x%02x\n", El1Sync)
fmt.Fprintf(w, "#define El1Irq 0x%02x\n", El1Irq)
fmt.Fprintf(w, "#define El1Fiq 0x%02x\n", El1Fiq)
fmt.Fprintf(w, "#define El1Error 0x%02x\n", El1Error)
fmt.Fprintf(w, "#define El1Err 0x%02x\n", El1Err)
fmt.Fprintf(w, "#define El0Sync 0x%02x\n", El0Sync)
fmt.Fprintf(w, "#define El0Irq 0x%02x\n", El0Irq)
fmt.Fprintf(w, "#define El0Fiq 0x%02x\n", El0Fiq)
fmt.Fprintf(w, "#define El0Error 0x%02x\n", El0Error)
fmt.Fprintf(w, "#define El0Err 0x%02x\n", El0Err)
fmt.Fprintf(w, "#define El0Sync_invalid 0x%02x\n", El0Sync_invalid)
fmt.Fprintf(w, "#define El0Irq_invalid 0x%02x\n", El0Irq_invalid)
fmt.Fprintf(w, "#define El0Fiq_invalid 0x%02x\n", El0Fiq_invalid)
fmt.Fprintf(w, "#define El0Error_invalid 0x%02x\n", El0Error_invalid)
fmt.Fprintf(w, "#define El1SyncDa 0x%02x\n", El1SyncDa)
fmt.Fprintf(w, "#define El1SyncIa 0x%02x\n", El1SyncIa)
fmt.Fprintf(w, "#define El1SyncSpPc 0x%02x\n", El1SyncSpPc)
fmt.Fprintf(w, "#define El1SyncUndef 0x%02x\n", El1SyncUndef)
fmt.Fprintf(w, "#define El1SyncDbg 0x%02x\n", El1SyncDbg)
fmt.Fprintf(w, "#define El1SyncInv 0x%02x\n", El1SyncInv)
fmt.Fprintf(w, "#define El1Sync_da 0x%02x\n", El1Sync_da)
fmt.Fprintf(w, "#define El1Sync_ia 0x%02x\n", El1Sync_ia)
fmt.Fprintf(w, "#define El1Sync_sp_pc 0x%02x\n", El1Sync_sp_pc)
fmt.Fprintf(w, "#define El1Sync_undef 0x%02x\n", El1Sync_undef)
fmt.Fprintf(w, "#define El1Sync_dbg 0x%02x\n", El1Sync_dbg)
fmt.Fprintf(w, "#define El1Sync_inv 0x%02x\n", El1Sync_inv)
fmt.Fprintf(w, "#define El0SyncSVC 0x%02x\n", El0SyncSVC)
fmt.Fprintf(w, "#define El0SyncDa 0x%02x\n", El0SyncDa)
fmt.Fprintf(w, "#define El0SyncIa 0x%02x\n", El0SyncIa)
fmt.Fprintf(w, "#define El0SyncFpsimdAcc 0x%02x\n", El0SyncFpsimdAcc)
fmt.Fprintf(w, "#define El0SyncSveAcc 0x%02x\n", El0SyncSveAcc)
fmt.Fprintf(w, "#define El0SyncSys 0x%02x\n", El0SyncSys)
fmt.Fprintf(w, "#define El0SyncSpPc 0x%02x\n", El0SyncSpPc)
fmt.Fprintf(w, "#define El0SyncUndef 0x%02x\n", El0SyncUndef)
fmt.Fprintf(w, "#define El0SyncDbg 0x%02x\n", El0SyncDbg)
fmt.Fprintf(w, "#define El0SyncInv 0x%02x\n", El0SyncInv)
fmt.Fprintf(w, "#define El0Sync_svc 0x%02x\n", El0Sync_svc)
fmt.Fprintf(w, "#define El0Sync_da 0x%02x\n", El0Sync_da)
fmt.Fprintf(w, "#define El0Sync_ia 0x%02x\n", El0Sync_ia)
fmt.Fprintf(w, "#define El0Sync_fpsimd_acc 0x%02x\n", El0Sync_fpsimd_acc)
fmt.Fprintf(w, "#define El0Sync_sve_acc 0x%02x\n", El0Sync_sve_acc)
fmt.Fprintf(w, "#define El0Sync_sys 0x%02x\n", El0Sync_sys)
fmt.Fprintf(w, "#define El0Sync_sp_pc 0x%02x\n", El0Sync_sp_pc)
fmt.Fprintf(w, "#define El0Sync_undef 0x%02x\n", El0Sync_undef)
fmt.Fprintf(w, "#define El0Sync_dbg 0x%02x\n", El0Sync_dbg)
fmt.Fprintf(w, "#define El0Sync_inv 0x%02x\n", El0Sync_inv)
fmt.Fprintf(w, "#define El0ErrNMI 0x%02x\n", El0ErrNMI)
fmt.Fprintf(w, "#define PageFault 0x%02x\n", PageFault)
fmt.Fprintf(w, "#define Syscall 0x%02x\n", Syscall)