Constrain MM.mapASLocked() to required range under PlatformEffectPopulate.

PlatformEffectPopulate is currently only used by nvproxy; compared to switching
to PlatformEffectCommit, this preserves the distinction of not using
MAP_POPULATE if not requested by the application.

PiperOrigin-RevId: 607013252
This commit is contained in:
Jamie Liu
2024-02-14 09:38:19 -08:00
committed by gVisor bot
parent e56225db03
commit f5462c934b
3 changed files with 24 additions and 21 deletions
+9 -7
View File
@@ -19,6 +19,7 @@ import (
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/hostarch"
"gvisor.dev/gvisor/pkg/sentry/memmap"
"gvisor.dev/gvisor/pkg/sentry/platform"
)
@@ -162,8 +163,7 @@ func (mm *MemoryManager) Deactivate() {
mm.activeMu.Unlock()
}
// mapASLocked maps addresses in ar into mm.as. If precommit is true, mappings
// for all addresses in ar should be precommitted.
// mapASLocked maps addresses in ar into mm.as.
//
// Preconditions:
// - mm.activeMu must be locked.
@@ -171,13 +171,15 @@ func (mm *MemoryManager) Deactivate() {
// - ar.Length() != 0.
// - ar must be page-aligned.
// - pseg == mm.pmas.LowerBoundSegment(ar.Start).
func (mm *MemoryManager) mapASLocked(pseg pmaIterator, ar hostarch.AddrRange, precommit bool) error {
func (mm *MemoryManager) mapASLocked(pseg pmaIterator, ar hostarch.AddrRange, platformEffect memmap.MMapPlatformEffect) error {
// By default, map entire pmas at a time, under the assumption that there
// is no cost to mapping more of a pma than necessary.
mapAR := hostarch.AddrRange{0, ^hostarch.Addr(hostarch.PageSize - 1)}
if precommit {
// When explicitly precommitting, only map ar, since overmapping may
// incur unexpected resource usage.
if platformEffect != memmap.PlatformEffectDefault {
// When explicitly committing, only map ar, since overmapping may incur
// unexpected resource usage. When explicitly populating, do the same
// since an underlying device file may be sensitive to the mapped
// range.
mapAR = ar
} else if mapUnit := mm.p.MapUnit(); mapUnit != 0 {
// Limit the range we map to ar, aligned to mapUnit.
@@ -205,7 +207,7 @@ func (mm *MemoryManager) mapASLocked(pseg pmaIterator, ar hostarch.AddrRange, pr
perms.Write = false
}
if perms.Any() { // MapFile precondition
if err := mm.as.MapFile(pmaMapAR.Start, pma.file, pseg.fileRangeOf(pmaMapAR), perms, precommit); err != nil {
if err := mm.as.MapFile(pmaMapAR.Start, pma.file, pseg.fileRangeOf(pmaMapAR), perms, platformEffect == memmap.PlatformEffectCommit); err != nil {
return err
}
}
+2 -1
View File
@@ -19,6 +19,7 @@ import (
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/hostarch"
"gvisor.dev/gvisor/pkg/safemem"
"gvisor.dev/gvisor/pkg/sentry/memmap"
"gvisor.dev/gvisor/pkg/sentry/platform"
"gvisor.dev/gvisor/pkg/usermem"
)
@@ -499,7 +500,7 @@ func (mm *MemoryManager) handleASIOFault(ctx context.Context, addr hostarch.Addr
// anymore.
mm.activeMu.DowngradeLock()
err = mm.mapASLocked(pseg, ar, false)
err = mm.mapASLocked(pseg, ar, memmap.PlatformEffectDefault)
mm.activeMu.RUnlock()
return translateIOError(ctx, err)
}
+13 -13
View File
@@ -65,7 +65,7 @@ func (mm *MemoryManager) HandleUserFault(ctx context.Context, addr hostarch.Addr
mm.activeMu.DowngradeLock()
// Map the faulted page into the active AddressSpace.
err = mm.mapASLocked(pseg, ar, false)
err = mm.mapASLocked(pseg, ar, memmap.PlatformEffectDefault)
mm.activeMu.RUnlock()
return err
}
@@ -133,7 +133,7 @@ func (mm *MemoryManager) MMap(ctx context.Context, opts memmap.MMapOpts) (hostar
switch {
case opts.PlatformEffect >= memmap.PlatformEffectPopulate || opts.MLockMode == memmap.MLockEager:
// Get pmas and map as requested.
mm.populateVMAAndUnlock(ctx, vseg, ar, opts.PlatformEffect == memmap.PlatformEffectCommit)
mm.populateVMAAndUnlock(ctx, vseg, ar, opts.PlatformEffect)
case opts.Mappable == nil && length <= privateAllocUnit:
// NOTE(b/63077076, b/63360184): Get pmas and map eagerly in the hope
@@ -142,7 +142,7 @@ func (mm *MemoryManager) MMap(ctx context.Context, opts memmap.MMapOpts) (hostar
// memmap.Mappable.Translate is unknown; and only for small mappings,
// to avoid needing to allocate large amounts of memory that we may
// subsequently need to checkpoint.
mm.populateVMAAndUnlock(ctx, vseg, ar, false)
mm.populateVMAAndUnlock(ctx, vseg, ar, memmap.PlatformEffectDefault)
default:
mm.mappingMu.Unlock()
@@ -161,7 +161,7 @@ func (mm *MemoryManager) MMap(ctx context.Context, opts memmap.MMapOpts) (hostar
// Preconditions:
// - mm.mappingMu must be locked.
// - vseg.Range().IsSupersetOf(ar).
func (mm *MemoryManager) populateVMA(ctx context.Context, vseg vmaIterator, ar hostarch.AddrRange, precommit bool) {
func (mm *MemoryManager) populateVMA(ctx context.Context, vseg vmaIterator, ar hostarch.AddrRange, platformEffect memmap.MMapPlatformEffect) {
if !vseg.ValuePtr().effectivePerms.Any() {
// Linux doesn't populate inaccessible pages. See
// mm/gup.c:populate_vma_page_range.
@@ -193,7 +193,7 @@ func (mm *MemoryManager) populateVMA(ctx context.Context, vseg vmaIterator, ar h
mm.activeMu.DowngradeLock()
// As above, errors are silently ignored.
mm.mapASLocked(pseg, ar, precommit)
mm.mapASLocked(pseg, ar, platformEffect)
mm.activeMu.RUnlock()
}
@@ -208,7 +208,7 @@ func (mm *MemoryManager) populateVMA(ctx context.Context, vseg vmaIterator, ar h
//
// Postconditions: mm.mappingMu will be unlocked.
// +checklocksrelease:mm.mappingMu
func (mm *MemoryManager) populateVMAAndUnlock(ctx context.Context, vseg vmaIterator, ar hostarch.AddrRange, precommit bool) {
func (mm *MemoryManager) populateVMAAndUnlock(ctx context.Context, vseg vmaIterator, ar hostarch.AddrRange, platformEffect memmap.MMapPlatformEffect) {
// See populateVMA above for commentary.
if !vseg.ValuePtr().effectivePerms.Any() {
mm.mappingMu.Unlock()
@@ -234,7 +234,7 @@ func (mm *MemoryManager) populateVMAAndUnlock(ctx context.Context, vseg vmaItera
}
mm.activeMu.DowngradeLock()
mm.mapASLocked(pseg, ar, precommit)
mm.mapASLocked(pseg, ar, platformEffect)
mm.activeMu.RUnlock()
}
@@ -454,7 +454,7 @@ func (mm *MemoryManager) MRemap(ctx context.Context, oldAddr hostarch.Addr, oldS
}, droppedIDs)
if err == nil {
if vma.mlockMode == memmap.MLockEager {
mm.populateVMA(ctx, vseg, ar, true)
mm.populateVMA(ctx, vseg, ar, memmap.PlatformEffectCommit)
}
return oldAddr, nil
}
@@ -561,7 +561,7 @@ func (mm *MemoryManager) MRemap(ctx context.Context, oldAddr hostarch.Addr, oldS
if vma.mlockMode != memmap.MLockNone {
mm.lockedAS += uint64(newAR.Length())
if vma.mlockMode == memmap.MLockEager {
mm.populateVMA(ctx, vseg, newAR, true)
mm.populateVMA(ctx, vseg, newAR, memmap.PlatformEffectCommit)
}
}
return newAR.Start, nil
@@ -605,7 +605,7 @@ func (mm *MemoryManager) MRemap(ctx context.Context, oldAddr hostarch.Addr, oldS
}
if vma.mlockMode == memmap.MLockEager {
mm.populateVMA(ctx, vseg, newAR, true)
mm.populateVMA(ctx, vseg, newAR, memmap.PlatformEffectCommit)
}
return newAR.Start, nil
@@ -796,7 +796,7 @@ func (mm *MemoryManager) Brk(ctx context.Context, addr hostarch.Addr) (hostarch.
}
mm.brk.End = addr
if mm.defMLockMode == memmap.MLockEager {
mm.populateVMAAndUnlock(ctx, vseg, ar, true)
mm.populateVMAAndUnlock(ctx, vseg, ar, memmap.PlatformEffectCommit)
} else {
mm.mappingMu.Unlock()
}
@@ -909,7 +909,7 @@ func (mm *MemoryManager) MLock(ctx context.Context, addr hostarch.Addr, length u
mm.mappingMu.RUnlock()
if mm.as != nil {
mm.activeMu.DowngradeLock()
err := mm.mapASLocked(mm.pmas.LowerBoundSegment(ar.Start), ar, true /* precommit */)
err := mm.mapASLocked(mm.pmas.LowerBoundSegment(ar.Start), ar, memmap.PlatformEffectCommit)
mm.activeMu.RUnlock()
if err != nil {
return err
@@ -993,7 +993,7 @@ func (mm *MemoryManager) MLockAll(ctx context.Context, opts MLockAllOpts) error
mm.mappingMu.RUnlock()
if mm.as != nil {
mm.activeMu.DowngradeLock()
mm.mapASLocked(mm.pmas.FirstSegment(), mm.applicationAddrRange(), true /* precommit */)
mm.mapASLocked(mm.pmas.FirstSegment(), mm.applicationAddrRange(), memmap.PlatformEffectCommit)
mm.activeMu.RUnlock()
} else {
mm.activeMu.Unlock()