mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Merge pull request #7370 from avagin:kvm-sanity
PiperOrigin-RevId: 472577815
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user