Fix memmap.Translation.Perms returns.

memmap.Mappable.Translate() is passed a hostarch.AccessType indicating what
permissions are *immediately* required; it returns permissions in
memmap.Translation.Perms that are granted *to MM* until invalidation. MM
ensures that the permissions granted to the application are the intersection of
those granted by Translate, and those granted by VMA permissions; see
determination of pma.effectivePerms in
mm.MemoryManager.getPMAsInternalLocked(). This mechanism is used to avoid
marking pages dirty in the sentry's page cache for gofer-backed files until
PROT_WRITE pages are actually written to; see gofer.dentry.Translate(). In most
other cases, granting all supported permissions (to MM) up-front avoids a
redundant page fault for pages that are touched first for reading, and later
for writing.

Also:

- Prevent PROT_WRITE mappings of erofs files at mmap()/mprotect() time, rather
  than raising SIGBUS when writing to such mappings.

- Map nvproxy.frontendFD with PlatformEffectPopulate. This is the original goal
  of this CL; however, before this rest of this CL, MM.MMap() =>
  MM.populateVMAAndUnlock() => MM.getPMAsLocked(at=hostarch.NoAccess) =>
  MM.getPMAsInternalLocked(at=hostarch.NoAccess) =>
  nvproxy.frontendFD.Translate(at=hostarch.NoAccess) returns Translations with
  no permissions, causing MM.mapASLocked() to no-op.

PiperOrigin-RevId: 679360594
This commit is contained in:
Jamie Liu
2024-09-26 17:59:37 -07:00
committed by gVisor bot
parent 4a583f62ed
commit 86ceb5c26a
10 changed files with 27 additions and 15 deletions
+7 -1
View File
@@ -23,6 +23,12 @@ import (
// ConfigureMMap implements vfs.FileDescriptionImpl.ConfigureMMap.
func (fd *frontendFD) ConfigureMMap(ctx context.Context, opts *memmap.MMapOpts) error {
// Nvidia kernel driver: kernel-open/nvidia/nv-mmap.c:nvidia_mmap_helper()
// requires vm_pgoff == 0, so trying to lazily fault any subset of the
// mapping that doesn't include the beginning will fail.
if opts.PlatformEffect < memmap.PlatformEffectPopulate {
opts.PlatformEffect = memmap.PlatformEffectPopulate
}
return vfs.GenericConfigureMMap(&fd.vfsfd, fd, opts)
}
@@ -47,7 +53,7 @@ func (fd *frontendFD) Translate(ctx context.Context, required, optional memmap.M
Source: optional,
File: &fd.memmapFile,
Offset: optional.Start,
Perms: at,
Perms: hostarch.AnyAccess,
},
}, nil
}
+1 -3
View File
@@ -54,9 +54,7 @@ func (fd *uvmFD) Translate(ctx context.Context, required, optional memmap.Mappab
Source: optional,
File: &fd.memmapFile,
Offset: optional.Start,
// kernel-open/nvidia-uvm/uvm.c:uvm_mmap() requires mappings to be
// PROT_READ|PROT_WRITE.
Perms: hostarch.ReadWrite,
Perms: hostarch.AnyAccess,
},
}, nil
}
@@ -50,7 +50,7 @@ func (fd *accelFD) Translate(ctx context.Context, required, optional memmap.Mapp
Source: optional,
File: &fd.memmapFile,
Offset: optional.Start,
Perms: at,
Perms: hostarch.AnyAccess,
},
}, nil
}
@@ -61,7 +61,7 @@ func (fd *pciDeviceFD) Translate(ctx context.Context, required, optional memmap.
Source: optional,
File: &fd.memmapFile,
Offset: optional.Start,
Perms: at,
Perms: hostarch.AnyAccess,
},
}, nil
}
@@ -50,7 +50,7 @@ func (fd *tpuFD) Translate(ctx context.Context, required, optional memmap.Mappab
Source: optional,
File: &fd.memmapFile,
Offset: optional.Start,
Perms: at,
Perms: hostarch.AnyAccess,
},
}, nil
}
@@ -50,7 +50,7 @@ func (fd *vfioFD) Translate(ctx context.Context, required, optional memmap.Mappa
Source: optional,
File: &fd.memmapFile,
Offset: optional.Start,
Perms: at,
Perms: hostarch.AnyAccess,
},
}, nil
}
+1
View File
@@ -61,6 +61,7 @@ go_library(
"//pkg/errors/linuxerr",
"//pkg/fspath",
"//pkg/hostarch",
"//pkg/log",
"//pkg/refs",
"//pkg/safemem",
"//pkg/sentry/fsimpl/lock",
+11 -1
View File
@@ -23,6 +23,7 @@ import (
"gvisor.dev/gvisor/pkg/erofs"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/hostarch"
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/safemem"
"gvisor.dev/gvisor/pkg/sentry/memmap"
"gvisor.dev/gvisor/pkg/sentry/vfs"
@@ -126,6 +127,9 @@ func (fd *regularFileFD) Seek(ctx context.Context, offset int64, whence int32) (
// ConfigureMMap implements vfs.FileDescriptionImpl.ConfigureMMap.
func (fd *regularFileFD) ConfigureMMap(ctx context.Context, opts *memmap.MMapOpts) error {
if opts.MaxPerms.Write && !opts.Private {
return linuxerr.EINVAL
}
return vfs.GenericConfigureMMap(&fd.vfsfd, fd.inode(), opts)
}
@@ -163,6 +167,10 @@ func (i *inode) Translate(ctx context.Context, required, optional memmap.Mappabl
optional.End = pgend
}
if at.Write {
// This shouldn't be possible due to the check in ConfigureMMap().
inodeTranslateWriteWarnOnce.Do(func() {
log.Traceback("erofs.inode.Translate: unexpected access type %v", at)
})
return nil, &memmap.BusError{linuxerr.EROFS}
}
offset, err := i.DataOffset()
@@ -175,11 +183,13 @@ func (i *inode) Translate(ctx context.Context, required, optional memmap.Mappabl
Source: mr,
File: &i.fs.mf,
Offset: mr.Start + offset,
Perms: at,
Perms: hostarch.ReadExecute,
},
}, nil
}
var inodeTranslateWriteWarnOnce sync.Once
// InvalidateUnsavable implements memmap.Mappable.InvalidateUnsavable.
func (i *inode) InvalidateUnsavable(ctx context.Context) error {
i.mapsMu.Lock()
+1 -4
View File
@@ -809,10 +809,7 @@ func (d *dentry) Translate(ctx context.Context, required, optional memmap.Mappab
segMR := seg.Range().Intersect(optional)
// TODO(jamieliu): Make Translations writable even if writability is
// not required if already kept-dirty by another writable translation.
perms := hostarch.AccessType{
Read: true,
Execute: true,
}
perms := hostarch.ReadExecute
if at.Write {
// From this point forward, this memory can be dirtied through the
// mapping at any time.
+2 -2
View File
@@ -570,7 +570,7 @@ func (sqemf *sqEntriesFile) Translate(ctx context.Context, required, optional me
Source: source,
File: pgalloc.MemoryFileFromContext(ctx),
Offset: sqemf.fr.Start + source.Start,
Perms: at,
Perms: hostarch.AnyAccess,
},
}, nil
}
@@ -616,7 +616,7 @@ func (rbmf *ringsBufferFile) Translate(ctx context.Context, required, optional m
Source: source,
File: pgalloc.MemoryFileFromContext(ctx),
Offset: rbmf.fr.Start + source.Start,
Perms: at,
Perms: hostarch.AnyAccess,
},
}, nil
}