summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/memmap
diff options
context:
space:
mode:
authorRahat Mahmood <rahat@google.com>2018-12-12 13:09:10 -0800
committerShentubot <shentubot@google.com>2018-12-12 13:09:59 -0800
commit75e39eaa74c65b6f7cfb95addb6ac0cbcc7d951a (patch)
tree1a6b64491851e002727a08546f1168c89b9c32aa /pkg/sentry/memmap
parenta2c868a098fcb51dcdf629045c5f5c0f68c2766f (diff)
Pass information about map writableness to filesystems.
This is necessary to implement file seals for memfds. PiperOrigin-RevId: 225239394 Change-Id: Ib3f1ab31385afc4b24e96cd81a05ef1bebbcbb70
Diffstat (limited to 'pkg/sentry/memmap')
-rw-r--r--pkg/sentry/memmap/mapping_set.go18
-rw-r--r--pkg/sentry/memmap/mapping_set_test.go102
-rw-r--r--pkg/sentry/memmap/memmap.go17
3 files changed, 112 insertions, 25 deletions
diff --git a/pkg/sentry/memmap/mapping_set.go b/pkg/sentry/memmap/mapping_set.go
index 33cf16f91..bd07e9aac 100644
--- a/pkg/sentry/memmap/mapping_set.go
+++ b/pkg/sentry/memmap/mapping_set.go
@@ -40,6 +40,7 @@ type MappingsOfRange map[MappingOfRange]struct{}
type MappingOfRange struct {
MappingSpace MappingSpace
AddrRange usermem.AddrRange
+ Writable bool
}
func (r MappingOfRange) invalidate(opts InvalidateOpts) {
@@ -92,6 +93,7 @@ func (mappingSetFunctions) Merge(r1 MappableRange, val1 MappingsOfRange, r2 Mapp
Start: k1.AddrRange.End,
End: k1.AddrRange.End + usermem.Addr(r2.Length()),
},
+ Writable: k1.Writable,
}
if _, ok := val2[k2]; !ok {
return nil, false
@@ -104,6 +106,7 @@ func (mappingSetFunctions) Merge(r1 MappableRange, val1 MappingsOfRange, r2 Mapp
Start: k1.AddrRange.Start,
End: k2.AddrRange.End,
},
+ Writable: k1.Writable,
}] = struct{}{}
}
@@ -129,6 +132,7 @@ func (mappingSetFunctions) Split(r MappableRange, val MappingsOfRange, split uin
Start: k.AddrRange.Start,
End: k.AddrRange.Start + offset,
},
+ Writable: k.Writable,
}
m1[k1] = struct{}{}
@@ -138,6 +142,7 @@ func (mappingSetFunctions) Split(r MappableRange, val MappingsOfRange, split uin
Start: k.AddrRange.Start + offset,
End: k.AddrRange.End,
},
+ Writable: k.Writable,
}
m2[k2] = struct{}{}
}
@@ -152,7 +157,7 @@ func (mappingSetFunctions) Split(r MappableRange, val MappingsOfRange, split uin
// indicating that ms maps addresses [0x4000, 0x6000) to MappableRange [0x0,
// 0x2000). Then for subsetRange = [0x1000, 0x2000), subsetMapping returns a
// MappingOfRange for which AddrRange = [0x5000, 0x6000).
-func subsetMapping(wholeRange, subsetRange MappableRange, ms MappingSpace, addr usermem.Addr) MappingOfRange {
+func subsetMapping(wholeRange, subsetRange MappableRange, ms MappingSpace, addr usermem.Addr, writable bool) MappingOfRange {
if !wholeRange.IsSupersetOf(subsetRange) {
panic(fmt.Sprintf("%v is not a superset of %v", wholeRange, subsetRange))
}
@@ -165,6 +170,7 @@ func subsetMapping(wholeRange, subsetRange MappableRange, ms MappingSpace, addr
Start: start,
End: start + usermem.Addr(subsetRange.Length()),
},
+ Writable: writable,
}
}
@@ -172,7 +178,7 @@ func subsetMapping(wholeRange, subsetRange MappableRange, ms MappingSpace, addr
// previously had no mappings.
//
// Preconditions: As for Mappable.AddMapping.
-func (s *MappingSet) AddMapping(ms MappingSpace, ar usermem.AddrRange, offset uint64) []MappableRange {
+func (s *MappingSet) AddMapping(ms MappingSpace, ar usermem.AddrRange, offset uint64, writable bool) []MappableRange {
mr := MappableRange{offset, offset + uint64(ar.Length())}
var mapped []MappableRange
seg, gap := s.Find(mr.Start)
@@ -180,7 +186,7 @@ func (s *MappingSet) AddMapping(ms MappingSpace, ar usermem.AddrRange, offset ui
switch {
case seg.Ok() && seg.Start() < mr.End:
seg = s.Isolate(seg, mr)
- seg.Value()[subsetMapping(mr, seg.Range(), ms, ar.Start)] = struct{}{}
+ seg.Value()[subsetMapping(mr, seg.Range(), ms, ar.Start, writable)] = struct{}{}
seg, gap = seg.NextNonEmpty()
case gap.Ok() && gap.Start() < mr.End:
@@ -199,7 +205,7 @@ func (s *MappingSet) AddMapping(ms MappingSpace, ar usermem.AddrRange, offset ui
// MappableRanges that now have no mappings.
//
// Preconditions: As for Mappable.RemoveMapping.
-func (s *MappingSet) RemoveMapping(ms MappingSpace, ar usermem.AddrRange, offset uint64) []MappableRange {
+func (s *MappingSet) RemoveMapping(ms MappingSpace, ar usermem.AddrRange, offset uint64, writable bool) []MappableRange {
mr := MappableRange{offset, offset + uint64(ar.Length())}
var unmapped []MappableRange
@@ -213,7 +219,7 @@ func (s *MappingSet) RemoveMapping(ms MappingSpace, ar usermem.AddrRange, offset
// Remove this part of the mapping.
mappings := seg.Value()
- delete(mappings, subsetMapping(mr, seg.Range(), ms, ar.Start))
+ delete(mappings, subsetMapping(mr, seg.Range(), ms, ar.Start, writable))
if len(mappings) == 0 {
unmapped = append(unmapped, seg.Range())
@@ -231,7 +237,7 @@ func (s *MappingSet) Invalidate(mr MappableRange, opts InvalidateOpts) {
for seg := s.LowerBoundSegment(mr.Start); seg.Ok() && seg.Start() < mr.End; seg = seg.NextSegment() {
segMR := seg.Range()
for m := range seg.Value() {
- region := subsetMapping(segMR, segMR.Intersect(mr), m.MappingSpace, m.AddrRange.Start)
+ region := subsetMapping(segMR, segMR.Intersect(mr), m.MappingSpace, m.AddrRange.Start, m.Writable)
region.invalidate(opts)
}
}
diff --git a/pkg/sentry/memmap/mapping_set_test.go b/pkg/sentry/memmap/mapping_set_test.go
index 49ee34548..45d1d4688 100644
--- a/pkg/sentry/memmap/mapping_set_test.go
+++ b/pkg/sentry/memmap/mapping_set_test.go
@@ -40,7 +40,7 @@ func TestAddRemoveMapping(t *testing.T) {
set := MappingSet{}
ms := &testMappingSpace{}
- mapped := set.AddMapping(ms, usermem.AddrRange{0x10000, 0x12000}, 0x1000)
+ mapped := set.AddMapping(ms, usermem.AddrRange{0x10000, 0x12000}, 0x1000, true)
if got, want := mapped, []MappableRange{{0x1000, 0x3000}}; !reflect.DeepEqual(got, want) {
t.Errorf("AddMapping: got %+v, wanted %+v", got, want)
}
@@ -49,7 +49,7 @@ func TestAddRemoveMapping(t *testing.T) {
// [0x10000, 0x12000) => [0x1000, 0x3000)
t.Log(&set)
- mapped = set.AddMapping(ms, usermem.AddrRange{0x20000, 0x21000}, 0x2000)
+ mapped = set.AddMapping(ms, usermem.AddrRange{0x20000, 0x21000}, 0x2000, true)
if len(mapped) != 0 {
t.Errorf("AddMapping: got %+v, wanted []", mapped)
}
@@ -59,7 +59,7 @@ func TestAddRemoveMapping(t *testing.T) {
// [0x11000, 0x12000) and [0x20000, 0x21000) => [0x2000, 0x3000)
t.Log(&set)
- mapped = set.AddMapping(ms, usermem.AddrRange{0x30000, 0x31000}, 0x4000)
+ mapped = set.AddMapping(ms, usermem.AddrRange{0x30000, 0x31000}, 0x4000, true)
if got, want := mapped, []MappableRange{{0x4000, 0x5000}}; !reflect.DeepEqual(got, want) {
t.Errorf("AddMapping: got %+v, wanted %+v", got, want)
}
@@ -70,7 +70,7 @@ func TestAddRemoveMapping(t *testing.T) {
// [0x30000, 0x31000) => [0x4000, 0x5000)
t.Log(&set)
- mapped = set.AddMapping(ms, usermem.AddrRange{0x12000, 0x15000}, 0x3000)
+ mapped = set.AddMapping(ms, usermem.AddrRange{0x12000, 0x15000}, 0x3000, true)
if got, want := mapped, []MappableRange{{0x3000, 0x4000}, {0x5000, 0x6000}}; !reflect.DeepEqual(got, want) {
t.Errorf("AddMapping: got %+v, wanted %+v", got, want)
}
@@ -83,7 +83,7 @@ func TestAddRemoveMapping(t *testing.T) {
// [0x14000, 0x15000) => [0x5000, 0x6000)
t.Log(&set)
- unmapped := set.RemoveMapping(ms, usermem.AddrRange{0x10000, 0x11000}, 0x1000)
+ unmapped := set.RemoveMapping(ms, usermem.AddrRange{0x10000, 0x11000}, 0x1000, true)
if got, want := unmapped, []MappableRange{{0x1000, 0x2000}}; !reflect.DeepEqual(got, want) {
t.Errorf("RemoveMapping: got %+v, wanted %+v", got, want)
}
@@ -95,7 +95,7 @@ func TestAddRemoveMapping(t *testing.T) {
// [0x14000, 0x15000) => [0x5000, 0x6000)
t.Log(&set)
- unmapped = set.RemoveMapping(ms, usermem.AddrRange{0x20000, 0x21000}, 0x2000)
+ unmapped = set.RemoveMapping(ms, usermem.AddrRange{0x20000, 0x21000}, 0x2000, true)
if len(unmapped) != 0 {
t.Errorf("RemoveMapping: got %+v, wanted []", unmapped)
}
@@ -106,7 +106,7 @@ func TestAddRemoveMapping(t *testing.T) {
// [0x14000, 0x15000) => [0x5000, 0x6000)
t.Log(&set)
- unmapped = set.RemoveMapping(ms, usermem.AddrRange{0x11000, 0x15000}, 0x2000)
+ unmapped = set.RemoveMapping(ms, usermem.AddrRange{0x11000, 0x15000}, 0x2000, true)
if got, want := unmapped, []MappableRange{{0x2000, 0x4000}, {0x5000, 0x6000}}; !reflect.DeepEqual(got, want) {
t.Errorf("RemoveMapping: got %+v, wanted %+v", got, want)
}
@@ -115,7 +115,7 @@ func TestAddRemoveMapping(t *testing.T) {
// [0x30000, 0x31000) => [0x4000, 0x5000)
t.Log(&set)
- unmapped = set.RemoveMapping(ms, usermem.AddrRange{0x30000, 0x31000}, 0x4000)
+ unmapped = set.RemoveMapping(ms, usermem.AddrRange{0x30000, 0x31000}, 0x4000, true)
if got, want := unmapped, []MappableRange{{0x4000, 0x5000}}; !reflect.DeepEqual(got, want) {
t.Errorf("RemoveMapping: got %+v, wanted %+v", got, want)
}
@@ -125,7 +125,7 @@ func TestInvalidateWholeMapping(t *testing.T) {
set := MappingSet{}
ms := &testMappingSpace{}
- set.AddMapping(ms, usermem.AddrRange{0x10000, 0x11000}, 0)
+ set.AddMapping(ms, usermem.AddrRange{0x10000, 0x11000}, 0, true)
// Mappings:
// [0x10000, 0x11000) => [0, 0x1000)
t.Log(&set)
@@ -139,7 +139,7 @@ func TestInvalidatePartialMapping(t *testing.T) {
set := MappingSet{}
ms := &testMappingSpace{}
- set.AddMapping(ms, usermem.AddrRange{0x10000, 0x13000}, 0)
+ set.AddMapping(ms, usermem.AddrRange{0x10000, 0x13000}, 0, true)
// Mappings:
// [0x10000, 0x13000) => [0, 0x3000)
t.Log(&set)
@@ -153,8 +153,8 @@ func TestInvalidateMultipleMappings(t *testing.T) {
set := MappingSet{}
ms := &testMappingSpace{}
- set.AddMapping(ms, usermem.AddrRange{0x10000, 0x11000}, 0)
- set.AddMapping(ms, usermem.AddrRange{0x20000, 0x21000}, 0x2000)
+ set.AddMapping(ms, usermem.AddrRange{0x10000, 0x11000}, 0, true)
+ set.AddMapping(ms, usermem.AddrRange{0x20000, 0x21000}, 0x2000, true)
// Mappings:
// [0x10000, 0x11000) => [0, 0x1000)
// [0x12000, 0x13000) => [0x2000, 0x3000)
@@ -170,8 +170,8 @@ func TestInvalidateOverlappingMappings(t *testing.T) {
ms1 := &testMappingSpace{}
ms2 := &testMappingSpace{}
- set.AddMapping(ms1, usermem.AddrRange{0x10000, 0x12000}, 0)
- set.AddMapping(ms2, usermem.AddrRange{0x20000, 0x22000}, 0x1000)
+ set.AddMapping(ms1, usermem.AddrRange{0x10000, 0x12000}, 0, true)
+ set.AddMapping(ms2, usermem.AddrRange{0x20000, 0x22000}, 0x1000, true)
// Mappings:
// ms1:[0x10000, 0x12000) => [0, 0x2000)
// ms2:[0x11000, 0x13000) => [0x1000, 0x3000)
@@ -184,3 +184,77 @@ func TestInvalidateOverlappingMappings(t *testing.T) {
t.Errorf("Invalidate: ms1: got %+v, wanted %+v", got, want)
}
}
+
+func TestMixedWritableMappings(t *testing.T) {
+ set := MappingSet{}
+ ms := &testMappingSpace{}
+
+ mapped := set.AddMapping(ms, usermem.AddrRange{0x10000, 0x12000}, 0x1000, true)
+ if got, want := mapped, []MappableRange{{0x1000, 0x3000}}; !reflect.DeepEqual(got, want) {
+ t.Errorf("AddMapping: got %+v, wanted %+v", got, want)
+ }
+
+ // Mappings:
+ // [0x10000, 0x12000) writable => [0x1000, 0x3000)
+ t.Log(&set)
+
+ mapped = set.AddMapping(ms, usermem.AddrRange{0x20000, 0x22000}, 0x2000, false)
+ if got, want := mapped, []MappableRange{{0x3000, 0x4000}}; !reflect.DeepEqual(got, want) {
+ t.Errorf("AddMapping: got %+v, wanted %+v", got, want)
+ }
+
+ // Mappings:
+ // [0x10000, 0x11000) writable => [0x1000, 0x2000)
+ // [0x11000, 0x12000) writable and [0x20000, 0x21000) readonly => [0x2000, 0x3000)
+ // [0x21000, 0x22000) readonly => [0x3000, 0x4000)
+ t.Log(&set)
+
+ // Unmap should fail because we specified the readonly map address range, but
+ // asked to unmap a writable segment.
+ unmapped := set.RemoveMapping(ms, usermem.AddrRange{0x20000, 0x21000}, 0x2000, true)
+ if len(unmapped) != 0 {
+ t.Errorf("RemoveMapping: got %+v, wanted []", unmapped)
+ }
+
+ // Readonly mapping removed, but writable mapping still exists in the range,
+ // so no mappable range fully unmapped.
+ unmapped = set.RemoveMapping(ms, usermem.AddrRange{0x20000, 0x21000}, 0x2000, false)
+ if len(unmapped) != 0 {
+ t.Errorf("RemoveMapping: got %+v, wanted []", unmapped)
+ }
+
+ // Mappings:
+ // [0x10000, 0x12000) writable => [0x1000, 0x3000)
+ // [0x21000, 0x22000) readonly => [0x3000, 0x4000)
+ t.Log(&set)
+
+ unmapped = set.RemoveMapping(ms, usermem.AddrRange{0x11000, 0x12000}, 0x2000, true)
+ if got, want := unmapped, []MappableRange{{0x2000, 0x3000}}; !reflect.DeepEqual(got, want) {
+ t.Errorf("RemoveMapping: got %+v, wanted %+v", got, want)
+ }
+
+ // Mappings:
+ // [0x10000, 0x12000) writable => [0x1000, 0x3000)
+ // [0x21000, 0x22000) readonly => [0x3000, 0x4000)
+ t.Log(&set)
+
+ // Unmap should fail since writable bit doesn't match.
+ unmapped = set.RemoveMapping(ms, usermem.AddrRange{0x10000, 0x12000}, 0x1000, false)
+ if len(unmapped) != 0 {
+ t.Errorf("RemoveMapping: got %+v, wanted []", unmapped)
+ }
+
+ unmapped = set.RemoveMapping(ms, usermem.AddrRange{0x10000, 0x12000}, 0x1000, true)
+ if got, want := unmapped, []MappableRange{{0x1000, 0x2000}}; !reflect.DeepEqual(got, want) {
+ t.Errorf("RemoveMapping: got %+v, wanted %+v", got, want)
+ }
+
+ // Mappings:
+ // [0x21000, 0x22000) readonly => [0x3000, 0x4000)
+ t.Log(&set)
+
+ unmapped = set.RemoveMapping(ms, usermem.AddrRange{0x21000, 0x22000}, 0x3000, false)
+ if got, want := unmapped, []MappableRange{{0x3000, 0x4000}}; !reflect.DeepEqual(got, want) {
+ t.Errorf("RemoveMapping: got %+v, wanted %+v", got, want)
+ }
+}
diff --git a/pkg/sentry/memmap/memmap.go b/pkg/sentry/memmap/memmap.go
index 05349a77f..28e2bed9b 100644
--- a/pkg/sentry/memmap/memmap.go
+++ b/pkg/sentry/memmap/memmap.go
@@ -36,16 +36,22 @@ type Mappable interface {
// AddMapping notifies the Mappable of a mapping from addresses ar in ms to
// offsets [offset, offset+ar.Length()) in this Mappable.
//
+ // The writable flag indicates whether the backing data for a Mappable can
+ // be modified through the mapping. Effectively, this means a shared mapping
+ // where Translate may be called with at.Write == true. This is a property
+ // established at mapping creation and must remain constant throughout the
+ // lifetime of the mapping.
+ //
// Preconditions: offset+ar.Length() does not overflow.
- AddMapping(ctx context.Context, ms MappingSpace, ar usermem.AddrRange, offset uint64) error
+ AddMapping(ctx context.Context, ms MappingSpace, ar usermem.AddrRange, offset uint64, writable bool) error
// RemoveMapping notifies the Mappable of the removal of a mapping from
// addresses ar in ms to offsets [offset, offset+ar.Length()) in this
// Mappable.
//
// Preconditions: offset+ar.Length() does not overflow. The removed mapping
- // must exist.
- RemoveMapping(ctx context.Context, ms MappingSpace, ar usermem.AddrRange, offset uint64)
+ // must exist. writable must match the corresponding call to AddMapping.
+ RemoveMapping(ctx context.Context, ms MappingSpace, ar usermem.AddrRange, offset uint64, writable bool)
// CopyMapping notifies the Mappable of an attempt to copy a mapping in ms
// from srcAR to dstAR. For most Mappables, this is equivalent to
@@ -56,8 +62,9 @@ type Mappable interface {
// MappingSpace; it is analogous to Linux's vm_operations_struct::mremap.
//
// Preconditions: offset+srcAR.Length() and offset+dstAR.Length() do not
- // overflow. The mapping at srcAR must exist.
- CopyMapping(ctx context.Context, ms MappingSpace, srcAR, dstAR usermem.AddrRange, offset uint64) error
+ // overflow. The mapping at srcAR must exist. writable must match the
+ // corresponding call to AddMapping.
+ CopyMapping(ctx context.Context, ms MappingSpace, srcAR, dstAR usermem.AddrRange, offset uint64, writable bool) error
// Translate returns the Mappable's current mappings for at least the range
// of offsets specified by required, and at most the range of offsets