diff options
author | Jamie Liu <jamieliu@google.com> | 2019-08-29 10:50:48 -0700 |
---|---|---|
committer | Nicolas Lacasse <nlacasse@google.com> | 2019-08-29 14:01:03 -0700 |
commit | 36a8949b2a52aabbe3f0548f1207c133da113c56 (patch) | |
tree | 37da2f9a78fba1cd8243e9cf311de96060e7a11a /pkg/sentry | |
parent | 6e8fc27dc5de8ed0a04fe943a6354c0133bfc63f (diff) |
Add limit_host_fd_translation Gofer mount option.
PiperOrigin-RevId: 266177409
Diffstat (limited to 'pkg/sentry')
-rw-r--r-- | pkg/sentry/fs/fsutil/inode_cached.go | 34 | ||||
-rw-r--r-- | pkg/sentry/fs/fsutil/inode_cached_test.go | 10 | ||||
-rw-r--r-- | pkg/sentry/fs/gofer/fs.go | 22 | ||||
-rw-r--r-- | pkg/sentry/fs/gofer/session.go | 27 | ||||
-rw-r--r-- | pkg/sentry/fs/host/inode.go | 6 |
5 files changed, 68 insertions, 31 deletions
diff --git a/pkg/sentry/fs/fsutil/inode_cached.go b/pkg/sentry/fs/fsutil/inode_cached.go index e70bc28fb..20cb9a367 100644 --- a/pkg/sentry/fs/fsutil/inode_cached.go +++ b/pkg/sentry/fs/fsutil/inode_cached.go @@ -66,10 +66,8 @@ type CachingInodeOperations struct { // mfp is used to allocate memory that caches backingFile's contents. mfp pgalloc.MemoryFileProvider - // forcePageCache indicates the sentry page cache should be used regardless - // of whether the platform supports host mapped I/O or not. This must not be - // modified after inode creation. - forcePageCache bool + // opts contains options. opts is immutable. + opts CachingInodeOperationsOptions attrMu sync.Mutex `state:"nosave"` @@ -116,6 +114,20 @@ type CachingInodeOperations struct { refs frameRefSet } +// CachingInodeOperationsOptions configures a CachingInodeOperations. +// +// +stateify savable +type CachingInodeOperationsOptions struct { + // If ForcePageCache is true, use the sentry page cache even if a host file + // descriptor is available. + ForcePageCache bool + + // If LimitHostFDTranslation is true, apply maxFillRange() constraints to + // host file descriptor mappings returned by + // CachingInodeOperations.Translate(). + LimitHostFDTranslation bool +} + // CachedFileObject is a file that may require caching. type CachedFileObject interface { // ReadToBlocksAt reads up to dsts.NumBytes() bytes from the file to dsts, @@ -159,7 +171,7 @@ type CachedFileObject interface { // NewCachingInodeOperations returns a new CachingInodeOperations backed by // a CachedFileObject and its initial unstable attributes. -func NewCachingInodeOperations(ctx context.Context, backingFile CachedFileObject, uattr fs.UnstableAttr, forcePageCache bool) *CachingInodeOperations { +func NewCachingInodeOperations(ctx context.Context, backingFile CachedFileObject, uattr fs.UnstableAttr, opts CachingInodeOperationsOptions) *CachingInodeOperations { mfp := pgalloc.MemoryFileProviderFromContext(ctx) if mfp == nil { panic(fmt.Sprintf("context.Context %T lacks non-nil value for key %T", ctx, pgalloc.CtxMemoryFileProvider)) @@ -167,7 +179,7 @@ func NewCachingInodeOperations(ctx context.Context, backingFile CachedFileObject return &CachingInodeOperations{ backingFile: backingFile, mfp: mfp, - forcePageCache: forcePageCache, + opts: opts, attr: uattr, hostFileMapper: NewHostFileMapper(), } @@ -763,7 +775,7 @@ func (rw *inodeReadWriter) WriteFromBlocks(srcs safemem.BlockSeq) (uint64, error // and memory mappings, and false if c.cache may contain data cached from // c.backingFile. func (c *CachingInodeOperations) useHostPageCache() bool { - return !c.forcePageCache && c.backingFile.FD() >= 0 + return !c.opts.ForcePageCache && c.backingFile.FD() >= 0 } // AddMapping implements memmap.Mappable.AddMapping. @@ -835,11 +847,15 @@ func (c *CachingInodeOperations) CopyMapping(ctx context.Context, ms memmap.Mapp func (c *CachingInodeOperations) Translate(ctx context.Context, required, optional memmap.MappableRange, at usermem.AccessType) ([]memmap.Translation, error) { // Hot path. Avoid defer. if c.useHostPageCache() { + mr := optional + if c.opts.LimitHostFDTranslation { + mr = maxFillRange(required, optional) + } return []memmap.Translation{ { - Source: optional, + Source: mr, File: c, - Offset: optional.Start, + Offset: mr.Start, Perms: usermem.AnyAccess, }, }, nil diff --git a/pkg/sentry/fs/fsutil/inode_cached_test.go b/pkg/sentry/fs/fsutil/inode_cached_test.go index dc19255ed..eb5730c35 100644 --- a/pkg/sentry/fs/fsutil/inode_cached_test.go +++ b/pkg/sentry/fs/fsutil/inode_cached_test.go @@ -61,7 +61,7 @@ func TestSetPermissions(t *testing.T) { uattr := fs.WithCurrentTime(ctx, fs.UnstableAttr{ Perms: fs.FilePermsFromMode(0444), }) - iops := NewCachingInodeOperations(ctx, noopBackingFile{}, uattr, false /*forcePageCache*/) + iops := NewCachingInodeOperations(ctx, noopBackingFile{}, uattr, CachingInodeOperationsOptions{}) defer iops.Release() perms := fs.FilePermsFromMode(0777) @@ -150,7 +150,7 @@ func TestSetTimestamps(t *testing.T) { ModificationTime: epoch, StatusChangeTime: epoch, } - iops := NewCachingInodeOperations(ctx, noopBackingFile{}, uattr, false /*forcePageCache*/) + iops := NewCachingInodeOperations(ctx, noopBackingFile{}, uattr, CachingInodeOperationsOptions{}) defer iops.Release() if err := iops.SetTimestamps(ctx, nil, test.ts); err != nil { @@ -188,7 +188,7 @@ func TestTruncate(t *testing.T) { uattr := fs.UnstableAttr{ Size: 0, } - iops := NewCachingInodeOperations(ctx, noopBackingFile{}, uattr, false /*forcePageCache*/) + iops := NewCachingInodeOperations(ctx, noopBackingFile{}, uattr, CachingInodeOperationsOptions{}) defer iops.Release() if err := iops.Truncate(ctx, nil, uattr.Size); err != nil { @@ -280,7 +280,7 @@ func TestRead(t *testing.T) { uattr := fs.UnstableAttr{ Size: int64(len(buf)), } - iops := NewCachingInodeOperations(ctx, newSliceBackingFile(buf), uattr, false /*forcePageCache*/) + iops := NewCachingInodeOperations(ctx, newSliceBackingFile(buf), uattr, CachingInodeOperationsOptions{}) defer iops.Release() // Expect the cache to be initially empty. @@ -336,7 +336,7 @@ func TestWrite(t *testing.T) { uattr := fs.UnstableAttr{ Size: int64(len(buf)), } - iops := NewCachingInodeOperations(ctx, newSliceBackingFile(buf), uattr, false /*forcePageCache*/) + iops := NewCachingInodeOperations(ctx, newSliceBackingFile(buf), uattr, CachingInodeOperationsOptions{}) defer iops.Release() // Expect the cache to be initially empty. diff --git a/pkg/sentry/fs/gofer/fs.go b/pkg/sentry/fs/gofer/fs.go index 69999dc28..8f8ab5d29 100644 --- a/pkg/sentry/fs/gofer/fs.go +++ b/pkg/sentry/fs/gofer/fs.go @@ -54,6 +54,10 @@ const ( // sandbox using files backed by the gofer. If set to false, unix sockets // cannot be bound to gofer files without an overlay on top. privateUnixSocketKey = "privateunixsocket" + + // If present, sets CachingInodeOperationsOptions.LimitHostFDTranslation to + // true. + limitHostFDTranslationKey = "limit_host_fd_translation" ) // defaultAname is the default attach name. @@ -134,12 +138,13 @@ func (f *filesystem) Mount(ctx context.Context, device string, flags fs.MountSou // opts are parsed 9p mount options. type opts struct { - fd int - aname string - policy cachePolicy - msize uint32 - version string - privateunixsocket bool + fd int + aname string + policy cachePolicy + msize uint32 + version string + privateunixsocket bool + limitHostFDTranslation bool } // options parses mount(2) data into structured options. @@ -237,6 +242,11 @@ func options(data string) (opts, error) { delete(options, privateUnixSocketKey) } + if _, ok := options[limitHostFDTranslationKey]; ok { + o.limitHostFDTranslation = true + delete(options, limitHostFDTranslationKey) + } + // Fail to attach if the caller wanted us to do something that we // don't support. if len(options) > 0 { diff --git a/pkg/sentry/fs/gofer/session.go b/pkg/sentry/fs/gofer/session.go index 69d08a627..50da865c1 100644 --- a/pkg/sentry/fs/gofer/session.go +++ b/pkg/sentry/fs/gofer/session.go @@ -117,6 +117,11 @@ type session struct { // Flags provided to the mount. superBlockFlags fs.MountSourceFlags `state:"wait"` + // limitHostFDTranslation is the value used for + // CachingInodeOperationsOptions.LimitHostFDTranslation for all + // CachingInodeOperations created by the session. + limitHostFDTranslation bool + // connID is a unique identifier for the session connection. connID string `state:"wait"` @@ -218,8 +223,11 @@ func newInodeOperations(ctx context.Context, s *session, file contextFile, qid p uattr := unstable(ctx, valid, attr, s.mounter, s.client) return sattr, &inodeOperations{ - fileState: fileState, - cachingInodeOps: fsutil.NewCachingInodeOperations(ctx, fileState, uattr, s.superBlockFlags.ForcePageCache), + fileState: fileState, + cachingInodeOps: fsutil.NewCachingInodeOperations(ctx, fileState, uattr, fsutil.CachingInodeOperationsOptions{ + ForcePageCache: s.superBlockFlags.ForcePageCache, + LimitHostFDTranslation: s.limitHostFDTranslation, + }), } } @@ -242,13 +250,14 @@ func Root(ctx context.Context, dev string, filesystem fs.Filesystem, superBlockF // Construct the session. s := session{ - connID: dev, - msize: o.msize, - version: o.version, - cachePolicy: o.policy, - aname: o.aname, - superBlockFlags: superBlockFlags, - mounter: mounter, + connID: dev, + msize: o.msize, + version: o.version, + cachePolicy: o.policy, + aname: o.aname, + superBlockFlags: superBlockFlags, + limitHostFDTranslation: o.limitHostFDTranslation, + mounter: mounter, } s.EnableLeakCheck("gofer.session") diff --git a/pkg/sentry/fs/host/inode.go b/pkg/sentry/fs/host/inode.go index 679d8321a..894ab01f0 100644 --- a/pkg/sentry/fs/host/inode.go +++ b/pkg/sentry/fs/host/inode.go @@ -200,8 +200,10 @@ func newInode(ctx context.Context, msrc *fs.MountSource, fd int, saveable bool, // Build the fs.InodeOperations. uattr := unstableAttr(msrc.MountSourceOperations.(*superOperations), &s) iops := &inodeOperations{ - fileState: fileState, - cachingInodeOps: fsutil.NewCachingInodeOperations(ctx, fileState, uattr, msrc.Flags.ForcePageCache), + fileState: fileState, + cachingInodeOps: fsutil.NewCachingInodeOperations(ctx, fileState, uattr, fsutil.CachingInodeOperationsOptions{ + ForcePageCache: msrc.Flags.ForcePageCache, + }), } // Return the fs.Inode. |