diff options
author | Nicolas Lacasse <nlacasse@google.com> | 2018-07-19 14:52:43 -0700 |
---|---|---|
committer | Shentubot <shentubot@google.com> | 2018-07-19 14:53:38 -0700 |
commit | ea371031968095209793ea39007cfdf5a9d66d10 (patch) | |
tree | dda4a3353bf0d0a5197208af5eb4bd1c35d4209a | |
parent | df5a5d388e1fc3349ee70c3476fdffb195fbce9c (diff) |
ConfigureMMap on an overlay file delegates to the upper if there is no lower.
In the general case with an overlay, all mmap calls must go through the
overlay, because in the event of a copy-up, the overlay needs to invalidate any
previously-created mappings.
If there if no lower file, however, there will never be a copy-up, so the
overlay can delegate directly to the upper file in that case.
This also allows us to correctly mmap /dev/zero when it is in an overlay. This
file has special semantics which the overlay does not know about. In
particular, it does not implement Mappable(), which (in the general case) the
overlay uses to detect if a file is mappable or not.
PiperOrigin-RevId: 205306743
Change-Id: I92331649aa648340ef6e65411c2b42c12fa69631
-rw-r--r-- | pkg/sentry/fs/file_overlay.go | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/pkg/sentry/fs/file_overlay.go b/pkg/sentry/fs/file_overlay.go index c27c5946e..36b2cf75e 100644 --- a/pkg/sentry/fs/file_overlay.go +++ b/pkg/sentry/fs/file_overlay.go @@ -18,6 +18,7 @@ import ( "sync" "gvisor.googlesource.com/gvisor/pkg/log" + "gvisor.googlesource.com/gvisor/pkg/refs" "gvisor.googlesource.com/gvisor/pkg/sentry/arch" "gvisor.googlesource.com/gvisor/pkg/sentry/context" "gvisor.googlesource.com/gvisor/pkg/sentry/memmap" @@ -263,6 +264,34 @@ func (*overlayFileOperations) ConfigureMMap(ctx context.Context, file *File, opt o.copyMu.RLock() defer o.copyMu.RUnlock() + // If there is no lower inode, the overlay will never need to do a + // copy-up, and thus will never need to invalidate any mappings. We can + // call ConfigureMMap directly on the upper file. + if o.lower == nil { + f := file.FileOperations.(*overlayFileOperations) + if err := f.upper.ConfigureMMap(ctx, opts); err != nil { + return err + } + + // ConfigureMMap will set the MappableIdentity to the upper + // file and take a reference on it, but we must also hold a + // reference to the overlay file during the lifetime of the + // Mappable. If we do not do this, the overlay file can be + // Released before the upper file is Released, and we will be + // unable to traverse to the upper file during Save, thus + // preventing us from saving a proper inode mapping for the + // file. + file.IncRef() + id := &overlayMappingIdentity{ + id: opts.MappingIdentity, + overlayFile: file, + } + + // Swap out the old MappingIdentity for the wrapped one. + opts.MappingIdentity = id + return nil + } + if !o.isMappableLocked() { return syserror.ENODEV } @@ -343,3 +372,42 @@ func readdirOne(ctx context.Context, d *Dirent) (map[string]DentAttr, error) { delete(stubSerializer.Entries, "..") return stubSerializer.Entries, nil } + +// overlayMappingIdentity wraps a MappingIdentity, and also holds a reference +// on a file during its lifetime. +type overlayMappingIdentity struct { + refs.AtomicRefCount + id memmap.MappingIdentity + overlayFile *File +} + +// DecRef implements AtomicRefCount.DecRef. +func (omi *overlayMappingIdentity) DecRef() { + omi.AtomicRefCount.DecRefWithDestructor(func() { + omi.overlayFile.DecRef() + omi.id.DecRef() + }) +} + +// DeviceID implements MappingIdentity.DeviceID using the device id from the +// overlayFile. +func (omi *overlayMappingIdentity) DeviceID() uint64 { + return omi.overlayFile.Dirent.Inode.StableAttr.DeviceID +} + +// DeviceID implements MappingIdentity.InodeID using the inode id from the +// overlayFile. +func (omi *overlayMappingIdentity) InodeID() uint64 { + return omi.overlayFile.Dirent.Inode.StableAttr.InodeID +} + +// MappedName implements MappingIdentity.MappedName. +func (omi *overlayMappingIdentity) MappedName(ctx context.Context) string { + name, _ := omi.overlayFile.Dirent.FullName(RootFromContext(ctx)) + return name +} + +// Msync implements MappingIdentity.Msync. +func (omi *overlayMappingIdentity) Msync(ctx context.Context, mr memmap.MappableRange) error { + return omi.id.Msync(ctx, mr) +} |