summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/mm/mm_test.go
diff options
context:
space:
mode:
authorGoogler <noreply@google.com>2018-04-27 10:37:02 -0700
committerAdin Scannell <ascannell@google.com>2018-04-28 01:44:26 -0400
commitd02b74a5dcfed4bfc8f2f8e545bca4d2afabb296 (patch)
tree54f95eef73aee6bacbfc736fffc631be2605ed53 /pkg/sentry/mm/mm_test.go
parentf70210e742919f40aa2f0934a22f1c9ba6dada62 (diff)
Check in gVisor.
PiperOrigin-RevId: 194583126 Change-Id: Ica1d8821a90f74e7e745962d71801c598c652463
Diffstat (limited to 'pkg/sentry/mm/mm_test.go')
-rw-r--r--pkg/sentry/mm/mm_test.go174
1 files changed, 174 insertions, 0 deletions
diff --git a/pkg/sentry/mm/mm_test.go b/pkg/sentry/mm/mm_test.go
new file mode 100644
index 000000000..b47aa7263
--- /dev/null
+++ b/pkg/sentry/mm/mm_test.go
@@ -0,0 +1,174 @@
+// Copyright 2018 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package mm
+
+import (
+ "testing"
+
+ "gvisor.googlesource.com/gvisor/pkg/sentry/arch"
+ "gvisor.googlesource.com/gvisor/pkg/sentry/context"
+ "gvisor.googlesource.com/gvisor/pkg/sentry/context/contexttest"
+ "gvisor.googlesource.com/gvisor/pkg/sentry/limits"
+ "gvisor.googlesource.com/gvisor/pkg/sentry/memmap"
+ "gvisor.googlesource.com/gvisor/pkg/sentry/platform"
+ "gvisor.googlesource.com/gvisor/pkg/sentry/usermem"
+ "gvisor.googlesource.com/gvisor/pkg/syserror"
+)
+
+func testMemoryManager(ctx context.Context) *MemoryManager {
+ p := platform.FromContext(ctx)
+ mm := NewMemoryManager(p)
+ mm.layout = arch.MmapLayout{
+ MinAddr: p.MinUserAddress(),
+ MaxAddr: p.MaxUserAddress(),
+ BottomUpBase: p.MinUserAddress(),
+ TopDownBase: p.MaxUserAddress(),
+ }
+ return mm
+}
+
+func (mm *MemoryManager) realUsageAS() uint64 {
+ return uint64(mm.vmas.Span())
+}
+
+func TestUsageASUpdates(t *testing.T) {
+ ctx := contexttest.Context(t)
+ mm := testMemoryManager(ctx)
+ defer mm.DecUsers(ctx)
+
+ addr, err := mm.MMap(ctx, memmap.MMapOpts{
+ Length: 2 * usermem.PageSize,
+ })
+ if err != nil {
+ t.Fatalf("MMap got err %v want nil", err)
+ }
+ realUsage := mm.realUsageAS()
+ if mm.usageAS != realUsage {
+ t.Fatalf("usageAS believes %v bytes are mapped; %v bytes are actually mapped", mm.usageAS, realUsage)
+ }
+
+ mm.MUnmap(ctx, addr, usermem.PageSize)
+ realUsage = mm.realUsageAS()
+ if mm.usageAS != realUsage {
+ t.Fatalf("usageAS believes %v bytes are mapped; %v bytes are actually mapped", mm.usageAS, realUsage)
+ }
+}
+
+func TestBrkDataLimitUpdates(t *testing.T) {
+ limitSet := limits.NewLimitSet()
+ limitSet.Set(limits.Data, limits.Limit{}) // zero RLIMIT_DATA
+
+ ctx := contexttest.WithLimitSet(contexttest.Context(t), limitSet)
+ mm := testMemoryManager(ctx)
+ defer mm.DecUsers(ctx)
+
+ // Try to extend the brk by one page and expect doing so to fail.
+ oldBrk, _ := mm.Brk(ctx, 0)
+ if newBrk, _ := mm.Brk(ctx, oldBrk+usermem.PageSize); newBrk != oldBrk {
+ t.Errorf("brk() increased data segment above RLIMIT_DATA (old brk = %#x, new brk = %#x", oldBrk, newBrk)
+ }
+}
+
+// TestIOAfterUnmap ensures that IO fails after unmap.
+func TestIOAfterUnmap(t *testing.T) {
+ ctx := contexttest.Context(t)
+ mm := testMemoryManager(ctx)
+ defer mm.DecUsers(ctx)
+
+ addr, err := mm.MMap(ctx, memmap.MMapOpts{
+ Length: usermem.PageSize,
+ Private: true,
+ Perms: usermem.Read,
+ MaxPerms: usermem.AnyAccess,
+ })
+ if err != nil {
+ t.Fatalf("MMap got err %v want nil", err)
+ }
+
+ // IO works before munmap.
+ b := make([]byte, 1)
+ n, err := mm.CopyIn(ctx, addr, b, usermem.IOOpts{})
+ if err != nil {
+ t.Errorf("CopyIn got err %v want nil", err)
+ }
+ if n != 1 {
+ t.Errorf("CopyIn got %d want 1", n)
+ }
+
+ err = mm.MUnmap(ctx, addr, usermem.PageSize)
+ if err != nil {
+ t.Fatalf("MUnmap got err %v want nil", err)
+ }
+
+ n, err = mm.CopyIn(ctx, addr, b, usermem.IOOpts{})
+ if err != syserror.EFAULT {
+ t.Errorf("CopyIn got err %v want EFAULT", err)
+ }
+ if n != 0 {
+ t.Errorf("CopyIn got %d want 0", n)
+ }
+}
+
+// TestIOAfterMProtect tests IO interaction with mprotect permissions.
+func TestIOAfterMProtect(t *testing.T) {
+ ctx := contexttest.Context(t)
+ mm := testMemoryManager(ctx)
+ defer mm.DecUsers(ctx)
+
+ addr, err := mm.MMap(ctx, memmap.MMapOpts{
+ Length: usermem.PageSize,
+ Private: true,
+ Perms: usermem.ReadWrite,
+ MaxPerms: usermem.AnyAccess,
+ })
+ if err != nil {
+ t.Fatalf("MMap got err %v want nil", err)
+ }
+
+ // Writing works before mprotect.
+ b := make([]byte, 1)
+ n, err := mm.CopyOut(ctx, addr, b, usermem.IOOpts{})
+ if err != nil {
+ t.Errorf("CopyOut got err %v want nil", err)
+ }
+ if n != 1 {
+ t.Errorf("CopyOut got %d want 1", n)
+ }
+
+ err = mm.MProtect(addr, usermem.PageSize, usermem.Read, false)
+ if err != nil {
+ t.Errorf("MProtect got err %v want nil", err)
+ }
+
+ // Without IgnorePermissions, CopyOut should no longer succeed.
+ n, err = mm.CopyOut(ctx, addr, b, usermem.IOOpts{})
+ if err != syserror.EFAULT {
+ t.Errorf("CopyOut got err %v want EFAULT", err)
+ }
+ if n != 0 {
+ t.Errorf("CopyOut got %d want 0", n)
+ }
+
+ // With IgnorePermissions, CopyOut should succeed despite mprotect.
+ n, err = mm.CopyOut(ctx, addr, b, usermem.IOOpts{
+ IgnorePermissions: true,
+ })
+ if err != nil {
+ t.Errorf("CopyOut got err %v want nil", err)
+ }
+ if n != 1 {
+ t.Errorf("CopyOut got %d want 1", n)
+ }
+}