diff options
author | Adin Scannell <ascannell@google.com> | 2018-05-30 15:13:36 -0700 |
---|---|---|
committer | Shentubot <shentubot@google.com> | 2018-05-30 15:14:44 -0700 |
commit | c59475599dbcc226e1ef516f40b581d6f2f3be75 (patch) | |
tree | 26eec98c27286aecb2ec91ee1f2c3484677c59d9 /pkg/sentry/platform/kvm | |
parent | 812e83d3bbb99d4fa1ece4712a1ac85e84fe6ec3 (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.go | 5 | ||||
-rw-r--r-- | pkg/sentry/platform/kvm/context.go | 19 | ||||
-rw-r--r-- | pkg/sentry/platform/kvm/kvm.go | 8 | ||||
-rw-r--r-- | pkg/sentry/platform/kvm/kvm_test.go | 108 | ||||
-rw-r--r-- | pkg/sentry/platform/kvm/machine.go | 15 | ||||
-rw-r--r-- | pkg/sentry/platform/kvm/machine_amd64.go | 7 |
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", ®s) } 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", ®s) } @@ -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 |