gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/sentry/memmap/mapping_set_test.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package memmap
    16  
    17  import (
    18  	"slices"
    19  	"testing"
    20  
    21  	"gvisor.dev/gvisor/pkg/hostarch"
    22  )
    23  
    24  type testMappingSpace struct {
    25  	// Ideally we'd store the full ranges that were invalidated, rather
    26  	// than individual calls to Invalidate, as they are an implementation
    27  	// detail, but this is the simplest way for now.
    28  	inv []hostarch.AddrRange
    29  }
    30  
    31  func (n *testMappingSpace) reset() {
    32  	n.inv = []hostarch.AddrRange{}
    33  }
    34  
    35  func (n *testMappingSpace) Invalidate(ar hostarch.AddrRange, opts InvalidateOpts) {
    36  	n.inv = append(n.inv, ar)
    37  }
    38  
    39  func TestAddRemoveMapping(t *testing.T) {
    40  	set := MappingSet{}
    41  	ms := &testMappingSpace{}
    42  
    43  	mapped := set.AddMapping(ms, hostarch.AddrRange{0x10000, 0x12000}, 0x1000, true)
    44  	if got, want := mapped, []MappableRange{{0x1000, 0x3000}}; !slices.Equal(got, want) {
    45  		t.Errorf("AddMapping: got %+v, wanted %+v", got, want)
    46  	}
    47  
    48  	// Mappings (hostarch.AddrRanges => memmap.MappableRange):
    49  	// [0x10000, 0x12000) => [0x1000, 0x3000)
    50  	t.Log(&set)
    51  
    52  	mapped = set.AddMapping(ms, hostarch.AddrRange{0x20000, 0x21000}, 0x2000, true)
    53  	if len(mapped) != 0 {
    54  		t.Errorf("AddMapping: got %+v, wanted []", mapped)
    55  	}
    56  
    57  	// Mappings:
    58  	// [0x10000, 0x11000) => [0x1000, 0x2000)
    59  	// [0x11000, 0x12000) and [0x20000, 0x21000) => [0x2000, 0x3000)
    60  	t.Log(&set)
    61  
    62  	mapped = set.AddMapping(ms, hostarch.AddrRange{0x30000, 0x31000}, 0x4000, true)
    63  	if got, want := mapped, []MappableRange{{0x4000, 0x5000}}; !slices.Equal(got, want) {
    64  		t.Errorf("AddMapping: got %+v, wanted %+v", got, want)
    65  	}
    66  
    67  	// Mappings:
    68  	// [0x10000, 0x11000) => [0x1000, 0x2000)
    69  	// [0x11000, 0x12000) and [0x20000, 0x21000) => [0x2000, 0x3000)
    70  	// [0x30000, 0x31000) => [0x4000, 0x5000)
    71  	t.Log(&set)
    72  
    73  	mapped = set.AddMapping(ms, hostarch.AddrRange{0x12000, 0x15000}, 0x3000, true)
    74  	if got, want := mapped, []MappableRange{{0x3000, 0x4000}, {0x5000, 0x6000}}; !slices.Equal(got, want) {
    75  		t.Errorf("AddMapping: got %+v, wanted %+v", got, want)
    76  	}
    77  
    78  	// Mappings:
    79  	// [0x10000, 0x11000) => [0x1000, 0x2000)
    80  	// [0x11000, 0x12000) and [0x20000, 0x21000) => [0x2000, 0x3000)
    81  	// [0x12000, 0x13000) => [0x3000, 0x4000)
    82  	// [0x13000, 0x14000) and [0x30000, 0x31000) => [0x4000, 0x5000)
    83  	// [0x14000, 0x15000) => [0x5000, 0x6000)
    84  	t.Log(&set)
    85  
    86  	unmapped := set.RemoveMapping(ms, hostarch.AddrRange{0x10000, 0x11000}, 0x1000, true)
    87  	if got, want := unmapped, []MappableRange{{0x1000, 0x2000}}; !slices.Equal(got, want) {
    88  		t.Errorf("RemoveMapping: got %+v, wanted %+v", got, want)
    89  	}
    90  
    91  	// Mappings:
    92  	// [0x11000, 0x12000) and [0x20000, 0x21000) => [0x2000, 0x3000)
    93  	// [0x12000, 0x13000) => [0x3000, 0x4000)
    94  	// [0x13000, 0x14000) and [0x30000, 0x31000) => [0x4000, 0x5000)
    95  	// [0x14000, 0x15000) => [0x5000, 0x6000)
    96  	t.Log(&set)
    97  
    98  	unmapped = set.RemoveMapping(ms, hostarch.AddrRange{0x20000, 0x21000}, 0x2000, true)
    99  	if len(unmapped) != 0 {
   100  		t.Errorf("RemoveMapping: got %+v, wanted []", unmapped)
   101  	}
   102  
   103  	// Mappings:
   104  	// [0x11000, 0x13000) => [0x2000, 0x4000)
   105  	// [0x13000, 0x14000) and [0x30000, 0x31000) => [0x4000, 0x5000)
   106  	// [0x14000, 0x15000) => [0x5000, 0x6000)
   107  	t.Log(&set)
   108  
   109  	unmapped = set.RemoveMapping(ms, hostarch.AddrRange{0x11000, 0x15000}, 0x2000, true)
   110  	if got, want := unmapped, []MappableRange{{0x2000, 0x4000}, {0x5000, 0x6000}}; !slices.Equal(got, want) {
   111  		t.Errorf("RemoveMapping: got %+v, wanted %+v", got, want)
   112  	}
   113  
   114  	// Mappings:
   115  	// [0x30000, 0x31000) => [0x4000, 0x5000)
   116  	t.Log(&set)
   117  
   118  	unmapped = set.RemoveMapping(ms, hostarch.AddrRange{0x30000, 0x31000}, 0x4000, true)
   119  	if got, want := unmapped, []MappableRange{{0x4000, 0x5000}}; !slices.Equal(got, want) {
   120  		t.Errorf("RemoveMapping: got %+v, wanted %+v", got, want)
   121  	}
   122  }
   123  
   124  func TestInvalidateWholeMapping(t *testing.T) {
   125  	set := MappingSet{}
   126  	ms := &testMappingSpace{}
   127  
   128  	set.AddMapping(ms, hostarch.AddrRange{0x10000, 0x11000}, 0, true)
   129  	// Mappings:
   130  	// [0x10000, 0x11000) => [0, 0x1000)
   131  	t.Log(&set)
   132  	set.Invalidate(MappableRange{0, 0x1000}, InvalidateOpts{})
   133  	if got, want := ms.inv, []hostarch.AddrRange{{Start: 0x10000, End: 0x11000}}; !slices.Equal(got, want) {
   134  		t.Errorf("Invalidate: got %+v, wanted %+v", got, want)
   135  	}
   136  }
   137  
   138  func TestInvalidatePartialMapping(t *testing.T) {
   139  	set := MappingSet{}
   140  	ms := &testMappingSpace{}
   141  
   142  	set.AddMapping(ms, hostarch.AddrRange{0x10000, 0x13000}, 0, true)
   143  	// Mappings:
   144  	// [0x10000, 0x13000) => [0, 0x3000)
   145  	t.Log(&set)
   146  	set.Invalidate(MappableRange{0x1000, 0x2000}, InvalidateOpts{})
   147  	if got, want := ms.inv, []hostarch.AddrRange{{Start: 0x11000, End: 0x12000}}; !slices.Equal(got, want) {
   148  		t.Errorf("Invalidate: got %+v, wanted %+v", got, want)
   149  	}
   150  }
   151  
   152  func TestInvalidateMultipleMappings(t *testing.T) {
   153  	set := MappingSet{}
   154  	ms := &testMappingSpace{}
   155  
   156  	set.AddMapping(ms, hostarch.AddrRange{0x10000, 0x11000}, 0, true)
   157  	set.AddMapping(ms, hostarch.AddrRange{0x20000, 0x21000}, 0x2000, true)
   158  	// Mappings:
   159  	// [0x10000, 0x11000) => [0, 0x1000)
   160  	// [0x12000, 0x13000) => [0x2000, 0x3000)
   161  	t.Log(&set)
   162  	set.Invalidate(MappableRange{0, 0x3000}, InvalidateOpts{})
   163  	if got, want := ms.inv, []hostarch.AddrRange{{Start: 0x10000, End: 0x11000}, {Start: 0x20000, End: 0x21000}}; !slices.Equal(got, want) {
   164  		t.Errorf("Invalidate: got %+v, wanted %+v", got, want)
   165  	}
   166  }
   167  
   168  func TestInvalidateOverlappingMappings(t *testing.T) {
   169  	set := MappingSet{}
   170  	ms1 := &testMappingSpace{}
   171  	ms2 := &testMappingSpace{}
   172  
   173  	set.AddMapping(ms1, hostarch.AddrRange{0x10000, 0x12000}, 0, true)
   174  	set.AddMapping(ms2, hostarch.AddrRange{0x20000, 0x22000}, 0x1000, true)
   175  	// Mappings:
   176  	// ms1:[0x10000, 0x12000) => [0, 0x2000)
   177  	// ms2:[0x11000, 0x13000) => [0x1000, 0x3000)
   178  	t.Log(&set)
   179  	set.Invalidate(MappableRange{0x1000, 0x2000}, InvalidateOpts{})
   180  	if got, want := ms1.inv, []hostarch.AddrRange{{Start: 0x11000, End: 0x12000}}; !slices.Equal(got, want) {
   181  		t.Errorf("Invalidate: ms1: got %+v, wanted %+v", got, want)
   182  	}
   183  	if got, want := ms2.inv, []hostarch.AddrRange{{Start: 0x20000, End: 0x21000}}; !slices.Equal(got, want) {
   184  		t.Errorf("Invalidate: ms1: got %+v, wanted %+v", got, want)
   185  	}
   186  }
   187  
   188  func TestMixedWritableMappings(t *testing.T) {
   189  	set := MappingSet{}
   190  	ms := &testMappingSpace{}
   191  
   192  	mapped := set.AddMapping(ms, hostarch.AddrRange{0x10000, 0x12000}, 0x1000, true)
   193  	if got, want := mapped, []MappableRange{{0x1000, 0x3000}}; !slices.Equal(got, want) {
   194  		t.Errorf("AddMapping: got %+v, wanted %+v", got, want)
   195  	}
   196  
   197  	// Mappings:
   198  	// [0x10000, 0x12000) writable => [0x1000, 0x3000)
   199  	t.Log(&set)
   200  
   201  	mapped = set.AddMapping(ms, hostarch.AddrRange{0x20000, 0x22000}, 0x2000, false)
   202  	if got, want := mapped, []MappableRange{{0x3000, 0x4000}}; !slices.Equal(got, want) {
   203  		t.Errorf("AddMapping: got %+v, wanted %+v", got, want)
   204  	}
   205  
   206  	// Mappings:
   207  	// [0x10000, 0x11000) writable => [0x1000, 0x2000)
   208  	// [0x11000, 0x12000) writable and [0x20000, 0x21000) readonly => [0x2000, 0x3000)
   209  	// [0x21000, 0x22000) readonly => [0x3000, 0x4000)
   210  	t.Log(&set)
   211  
   212  	// Unmap should fail because we specified the readonly map address range, but
   213  	// asked to unmap a writable segment.
   214  	unmapped := set.RemoveMapping(ms, hostarch.AddrRange{0x20000, 0x21000}, 0x2000, true)
   215  	if len(unmapped) != 0 {
   216  		t.Errorf("RemoveMapping: got %+v, wanted []", unmapped)
   217  	}
   218  
   219  	// Readonly mapping removed, but writable mapping still exists in the range,
   220  	// so no mappable range fully unmapped.
   221  	unmapped = set.RemoveMapping(ms, hostarch.AddrRange{0x20000, 0x21000}, 0x2000, false)
   222  	if len(unmapped) != 0 {
   223  		t.Errorf("RemoveMapping: got %+v, wanted []", unmapped)
   224  	}
   225  
   226  	// Mappings:
   227  	// [0x10000, 0x12000) writable => [0x1000, 0x3000)
   228  	// [0x21000, 0x22000) readonly => [0x3000, 0x4000)
   229  	t.Log(&set)
   230  
   231  	unmapped = set.RemoveMapping(ms, hostarch.AddrRange{0x11000, 0x12000}, 0x2000, true)
   232  	if got, want := unmapped, []MappableRange{{0x2000, 0x3000}}; !slices.Equal(got, want) {
   233  		t.Errorf("RemoveMapping: got %+v, wanted %+v", got, want)
   234  	}
   235  
   236  	// Mappings:
   237  	// [0x10000, 0x12000) writable => [0x1000, 0x3000)
   238  	// [0x21000, 0x22000) readonly => [0x3000, 0x4000)
   239  	t.Log(&set)
   240  
   241  	// Unmap should fail since writable bit doesn't match.
   242  	unmapped = set.RemoveMapping(ms, hostarch.AddrRange{0x10000, 0x12000}, 0x1000, false)
   243  	if len(unmapped) != 0 {
   244  		t.Errorf("RemoveMapping: got %+v, wanted []", unmapped)
   245  	}
   246  
   247  	unmapped = set.RemoveMapping(ms, hostarch.AddrRange{0x10000, 0x12000}, 0x1000, true)
   248  	if got, want := unmapped, []MappableRange{{0x1000, 0x2000}}; !slices.Equal(got, want) {
   249  		t.Errorf("RemoveMapping: got %+v, wanted %+v", got, want)
   250  	}
   251  
   252  	// Mappings:
   253  	// [0x21000, 0x22000) readonly => [0x3000, 0x4000)
   254  	t.Log(&set)
   255  
   256  	unmapped = set.RemoveMapping(ms, hostarch.AddrRange{0x21000, 0x22000}, 0x3000, false)
   257  	if got, want := unmapped, []MappableRange{{0x3000, 0x4000}}; !slices.Equal(got, want) {
   258  		t.Errorf("RemoveMapping: got %+v, wanted %+v", got, want)
   259  	}
   260  }