summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/platform/kvm
diff options
context:
space:
mode:
authorAdin Scannell <ascannell@google.com>2018-05-30 15:13:36 -0700
committerShentubot <shentubot@google.com>2018-05-30 15:14:44 -0700
commitc59475599dbcc226e1ef516f40b581d6f2f3be75 (patch)
tree26eec98c27286aecb2ec91ee1f2c3484677c59d9 /pkg/sentry/platform/kvm
parent812e83d3bbb99d4fa1ece4712a1ac85e84fe6ec3 (diff)
Change ring0 & page tables arguments to structs.
This is a refactor of ring0 and ring0/pagetables that changes from individual arguments to opts structures. This should involve no functional changes, but sets the stage for subsequent changes. PiperOrigin-RevId: 198627556 Change-Id: Id4460340f6a73f0c793cd879324398139cd58ae9
Diffstat (limited to 'pkg/sentry/platform/kvm')
-rw-r--r--pkg/sentry/platform/kvm/address_space.go5
-rw-r--r--pkg/sentry/platform/kvm/context.go19
-rw-r--r--pkg/sentry/platform/kvm/kvm.go8
-rw-r--r--pkg/sentry/platform/kvm/kvm_test.go108
-rw-r--r--pkg/sentry/platform/kvm/machine.go15
-rw-r--r--pkg/sentry/platform/kvm/machine_amd64.go7
6 files changed, 124 insertions, 38 deletions
diff --git a/pkg/sentry/platform/kvm/address_space.go b/pkg/sentry/platform/kvm/address_space.go
index e81cc0caf..a777533c5 100644
--- a/pkg/sentry/platform/kvm/address_space.go
+++ b/pkg/sentry/platform/kvm/address_space.go
@@ -89,7 +89,10 @@ func (as *addressSpace) mapHost(addr usermem.Addr, m hostMapEntry, at usermem.Ac
// important; if the pagetable mappings were installed before
// ensuring the physical pages were available, then some other
// thread could theoretically access them.
- prev := as.pageTables.Map(addr, length, true /* user */, at, physical)
+ prev := as.pageTables.Map(addr, length, pagetables.MapOpts{
+ AccessType: at,
+ User: true,
+ }, physical)
inv = inv || prev
m.addr += length
m.length -= length
diff --git a/pkg/sentry/platform/kvm/context.go b/pkg/sentry/platform/kvm/context.go
index dec26a23a..aac84febf 100644
--- a/pkg/sentry/platform/kvm/context.go
+++ b/pkg/sentry/platform/kvm/context.go
@@ -35,10 +35,7 @@ type context struct {
// Switch runs the provided context in the given address space.
func (c *context) Switch(as platform.AddressSpace, ac arch.Context, _ int32) (*arch.SignalInfo, usermem.AccessType, error) {
- // Extract data.
localAS := as.(*addressSpace)
- regs := &ac.StateData().Regs
- fp := (*byte)(ac.FloatingPointData())
// Grab a vCPU.
cpu := c.machine.Get()
@@ -58,17 +55,17 @@ func (c *context) Switch(as platform.AddressSpace, ac arch.Context, _ int32) (*a
// that the flush can occur naturally on the next user entry.
cpu.active.set(localAS)
- // Mark the address space as dirty.
- flags := ring0.Flags(0)
- if localAS.Touch(cpu) {
- flags |= ring0.FlagFlush
- }
- if ac.FullRestore() {
- flags |= ring0.FlagFull
+ // Prepare switch options.
+ switchOpts := ring0.SwitchOpts{
+ Registers: &ac.StateData().Regs,
+ FloatingPointState: (*byte)(ac.FloatingPointData()),
+ PageTables: localAS.pageTables,
+ Flush: localAS.Touch(cpu),
+ FullRestore: ac.FullRestore(),
}
// Take the blue pill.
- si, at, err := cpu.SwitchToUser(regs, fp, localAS.pageTables, flags)
+ si, at, err := cpu.SwitchToUser(switchOpts)
// Clear the address space.
cpu.active.set(nil)
diff --git a/pkg/sentry/platform/kvm/kvm.go b/pkg/sentry/platform/kvm/kvm.go
index 15a241f01..6defb1c46 100644
--- a/pkg/sentry/platform/kvm/kvm.go
+++ b/pkg/sentry/platform/kvm/kvm.go
@@ -25,6 +25,7 @@ import (
"gvisor.googlesource.com/gvisor/pkg/sentry/platform"
"gvisor.googlesource.com/gvisor/pkg/sentry/platform/filemem"
"gvisor.googlesource.com/gvisor/pkg/sentry/platform/ring0"
+ "gvisor.googlesource.com/gvisor/pkg/sentry/platform/ring0/pagetables"
"gvisor.googlesource.com/gvisor/pkg/sentry/usermem"
)
@@ -123,8 +124,11 @@ func (k *KVM) NewAddressSpace(_ interface{}) (platform.AddressSpace, <-chan stru
pageTables := k.machine.kernel.PageTables.New()
applyPhysicalRegions(func(pr physicalRegion) bool {
// Map the kernel in the upper half.
- kernelVirtual := usermem.Addr(ring0.KernelStartAddress | pr.virtual)
- pageTables.Map(kernelVirtual, pr.length, false /* kernel */, usermem.AnyAccess, pr.physical)
+ pageTables.Map(
+ usermem.Addr(ring0.KernelStartAddress|pr.virtual),
+ pr.length,
+ pagetables.MapOpts{AccessType: usermem.AnyAccess},
+ pr.physical)
return true // Keep iterating.
})
diff --git a/pkg/sentry/platform/kvm/kvm_test.go b/pkg/sentry/platform/kvm/kvm_test.go
index a3466fbed..00919b214 100644
--- a/pkg/sentry/platform/kvm/kvm_test.go
+++ b/pkg/sentry/platform/kvm/kvm_test.go
@@ -142,7 +142,10 @@ func applicationTest(t testHarness, useHostMappings bool, target func(), fn func
// done for regular user code, but is fine for test
// purposes.)
applyPhysicalRegions(func(pr physicalRegion) bool {
- pt.Map(usermem.Addr(pr.virtual), pr.length, true /* user */, usermem.AnyAccess, pr.physical)
+ pt.Map(usermem.Addr(pr.virtual), pr.length, pagetables.MapOpts{
+ AccessType: usermem.AnyAccess,
+ User: true,
+ }, pr.physical)
return true // Keep iterating.
})
}
@@ -154,13 +157,22 @@ func applicationTest(t testHarness, useHostMappings bool, target func(), fn func
func TestApplicationSyscall(t *testing.T) {
applicationTest(t, true, testutil.SyscallLoop, func(c *vCPU, regs *syscall.PtraceRegs, pt *pagetables.PageTables) bool {
- if _, _, err := c.SwitchToUser(regs, dummyFPState, pt, ring0.FlagFull); err != nil {
+ if _, _, err := c.SwitchToUser(ring0.SwitchOpts{
+ Registers: regs,
+ FloatingPointState: dummyFPState,
+ PageTables: pt,
+ FullRestore: true,
+ }); err != nil {
t.Errorf("application syscall with full restore failed: %v", err)
}
return false
})
applicationTest(t, true, testutil.SyscallLoop, func(c *vCPU, regs *syscall.PtraceRegs, pt *pagetables.PageTables) bool {
- if _, _, err := c.SwitchToUser(regs, dummyFPState, pt, 0); err != nil {
+ if _, _, err := c.SwitchToUser(ring0.SwitchOpts{
+ Registers: regs,
+ FloatingPointState: dummyFPState,
+ PageTables: pt,
+ }); err != nil {
t.Errorf("application syscall with partial restore failed: %v", err)
}
return false
@@ -170,14 +182,23 @@ func TestApplicationSyscall(t *testing.T) {
func TestApplicationFault(t *testing.T) {
applicationTest(t, true, testutil.Touch, func(c *vCPU, regs *syscall.PtraceRegs, pt *pagetables.PageTables) bool {
testutil.SetTouchTarget(regs, nil) // Cause fault.
- if si, _, err := c.SwitchToUser(regs, dummyFPState, pt, ring0.FlagFull); err != platform.ErrContextSignal || (si != nil && si.Signo != int32(syscall.SIGSEGV)) {
+ if si, _, err := c.SwitchToUser(ring0.SwitchOpts{
+ Registers: regs,
+ FloatingPointState: dummyFPState,
+ PageTables: pt,
+ FullRestore: true,
+ }); err != platform.ErrContextSignal || (si != nil && si.Signo != int32(syscall.SIGSEGV)) {
t.Errorf("application fault with full restore got (%v, %v), expected (%v, SIGSEGV)", err, si, platform.ErrContextSignal)
}
return false
})
applicationTest(t, true, testutil.Touch, func(c *vCPU, regs *syscall.PtraceRegs, pt *pagetables.PageTables) bool {
testutil.SetTouchTarget(regs, nil) // Cause fault.
- if si, _, err := c.SwitchToUser(regs, dummyFPState, pt, 0); err != platform.ErrContextSignal || (si != nil && si.Signo != int32(syscall.SIGSEGV)) {
+ if si, _, err := c.SwitchToUser(ring0.SwitchOpts{
+ Registers: regs,
+ FloatingPointState: dummyFPState,
+ PageTables: pt,
+ }); err != platform.ErrContextSignal || (si != nil && si.Signo != int32(syscall.SIGSEGV)) {
t.Errorf("application fault with partial restore got (%v, %v), expected (%v, SIGSEGV)", err, si, platform.ErrContextSignal)
}
return false
@@ -187,7 +208,11 @@ func TestApplicationFault(t *testing.T) {
func TestRegistersSyscall(t *testing.T) {
applicationTest(t, true, testutil.TwiddleRegsSyscall, func(c *vCPU, regs *syscall.PtraceRegs, pt *pagetables.PageTables) bool {
testutil.SetTestRegs(regs) // Fill values for all registers.
- if _, _, err := c.SwitchToUser(regs, dummyFPState, pt, 0); err != nil {
+ if _, _, err := c.SwitchToUser(ring0.SwitchOpts{
+ Registers: regs,
+ FloatingPointState: dummyFPState,
+ PageTables: pt,
+ }); err != nil {
t.Errorf("application register check with partial restore got unexpected error: %v", err)
}
if err := testutil.CheckTestRegs(regs, false); err != nil {
@@ -200,7 +225,12 @@ func TestRegistersSyscall(t *testing.T) {
func TestRegistersFault(t *testing.T) {
applicationTest(t, true, testutil.TwiddleRegsFault, func(c *vCPU, regs *syscall.PtraceRegs, pt *pagetables.PageTables) bool {
testutil.SetTestRegs(regs) // Fill values for all registers.
- if si, _, err := c.SwitchToUser(regs, dummyFPState, pt, ring0.FlagFull); err != platform.ErrContextSignal || si.Signo != int32(syscall.SIGSEGV) {
+ if si, _, err := c.SwitchToUser(ring0.SwitchOpts{
+ Registers: regs,
+ FloatingPointState: dummyFPState,
+ PageTables: pt,
+ FullRestore: true,
+ }); err != platform.ErrContextSignal || si.Signo != int32(syscall.SIGSEGV) {
t.Errorf("application register check with full restore got unexpected error: %v", err)
}
if err := testutil.CheckTestRegs(regs, true); err != nil {
@@ -213,7 +243,12 @@ func TestRegistersFault(t *testing.T) {
func TestSegments(t *testing.T) {
applicationTest(t, true, testutil.TwiddleSegments, func(c *vCPU, regs *syscall.PtraceRegs, pt *pagetables.PageTables) bool {
testutil.SetTestSegments(regs)
- if _, _, err := c.SwitchToUser(regs, dummyFPState, pt, ring0.FlagFull); err != nil {
+ if _, _, err := c.SwitchToUser(ring0.SwitchOpts{
+ Registers: regs,
+ FloatingPointState: dummyFPState,
+ PageTables: pt,
+ FullRestore: true,
+ }); err != nil {
t.Errorf("application segment check with full restore got unexpected error: %v", err)
}
if err := testutil.CheckTestSegments(regs); err != nil {
@@ -229,7 +264,11 @@ func TestBounce(t *testing.T) {
time.Sleep(time.Millisecond)
c.BounceToKernel()
}()
- if _, _, err := c.SwitchToUser(regs, dummyFPState, pt, 0); err != platform.ErrContextInterrupt {
+ if _, _, err := c.SwitchToUser(ring0.SwitchOpts{
+ Registers: regs,
+ FloatingPointState: dummyFPState,
+ PageTables: pt,
+ }); err != platform.ErrContextInterrupt {
t.Errorf("application partial restore: got %v, wanted %v", err, platform.ErrContextInterrupt)
}
return false
@@ -239,7 +278,12 @@ func TestBounce(t *testing.T) {
time.Sleep(time.Millisecond)
c.BounceToKernel()
}()
- if _, _, err := c.SwitchToUser(regs, dummyFPState, pt, ring0.FlagFull); err != platform.ErrContextInterrupt {
+ if _, _, err := c.SwitchToUser(ring0.SwitchOpts{
+ Registers: regs,
+ FloatingPointState: dummyFPState,
+ PageTables: pt,
+ FullRestore: true,
+ }); err != platform.ErrContextInterrupt {
t.Errorf("application full restore: got %v, wanted %v", err, platform.ErrContextInterrupt)
}
return false
@@ -265,7 +309,11 @@ func TestBounceStress(t *testing.T) {
c.BounceToKernel()
}()
randomSleep()
- if _, _, err := c.SwitchToUser(regs, dummyFPState, pt, 0); err != platform.ErrContextInterrupt {
+ if _, _, err := c.SwitchToUser(ring0.SwitchOpts{
+ Registers: regs,
+ FloatingPointState: dummyFPState,
+ PageTables: pt,
+ }); err != platform.ErrContextInterrupt {
t.Errorf("application partial restore: got %v, wanted %v", err, platform.ErrContextInterrupt)
}
c.unlock()
@@ -280,12 +328,21 @@ func TestInvalidate(t *testing.T) {
var data uintptr // Used below.
applicationTest(t, true, testutil.Touch, func(c *vCPU, regs *syscall.PtraceRegs, pt *pagetables.PageTables) bool {
testutil.SetTouchTarget(regs, &data) // Read legitimate value.
- if _, _, err := c.SwitchToUser(regs, dummyFPState, pt, 0); err != nil {
+ if _, _, err := c.SwitchToUser(ring0.SwitchOpts{
+ Registers: regs,
+ FloatingPointState: dummyFPState,
+ PageTables: pt,
+ }); err != nil {
t.Errorf("application partial restore: got %v, wanted nil", err)
}
// Unmap the page containing data & invalidate.
pt.Unmap(usermem.Addr(reflect.ValueOf(&data).Pointer() & ^uintptr(usermem.PageSize-1)), usermem.PageSize)
- if _, _, err := c.SwitchToUser(regs, dummyFPState, pt, ring0.FlagFlush); err != platform.ErrContextSignal {
+ if _, _, err := c.SwitchToUser(ring0.SwitchOpts{
+ Registers: regs,
+ FloatingPointState: dummyFPState,
+ PageTables: pt,
+ Flush: true,
+ }); err != platform.ErrContextSignal {
t.Errorf("application partial restore: got %v, wanted %v", err, platform.ErrContextSignal)
}
return false
@@ -299,14 +356,23 @@ func IsFault(err error, si *arch.SignalInfo) bool {
func TestEmptyAddressSpace(t *testing.T) {
applicationTest(t, false, testutil.SyscallLoop, func(c *vCPU, regs *syscall.PtraceRegs, pt *pagetables.PageTables) bool {
- if si, _, err := c.SwitchToUser(regs, dummyFPState, pt, 0); !IsFault(err, si) {
+ if si, _, err := c.SwitchToUser(ring0.SwitchOpts{
+ Registers: regs,
+ FloatingPointState: dummyFPState,
+ PageTables: pt,
+ }); !IsFault(err, si) {
t.Errorf("first fault with partial restore failed got %v", err)
t.Logf("registers: %#v", &regs)
}
return false
})
applicationTest(t, false, testutil.SyscallLoop, func(c *vCPU, regs *syscall.PtraceRegs, pt *pagetables.PageTables) bool {
- if si, _, err := c.SwitchToUser(regs, dummyFPState, pt, ring0.FlagFull); !IsFault(err, si) {
+ if si, _, err := c.SwitchToUser(ring0.SwitchOpts{
+ Registers: regs,
+ FloatingPointState: dummyFPState,
+ PageTables: pt,
+ FullRestore: true,
+ }); !IsFault(err, si) {
t.Errorf("first fault with full restore failed got %v", err)
t.Logf("registers: %#v", &regs)
}
@@ -357,7 +423,11 @@ func BenchmarkApplicationSyscall(b *testing.B) {
a int // Count for ErrContextInterrupt.
)
applicationTest(b, true, testutil.SyscallLoop, func(c *vCPU, regs *syscall.PtraceRegs, pt *pagetables.PageTables) bool {
- if _, _, err := c.SwitchToUser(regs, dummyFPState, pt, 0); err != nil {
+ if _, _, err := c.SwitchToUser(ring0.SwitchOpts{
+ Registers: regs,
+ FloatingPointState: dummyFPState,
+ PageTables: pt,
+ }); err != nil {
if err == platform.ErrContextInterrupt {
a++
return true // Ignore.
@@ -390,7 +460,11 @@ func BenchmarkWorldSwitchToUserRoundtrip(b *testing.B) {
a int
)
applicationTest(b, true, testutil.SyscallLoop, func(c *vCPU, regs *syscall.PtraceRegs, pt *pagetables.PageTables) bool {
- if _, _, err := c.SwitchToUser(regs, dummyFPState, pt, 0); err != nil {
+ if _, _, err := c.SwitchToUser(ring0.SwitchOpts{
+ Registers: regs,
+ FloatingPointState: dummyFPState,
+ PageTables: pt,
+ }); err != nil {
if err == platform.ErrContextInterrupt {
a++
return true // Ignore.
diff --git a/pkg/sentry/platform/kvm/machine.go b/pkg/sentry/platform/kvm/machine.go
index 9b7e5130c..5a6109ced 100644
--- a/pkg/sentry/platform/kvm/machine.go
+++ b/pkg/sentry/platform/kvm/machine.go
@@ -186,10 +186,19 @@ func newMachine(vm int, vCPUs int) (*machine, error) {
// physical pages are mapped on demand, see kernel_unsafe.go.
applyPhysicalRegions(func(pr physicalRegion) bool {
// Map everything in the lower half.
- m.kernel.PageTables.Map(usermem.Addr(pr.virtual), pr.length, false /* kernel */, usermem.AnyAccess, pr.physical)
+ m.kernel.PageTables.Map(
+ usermem.Addr(pr.virtual),
+ pr.length,
+ pagetables.MapOpts{AccessType: usermem.AnyAccess},
+ pr.physical)
+
// And keep everything in the upper half.
- kernelAddr := usermem.Addr(ring0.KernelStartAddress | pr.virtual)
- m.kernel.PageTables.Map(kernelAddr, pr.length, false /* kernel */, usermem.AnyAccess, pr.physical)
+ m.kernel.PageTables.Map(
+ usermem.Addr(ring0.KernelStartAddress|pr.virtual),
+ pr.length,
+ pagetables.MapOpts{AccessType: usermem.AnyAccess},
+ pr.physical)
+
return true // Keep iterating.
})
diff --git a/pkg/sentry/platform/kvm/machine_amd64.go b/pkg/sentry/platform/kvm/machine_amd64.go
index f583f68f7..ba7bbcb91 100644
--- a/pkg/sentry/platform/kvm/machine_amd64.go
+++ b/pkg/sentry/platform/kvm/machine_amd64.go
@@ -24,7 +24,6 @@ import (
"gvisor.googlesource.com/gvisor/pkg/sentry/arch"
"gvisor.googlesource.com/gvisor/pkg/sentry/platform"
"gvisor.googlesource.com/gvisor/pkg/sentry/platform/ring0"
- "gvisor.googlesource.com/gvisor/pkg/sentry/platform/ring0/pagetables"
"gvisor.googlesource.com/gvisor/pkg/sentry/usermem"
)
@@ -121,7 +120,7 @@ func (c *vCPU) fault(signal int32) (*arch.SignalInfo, usermem.AccessType, error)
}
// SwitchToUser unpacks architectural-details.
-func (c *vCPU) SwitchToUser(regs *syscall.PtraceRegs, fpState *byte, pt *pagetables.PageTables, flags ring0.Flags) (*arch.SignalInfo, usermem.AccessType, error) {
+func (c *vCPU) SwitchToUser(switchOpts ring0.SwitchOpts) (*arch.SignalInfo, usermem.AccessType, error) {
// See below.
var vector ring0.Vector
@@ -131,7 +130,7 @@ func (c *vCPU) SwitchToUser(regs *syscall.PtraceRegs, fpState *byte, pt *pagetab
// allocations occur.
entersyscall()
bluepill(c)
- vector = c.CPU.SwitchToUser(regs, fpState, pt, flags)
+ vector = c.CPU.SwitchToUser(switchOpts)
exitsyscall()
switch vector {
@@ -147,7 +146,7 @@ func (c *vCPU) SwitchToUser(regs *syscall.PtraceRegs, fpState *byte, pt *pagetab
return info, usermem.AccessType{}, platform.ErrContextSignal
case ring0.GeneralProtectionFault:
- if !ring0.IsCanonical(regs.Rip) {
+ if !ring0.IsCanonical(switchOpts.Registers.Rip) {
// If the RIP is non-canonical, it's a SEGV.
info := &arch.SignalInfo{Signo: int32(syscall.SIGSEGV)}
return info, usermem.AccessType{}, platform.ErrContextSignal