Merge pull request #7370 from avagin:kvm-sanity

PiperOrigin-RevId: 472577815
This commit is contained in:
gVisor bot
2022-09-06 15:59:34 -07:00
7 changed files with 80 additions and 2 deletions
+20
View File
@@ -129,6 +129,12 @@ type CPUArchState struct {
// exception.
errorType uintptr
// vector is the vector of the last exception.
vector uintptr
// faultAddr is the value of the cr2 register.
faultAddr uintptr
*kernelEntry
// Copies of global variables, stored in CPU so that they can be used by
@@ -157,6 +163,20 @@ func (c *CPU) ClearErrorCode() {
c.errorType = 1 // User mode.
}
// Vector returns the vector of the last exception.
//
//go:nosplit
func (c *CPU) Vector() uintptr {
return c.vector
}
// FaultAddr returns the last fault address.
//
//go:nosplit
func (c *CPU) FaultAddr() uintptr {
return c.faultAddr
}
// SwitchArchOpts are embedded in SwitchOpts.
type SwitchArchOpts struct {
// UserPCID indicates that the application PCID to be used on switch,
+3 -1
View File
@@ -98,8 +98,10 @@ func (c *CPU) ClearErrorCode() {
c.errorType = 1 // User mode.
}
// FaultAddr returns the last fault address.
//
//go:nosplit
func (c *CPU) GetFaultAddr() (value uintptr) {
func (c *CPU) FaultAddr() (value uintptr) {
return c.faultAddr
}
+7
View File
@@ -20,6 +20,8 @@
#define CPU_FPU_STATE {{ .CPU.floatingPointState.Offset }}
#define CPU_ERROR_CODE ({{ .CPU.CPUArchState.Offset }}+{{ .CPUArchState.errorCode.Offset }})
#define CPU_ERROR_TYPE ({{ .CPU.CPUArchState.Offset }}+{{ .CPUArchState.errorType.Offset }})
#define CPU_VECTOR ({{ .CPU.CPUArchState.Offset }}+{{ .CPUArchState.vector.Offset }})
#define CPU_FAULT_ADDR ({{ .CPU.CPUArchState.Offset }}+{{ .CPUArchState.faultAddr.Offset }})
#define CPU_ENTRY ({{ .CPU.CPUArchState.Offset }}+{{ .CPUArchState.kernelEntry.Offset }})
#define CPU_HAS_XSAVE ({{ .CPU.CPUArchState.Offset }}+{{ .CPUArchState.hasXSAVE.Offset }})
#define CPU_HAS_XSAVEOPT ({{ .CPU.CPUArchState.Offset }}+{{ .CPUArchState.hasXSAVEOPT.Offset }})
@@ -488,6 +490,7 @@ kernel:
MOVQ BX, CPU_REGISTERS+PTRACE_RAX(AX)
MOVQ $0, CPU_ERROR_CODE(AX) // Clear error code.
MOVQ $0, CPU_ERROR_TYPE(AX) // Set error type to kernel.
MOVQ $0xffffffffffffffff, CPU_VECTOR(AX) // Set error type to kernel.
// Save floating point state. CPU.floatingPointState is a slice, so the
// first word of CPU.floatingPointState is a pointer to the destination
@@ -608,6 +611,10 @@ kernel:
// Set the error code and adjust the stack.
MOVQ 8(SP), BX // Load the error code.
MOVQ BX, CPU_ERROR_CODE(AX) // Copy out to the CPU.
MOVQ 0(SP), BX // Load the error code.
MOVQ BX, CPU_VECTOR(AX) // Copy out to the CPU.
BYTE $0x0f; BYTE $0x20; BYTE $0xd3; // MOV CR2, RBX
MOVQ BX, CPU_FAULT_ADDR(AX)
MOVQ $0, CPU_ERROR_TYPE(AX) // Set error type to kernel.
// Save floating point state. CPU.floatingPointState is a slice, so the
+26
View File
@@ -61,6 +61,32 @@ func bluepillArchEnter(context *arch.SignalContext64) *vCPU {
return c
}
// hltSanityCheck verifies the current state to detect obvious corruption.
//
//go:nosplit
func (c *vCPU) hltSanityCheck() {
vector := c.CPU.Vector()
switch ring0.Vector(vector) {
case ring0.PageFault:
if c.CPU.FaultAddr() < ring0.KernelStartAddress {
return
}
case ring0.DoubleFault:
case ring0.GeneralProtectionFault:
case ring0.InvalidOpcode:
case ring0.MachineCheck:
case ring0.VirtualizationException:
default:
return
}
printHex([]byte("Vector = "), uint64(c.CPU.Vector()))
printHex([]byte("FaultAddr = "), uint64(c.CPU.FaultAddr()))
printHex([]byte("rip = "), uint64(c.CPU.Registers().Rip))
printHex([]byte("rsp = "), uint64(c.CPU.Registers().Rsp))
throw("fault")
}
// KernelSyscall handles kernel syscalls.
//
// +checkescape:all
@@ -124,3 +124,9 @@ func (c *vCPU) KernelException(vector ring0.Vector) {
ring0.Halt()
}
// hltSanityCheck verifies the current state to detect obvious corruption.
//
//go:nosplit
func (c *vCPU) hltSanityCheck() {
}
@@ -80,6 +80,21 @@ func bluepillGuestExit(c *vCPU, context unsafe.Pointer) {
}
}
var hexSyms = []byte("0123456789abcdef")
//go:nosplit
func printHex(title []byte, val uint64) {
var str [18]byte
for i := 0; i < 16; i++ {
str[16-i] = hexSyms[val&0xf]
val = val >> 4
}
str[0] = ' '
str[17] = '\n'
unix.RawSyscall(unix.SYS_WRITE, uintptr(unix.Stderr), uintptr(unsafe.Pointer(&title[0])), uintptr(len(title)))
unix.RawSyscall(unix.SYS_WRITE, uintptr(unix.Stderr), uintptr(unsafe.Pointer(&str)), 18)
}
// bluepillHandler is called from the signal stub.
//
// The world may be stopped while this is executing, and it executes on the
@@ -185,6 +200,7 @@ func bluepillHandler(context unsafe.Pointer) {
c.die(bluepillArchContext(context), "debug")
return
case _KVM_EXIT_HLT:
c.hltSanityCheck()
bluepillGuestExit(c, context)
return
case _KVM_EXIT_MMIO:
@@ -205,6 +221,7 @@ func bluepillHandler(context unsafe.Pointer) {
c.die(bluepillArchContext(context), "entry failed")
return
default:
printHex([]byte("exitReason="), uint64(c.runData.exitReason))
bluepillArchHandleExit(c, context)
return
}
+1 -1
View File
@@ -168,7 +168,7 @@ func isWriteFault(code uint64) bool {
//go:nosplit
func (c *vCPU) fault(signal int32, info *linux.SignalInfo) (hostarch.AccessType, error) {
bluepill(c) // Probably no-op, but may not be.
faultAddr := c.GetFaultAddr()
faultAddr := c.FaultAddr()
code, user := c.ErrorCode()
if !user {
// The last fault serviced by this CPU was not a user