summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAdin Scannell <ascannell@google.com>2018-06-11 17:56:18 -0700
committerShentubot <shentubot@google.com>2018-06-11 17:57:19 -0700
commit09b0a9c320bd777bc52384bd0ec91ecfc61e481d (patch)
tree6a8370138e46b1439412a8707d103c40eedab86c
parentea4a468fbaacd55597ce89e3eabd2bb42746427b (diff)
Handle all exception vectors.
PiperOrigin-RevId: 200144655 Change-Id: I5a753c74b75007b7714d6fe34aa0d2e845dc5c41
-rw-r--r--pkg/sentry/platform/kvm/machine_amd64.go48
-rw-r--r--pkg/sentry/platform/ring0/kernel_amd64.go9
2 files changed, 49 insertions, 8 deletions
diff --git a/pkg/sentry/platform/kvm/machine_amd64.go b/pkg/sentry/platform/kvm/machine_amd64.go
index 7ac289756..52896eefe 100644
--- a/pkg/sentry/platform/kvm/machine_amd64.go
+++ b/pkg/sentry/platform/kvm/machine_amd64.go
@@ -137,6 +137,18 @@ func (c *vCPU) initArchState() error {
return c.setSystemTime()
}
+// nonCanonical generates a canonical address return.
+//
+//go:nosplit
+func nonCanonical(addr uint64, signal int32) (*arch.SignalInfo, usermem.AccessType, error) {
+ info := &arch.SignalInfo{
+ Signo: signal,
+ Code: arch.SignalInfoKernel,
+ }
+ info.SetAddr(addr) // Include address.
+ return info, usermem.NoAccess, platform.ErrContextSignal
+}
+
// fault generates an appropriate fault return.
//
//go:nosplit
@@ -169,6 +181,17 @@ func (c *vCPU) fault(signal int32) (*arch.SignalInfo, usermem.AccessType, error)
// SwitchToUser unpacks architectural-details.
func (c *vCPU) SwitchToUser(switchOpts ring0.SwitchOpts) (*arch.SignalInfo, usermem.AccessType, error) {
+ // Check for canonical addresses.
+ if regs := switchOpts.Registers; !ring0.IsCanonical(regs.Rip) {
+ return nonCanonical(regs.Rip, int32(syscall.SIGSEGV))
+ } else if !ring0.IsCanonical(regs.Rsp) {
+ return nonCanonical(regs.Rsp, int32(syscall.SIGBUS))
+ } else if !ring0.IsCanonical(regs.Fs_base) {
+ return nonCanonical(regs.Fs_base, int32(syscall.SIGBUS))
+ } else if !ring0.IsCanonical(regs.Gs_base) {
+ return nonCanonical(regs.Gs_base, int32(syscall.SIGBUS))
+ }
+
// Assign PCIDs.
if c.PCIDs != nil {
var requireFlushPCID bool // Force a flush?
@@ -205,7 +228,11 @@ func (c *vCPU) SwitchToUser(switchOpts ring0.SwitchOpts) (*arch.SignalInfo, user
info.SetAddr(switchOpts.Registers.Rip) // Include address.
return info, usermem.AccessType{}, platform.ErrContextSignal
- case ring0.GeneralProtectionFault:
+ case ring0.GeneralProtectionFault,
+ ring0.SegmentNotPresent,
+ ring0.BoundRangeExceeded,
+ ring0.InvalidTSS,
+ ring0.StackSegmentFault:
info := &arch.SignalInfo{
Signo: int32(syscall.SIGSEGV),
Code: arch.SignalInfoKernel,
@@ -229,7 +256,16 @@ func (c *vCPU) SwitchToUser(switchOpts ring0.SwitchOpts) (*arch.SignalInfo, user
info.SetAddr(switchOpts.Registers.Rip) // Include address.
return info, usermem.AccessType{}, platform.ErrContextSignal
- case ring0.X87FloatingPointException:
+ case ring0.Overflow:
+ info := &arch.SignalInfo{
+ Signo: int32(syscall.SIGFPE),
+ Code: 1, // FPE_INTOVF (integer overflow).
+ }
+ info.SetAddr(switchOpts.Registers.Rip) // Include address.
+ return info, usermem.AccessType{}, platform.ErrContextSignal
+
+ case ring0.X87FloatingPointException,
+ ring0.SIMDFloatingPointException:
info := &arch.SignalInfo{
Signo: int32(syscall.SIGFPE),
Code: 7, // FPE_FLTINV (invalid operation).
@@ -237,7 +273,7 @@ func (c *vCPU) SwitchToUser(switchOpts ring0.SwitchOpts) (*arch.SignalInfo, user
info.SetAddr(switchOpts.Registers.Rip) // Include address.
return info, usermem.AccessType{}, platform.ErrContextSignal
- case ring0.Vector(bounce):
+ case ring0.Vector(bounce): // ring0.VirtualizationException
return nil, usermem.NoAccess, platform.ErrContextInterrupt
case ring0.AlignmentCheck:
@@ -255,6 +291,12 @@ func (c *vCPU) SwitchToUser(switchOpts ring0.SwitchOpts) (*arch.SignalInfo, user
// directly into the instance.
return c.fault(int32(syscall.SIGBUS))
+ case ring0.DeviceNotAvailable,
+ ring0.DoubleFault,
+ ring0.CoprocessorSegmentOverrun,
+ ring0.MachineCheck,
+ ring0.SecurityException:
+ fallthrough
default:
panic(fmt.Sprintf("unexpected vector: 0x%x", vector))
}
diff --git a/pkg/sentry/platform/ring0/kernel_amd64.go b/pkg/sentry/platform/ring0/kernel_amd64.go
index c828af654..117e86104 100644
--- a/pkg/sentry/platform/ring0/kernel_amd64.go
+++ b/pkg/sentry/platform/ring0/kernel_amd64.go
@@ -162,17 +162,16 @@ func IsCanonical(addr uint64) bool {
// code that uses IP-relative addressing inside of absolute addresses. That's
// the case for amd64, but may not be the case for other architectures.
//
+// Precondition: the Rip, Rsp, Fs and Gs registers must be canonical.
+
+//
//go:nosplit
func (c *CPU) SwitchToUser(switchOpts SwitchOpts) (vector Vector) {
- // Check for canonical addresses.
- regs := switchOpts.Registers
- if !IsCanonical(regs.Rip) || !IsCanonical(regs.Rsp) || !IsCanonical(regs.Fs_base) || !IsCanonical(regs.Gs_base) {
- return GeneralProtectionFault
- }
userCR3 := switchOpts.PageTables.CR3(!switchOpts.Flush, switchOpts.UserPCID)
kernelCR3 := c.kernel.PageTables.CR3(true, switchOpts.KernelPCID)
// Sanitize registers.
+ regs := switchOpts.Registers
regs.Eflags &= ^uint64(UserFlagsClear)
regs.Eflags |= UserFlagsSet
regs.Cs = uint64(Ucode64) // Required for iret.