summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--pkg/sentry/platform/kvm/address_space.go8
-rw-r--r--pkg/sentry/platform/kvm/host_map.go108
2 files changed, 68 insertions, 48 deletions
diff --git a/pkg/sentry/platform/kvm/address_space.go b/pkg/sentry/platform/kvm/address_space.go
index 173885867..2302f78e1 100644
--- a/pkg/sentry/platform/kvm/address_space.go
+++ b/pkg/sentry/platform/kvm/address_space.go
@@ -46,6 +46,8 @@ type addressSpace struct {
dirtySet sync.Map
// files contains files mapped in the host address space.
+ //
+ // See host_map.go for more information.
files hostMap
}
@@ -112,7 +114,8 @@ func (as *addressSpace) mapHostFile(addr usermem.Addr, fd int, fr platform.FileR
inv := false
for _, m := range ms {
// The host mapped slices are guaranteed to be aligned.
- inv = inv || as.mapHost(addr, m, at)
+ prev := as.mapHost(addr, m, at)
+ inv = inv || prev
addr += usermem.Addr(m.length)
}
if inv {
@@ -157,10 +160,11 @@ func (as *addressSpace) mapFilemem(addr usermem.Addr, fr platform.FileRange, at
_ = s[i] // Touch to commit.
}
}
- inv = inv || as.mapHost(addr, hostMapEntry{
+ prev := as.mapHost(addr, hostMapEntry{
addr: reflect.ValueOf(&s[0]).Pointer(),
length: uintptr(len(s)),
}, at)
+ inv = inv || prev
addr += usermem.Addr(len(s))
}
if inv {
diff --git a/pkg/sentry/platform/kvm/host_map.go b/pkg/sentry/platform/kvm/host_map.go
index 357f8c92e..fc16ad2de 100644
--- a/pkg/sentry/platform/kvm/host_map.go
+++ b/pkg/sentry/platform/kvm/host_map.go
@@ -35,28 +35,48 @@ type hostMapEntry struct {
length uintptr
}
-func (hm *hostMap) forEachEntry(r usermem.AddrRange, fn func(offset uint64, m hostMapEntry)) {
- for seg := hm.set.FindSegment(r.Start); seg.Ok() && seg.Start() < r.End; seg = seg.NextSegment() {
- length := uintptr(seg.Range().Length())
- segOffset := uint64(0) // Adjusted below.
- if seg.End() > r.End {
- length -= uintptr(seg.End() - r.End)
- }
- if seg.Start() < r.Start {
- length -= uintptr(r.Start - seg.Start())
+// forEach iterates over all mappings in the given range.
+//
+// Precondition: segFn and gapFn must be non-nil.
+func (hm *hostMap) forEach(
+ r usermem.AddrRange,
+ segFn func(offset uint64, m hostMapEntry),
+ gapFn func(offset uint64, length uintptr) (uintptr, bool)) {
+
+ seg, gap := hm.set.Find(r.Start)
+ for {
+ if seg.Ok() && seg.Start() < r.End {
+ // A valid segment: pass information.
+ overlap := seg.Range().Intersect(r)
+ segOffset := uintptr(overlap.Start - seg.Start())
+ mapOffset := uint64(overlap.Start - r.Start)
+ segFn(mapOffset, hostMapEntry{
+ addr: seg.Value() + segOffset,
+ length: uintptr(overlap.Length()),
+ })
+ seg, gap = seg.NextNonEmpty()
+ } else if gap.Ok() && gap.Start() < r.End {
+ // A gap: pass gap information.
+ overlap := gap.Range().Intersect(r)
+ mapOffset := uint64(overlap.Start - r.Start)
+ addr, ok := gapFn(mapOffset, uintptr(overlap.Length()))
+ if ok {
+ seg = hm.set.Insert(gap, overlap, addr)
+ seg, gap = seg.NextNonEmpty()
+ } else {
+ seg = gap.NextSegment()
+ gap = hostMapGapIterator{} // Invalid.
+ }
} else {
- segOffset = uint64(seg.Start() - r.Start)
+ // Terminal.
+ break
}
- fn(segOffset, hostMapEntry{
- addr: seg.Value(),
- length: length,
- })
}
}
func (hm *hostMap) createMappings(r usermem.AddrRange, at usermem.AccessType, fd int, offset uint64) (ms []hostMapEntry, err error) {
- // Replace any existing mappings.
- hm.forEachEntry(r, func(segOffset uint64, m hostMapEntry) {
+ hm.forEach(r, func(mapOffset uint64, m hostMapEntry) {
+ // Replace any existing mappings.
_, _, errno := syscall.RawSyscall6(
syscall.SYS_MMAP,
m.addr,
@@ -64,48 +84,40 @@ func (hm *hostMap) createMappings(r usermem.AddrRange, at usermem.AccessType, fd
uintptr(at.Prot()),
syscall.MAP_FIXED|syscall.MAP_SHARED,
uintptr(fd),
- uintptr(offset+segOffset))
+ uintptr(offset+mapOffset))
if errno != 0 && err == nil {
err = errno
}
- })
- if err != nil {
- return nil, err
- }
-
- // Add in necessary new mappings.
- for gap := hm.set.FindGap(r.Start); gap.Ok() && gap.Start() < r.End; {
- length := uintptr(gap.Range().Length())
- gapOffset := uint64(0) // Adjusted below.
- if gap.End() > r.End {
- length -= uintptr(gap.End() - r.End)
- }
- if gap.Start() < r.Start {
- length -= uintptr(r.Start - gap.Start())
- } else {
- gapOffset = uint64(gap.Start() - r.Start)
- }
-
- // Map the host file memory.
- hostAddr, _, errno := syscall.RawSyscall6(
+ }, func(mapOffset uint64, length uintptr) (uintptr, bool) {
+ // Create a new mapping.
+ addr, _, errno := syscall.RawSyscall6(
syscall.SYS_MMAP,
0,
length,
uintptr(at.Prot()),
syscall.MAP_SHARED,
uintptr(fd),
- uintptr(offset+gapOffset))
+ uintptr(offset+mapOffset))
if errno != 0 {
- return nil, errno
+ err = errno
+ return 0, false
}
-
- // Insert into the host set and move to the next gap.
- gap = hm.set.Insert(gap, gap.Range().Intersect(r), hostAddr).NextGap()
+ return addr, true
+ })
+ if err != nil {
+ return nil, err
}
- // Collect all slices.
- hm.forEachEntry(r, func(_ uint64, m hostMapEntry) {
+ // Collect all entries.
+ //
+ // We do this after the first iteration because some segments may have
+ // been merged in the above, and we'll return the simplest form. This
+ // also provides a basic sanity check in the form of no gaps.
+ hm.forEach(r, func(_ uint64, m hostMapEntry) {
ms = append(ms, m)
+ }, func(uint64, uintptr) (uintptr, bool) {
+ // Should not happen: we just mapped this above.
+ panic("unexpected gap")
})
return ms, nil
@@ -121,7 +133,7 @@ func (hm *hostMap) CreateMappings(r usermem.AddrRange, at usermem.AccessType, fd
func (hm *hostMap) deleteMapping(r usermem.AddrRange) {
// Remove all the existing mappings.
- hm.forEachEntry(r, func(_ uint64, m hostMapEntry) {
+ hm.forEach(r, func(_ uint64, m hostMapEntry) {
_, _, errno := syscall.RawSyscall(
syscall.SYS_MUNMAP,
m.addr,
@@ -131,9 +143,13 @@ func (hm *hostMap) deleteMapping(r usermem.AddrRange) {
// Should never happen.
panic(fmt.Sprintf("unmap error: %v", errno))
}
+ }, func(uint64, uintptr) (uintptr, bool) {
+ // Sometimes deleteMapping will be called on a larger range
+ // than physical mappings are defined. That's okay.
+ return 0, false
})
- // Knock the range out.
+ // Knock the entire range out.
hm.set.RemoveRange(r)
}