Add support for mount flags

Plumbs MS_NOEXEC and MS_RDONLY. Others are TODO.

Updates #1623 #1193

PiperOrigin-RevId: 300764669
This commit is contained in:
Fabricio Voznika
2020-03-13 08:58:04 -07:00
committed by gVisor bot
parent f693e1334b
commit 8f8f16efaf
4 changed files with 42 additions and 23 deletions
-2
View File
@@ -115,8 +115,6 @@ func NewVFSLookup(mntns *vfs.MountNamespace, root, workingDir vfs.VirtualDentry)
//
// remainingTraversals is not configurable in VFS2, all callers are using the
// default anyways.
//
// TODO(gvisor.dev/issue/1623): Check mount has read and exec permission.
func (l *vfsLookup) OpenPath(ctx context.Context, pathname string, opts vfs.OpenOptions, _ *uint, resolveFinal bool) (File, error) {
vfsObj := l.mntns.Root().Mount().Filesystem().VirtualFilesystem()
creds := auth.CredentialsFromContext(ctx)
+22 -20
View File
@@ -74,6 +74,10 @@ type Mount struct {
// umounted is true. umounted is protected by VirtualFilesystem.mountMu.
umounted bool
// flags contains settings as specified for mount(2), e.g. MS_NOEXEC, except
// for MS_RDONLY which is tracked in "writers".
flags MountFlags
// The lower 63 bits of writers is the number of calls to
// Mount.CheckBeginWrite() that have not yet been paired with a call to
// Mount.EndWrite(). The MSB of writers is set if MS_RDONLY is in effect.
@@ -81,6 +85,21 @@ type Mount struct {
writers int64
}
func newMount(vfs *VirtualFilesystem, fs *Filesystem, root *Dentry, mntns *MountNamespace, opts *MountOptions) *Mount {
mnt := &Mount{
vfs: vfs,
fs: fs,
root: root,
flags: opts.Flags,
ns: mntns,
refs: 1,
}
if opts.ReadOnly {
mnt.setReadOnlyLocked(true)
}
return mnt
}
// A MountNamespace is a collection of Mounts.
//
// MountNamespaces are reference-counted. Unless otherwise specified, all
@@ -129,13 +148,7 @@ func (vfs *VirtualFilesystem) NewMountNamespace(ctx context.Context, creds *auth
refs: 1,
mountpoints: make(map[*Dentry]uint32),
}
mntns.root = &Mount{
vfs: vfs,
fs: fs,
root: root,
ns: mntns,
refs: 1,
}
mntns.root = newMount(vfs, fs, root, mntns, &MountOptions{})
return mntns, nil
}
@@ -148,12 +161,7 @@ func (vfs *VirtualFilesystem) NewDisconnectedMount(fs *Filesystem, root *Dentry,
if root != nil {
root.IncRef()
}
return &Mount{
vfs: vfs,
fs: fs,
root: root,
refs: 1,
}, nil
return newMount(vfs, fs, root, nil /* mntns */, opts), nil
}
// MountAt creates and mounts a Filesystem configured by the given arguments.
@@ -218,13 +226,7 @@ func (vfs *VirtualFilesystem) MountAt(ctx context.Context, creds *auth.Credentia
// are directories, or neither are, and returns ENOTDIR if this is not the
// case.
mntns := vd.mount.ns
mnt := &Mount{
vfs: vfs,
fs: fs,
root: root,
ns: mntns,
refs: 1,
}
mnt := newMount(vfs, fs, root, mntns, opts)
vfs.mounts.seq.BeginWrite()
vfs.connectLocked(mnt, vd, mntns)
vfs.mounts.seq.EndWrite()
+15 -1
View File
@@ -46,8 +46,21 @@ type MknodOptions struct {
DevMinor uint32
}
// MountFlags contains flags as specified for mount(2), e.g. MS_NOEXEC.
// MS_RDONLY is not part of MountFlags because it's tracked in Mount.writers.
type MountFlags struct {
// NoExec is equivalent to MS_NOEXEC.
NoExec bool
}
// MountOptions contains options to VirtualFilesystem.MountAt().
type MountOptions struct {
// Flags contains flags as specified for mount(2), e.g. MS_NOEXEC.
Flags MountFlags
// ReadOnly is equivalent to MS_RDONLY.
ReadOnly bool
// GetFilesystemOptions contains options to FilesystemType.GetFilesystem().
GetFilesystemOptions GetFilesystemOptions
@@ -75,7 +88,8 @@ type OpenOptions struct {
// FileExec is set when the file is being opened to be executed.
// VirtualFilesystem.OpenAt() checks that the caller has execute permissions
// on the file, and that the file is a regular file.
// on the file, that the file is a regular file, and that the mount doesn't
// have MS_NOEXEC set.
FileExec bool
}
+5
View File
@@ -388,6 +388,11 @@ func (vfs *VirtualFilesystem) OpenAt(ctx context.Context, creds *auth.Credential
// TODO(gvisor.dev/issue/1193): Move inside fsimpl to avoid another call
// to FileDescription.Stat().
if opts.FileExec {
if fd.Mount().flags.NoExec {
fd.DecRef()
return nil, syserror.EACCES
}
// Only a regular file can be executed.
stat, err := fd.Stat(ctx, StatOptions{Mask: linux.STATX_TYPE})
if err != nil {