summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorgVisor bot <gvisor-bot@google.com>2020-04-06 23:37:13 +0000
committergVisor bot <gvisor-bot@google.com>2020-04-06 23:37:13 +0000
commitcc6e5e72ef985cfcb53e897239cc111a31733c46 (patch)
tree807b305cdfe37f74a382595277eb62fde013c96e
parent8896fc29043691bdc617602c59d739c1fcaa4ede (diff)
parentdd98fdd5beb7f02e7c7b3aeb4f07f5d00ffc41e7 (diff)
Merge release-20200323.0-75-gdd98fdd (automated)
-rwxr-xr-xpkg/sentry/fsbridge/fsbridge_state_autogen.go10
-rwxr-xr-xpkg/sentry/fsbridge/vfs.go28
-rwxr-xr-xpkg/sentry/fsimpl/kernfs/filesystem.go36
-rwxr-xr-xpkg/sentry/fsimpl/kernfs/inode_impl_util.go5
-rwxr-xr-xpkg/sentry/fsimpl/kernfs/kernfs.go16
-rwxr-xr-xpkg/sentry/fsimpl/kernfs/symlink.go5
6 files changed, 71 insertions, 29 deletions
diff --git a/pkg/sentry/fsbridge/fsbridge_state_autogen.go b/pkg/sentry/fsbridge/fsbridge_state_autogen.go
index 51b57d859..d370b2d47 100755
--- a/pkg/sentry/fsbridge/fsbridge_state_autogen.go
+++ b/pkg/sentry/fsbridge/fsbridge_state_autogen.go
@@ -32,14 +32,14 @@ func (x *fsLookup) load(m state.Map) {
m.Load("workingDir", &x.workingDir)
}
-func (x *vfsFile) beforeSave() {}
-func (x *vfsFile) save(m state.Map) {
+func (x *VFSFile) beforeSave() {}
+func (x *VFSFile) save(m state.Map) {
x.beforeSave()
m.Save("file", &x.file)
}
-func (x *vfsFile) afterLoad() {}
-func (x *vfsFile) load(m state.Map) {
+func (x *VFSFile) afterLoad() {}
+func (x *VFSFile) load(m state.Map) {
m.Load("file", &x.file)
}
@@ -61,6 +61,6 @@ func (x *vfsLookup) load(m state.Map) {
func init() {
state.Register("pkg/sentry/fsbridge.fsFile", (*fsFile)(nil), state.Fns{Save: (*fsFile).save, Load: (*fsFile).load})
state.Register("pkg/sentry/fsbridge.fsLookup", (*fsLookup)(nil), state.Fns{Save: (*fsLookup).save, Load: (*fsLookup).load})
- state.Register("pkg/sentry/fsbridge.vfsFile", (*vfsFile)(nil), state.Fns{Save: (*vfsFile).save, Load: (*vfsFile).load})
+ state.Register("pkg/sentry/fsbridge.VFSFile", (*VFSFile)(nil), state.Fns{Save: (*VFSFile).save, Load: (*VFSFile).load})
state.Register("pkg/sentry/fsbridge.vfsLookup", (*vfsLookup)(nil), state.Fns{Save: (*vfsLookup).save, Load: (*vfsLookup).load})
}
diff --git a/pkg/sentry/fsbridge/vfs.go b/pkg/sentry/fsbridge/vfs.go
index 79b808359..89168220a 100755
--- a/pkg/sentry/fsbridge/vfs.go
+++ b/pkg/sentry/fsbridge/vfs.go
@@ -26,22 +26,22 @@ import (
"gvisor.dev/gvisor/pkg/usermem"
)
-// fsFile implements File interface over vfs.FileDescription.
+// VFSFile implements File interface over vfs.FileDescription.
//
// +stateify savable
-type vfsFile struct {
+type VFSFile struct {
file *vfs.FileDescription
}
-var _ File = (*vfsFile)(nil)
+var _ File = (*VFSFile)(nil)
// NewVFSFile creates a new File over fs.File.
func NewVFSFile(file *vfs.FileDescription) File {
- return &vfsFile{file: file}
+ return &VFSFile{file: file}
}
// PathnameWithDeleted implements File.
-func (f *vfsFile) PathnameWithDeleted(ctx context.Context) string {
+func (f *VFSFile) PathnameWithDeleted(ctx context.Context) string {
root := vfs.RootFromContext(ctx)
defer root.DecRef()
@@ -51,7 +51,7 @@ func (f *vfsFile) PathnameWithDeleted(ctx context.Context) string {
}
// ReadFull implements File.
-func (f *vfsFile) ReadFull(ctx context.Context, dst usermem.IOSequence, offset int64) (int64, error) {
+func (f *VFSFile) ReadFull(ctx context.Context, dst usermem.IOSequence, offset int64) (int64, error) {
var total int64
for dst.NumBytes() > 0 {
n, err := f.file.PRead(ctx, dst, offset+total, vfs.ReadOptions{})
@@ -67,12 +67,12 @@ func (f *vfsFile) ReadFull(ctx context.Context, dst usermem.IOSequence, offset i
}
// ConfigureMMap implements File.
-func (f *vfsFile) ConfigureMMap(ctx context.Context, opts *memmap.MMapOpts) error {
+func (f *VFSFile) ConfigureMMap(ctx context.Context, opts *memmap.MMapOpts) error {
return f.file.ConfigureMMap(ctx, opts)
}
// Type implements File.
-func (f *vfsFile) Type(ctx context.Context) (linux.FileMode, error) {
+func (f *VFSFile) Type(ctx context.Context) (linux.FileMode, error) {
stat, err := f.file.Stat(ctx, vfs.StatOptions{})
if err != nil {
return 0, err
@@ -81,15 +81,21 @@ func (f *vfsFile) Type(ctx context.Context) (linux.FileMode, error) {
}
// IncRef implements File.
-func (f *vfsFile) IncRef() {
+func (f *VFSFile) IncRef() {
f.file.IncRef()
}
// DecRef implements File.
-func (f *vfsFile) DecRef() {
+func (f *VFSFile) DecRef() {
f.file.DecRef()
}
+// FileDescription returns the FileDescription represented by f. It does not
+// take an additional reference on the returned FileDescription.
+func (f *VFSFile) FileDescription() *vfs.FileDescription {
+ return f.file
+}
+
// fsLookup implements Lookup interface using fs.File.
//
// +stateify savable
@@ -132,5 +138,5 @@ func (l *vfsLookup) OpenPath(ctx context.Context, pathname string, opts vfs.Open
if err != nil {
return nil, err
}
- return &vfsFile{file: fd}, nil
+ return &VFSFile{file: fd}, nil
}
diff --git a/pkg/sentry/fsimpl/kernfs/filesystem.go b/pkg/sentry/fsimpl/kernfs/filesystem.go
index 89f5da3d4..16a3c18ae 100755
--- a/pkg/sentry/fsimpl/kernfs/filesystem.go
+++ b/pkg/sentry/fsimpl/kernfs/filesystem.go
@@ -79,16 +79,22 @@ afterSymlink:
}
// Resolve any symlink at current path component.
if rp.ShouldFollowSymlink() && next.isSymlink() {
- // TODO: VFS2 needs something extra for /proc/[pid]/fd/ "magic symlinks".
- target, err := next.inode.Readlink(ctx)
+ targetVD, targetPathname, err := next.inode.Getlink(ctx)
if err != nil {
return nil, err
}
- if err := rp.HandleSymlink(target); err != nil {
- return nil, err
+ if targetVD.Ok() {
+ err := rp.HandleJump(targetVD)
+ targetVD.DecRef()
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ if err := rp.HandleSymlink(targetPathname); err != nil {
+ return nil, err
+ }
}
goto afterSymlink
-
}
rp.Advance()
return &next.vfsd, nil
@@ -470,19 +476,25 @@ afterTrailingSymlink:
}
childDentry := childVFSD.Impl().(*Dentry)
childInode := childDentry.inode
- if rp.ShouldFollowSymlink() {
- if childDentry.isSymlink() {
- target, err := childInode.Readlink(ctx)
+ if rp.ShouldFollowSymlink() && childDentry.isSymlink() {
+ targetVD, targetPathname, err := childInode.Getlink(ctx)
+ if err != nil {
+ return nil, err
+ }
+ if targetVD.Ok() {
+ err := rp.HandleJump(targetVD)
+ targetVD.DecRef()
if err != nil {
return nil, err
}
- if err := rp.HandleSymlink(target); err != nil {
+ } else {
+ if err := rp.HandleSymlink(targetPathname); err != nil {
return nil, err
}
- // rp.Final() may no longer be true since we now need to resolve the
- // symlink target.
- goto afterTrailingSymlink
}
+ // rp.Final() may no longer be true since we now need to resolve the
+ // symlink target.
+ goto afterTrailingSymlink
}
if err := childInode.CheckPermissions(ctx, rp.Credentials(), ats); err != nil {
return nil, err
diff --git a/pkg/sentry/fsimpl/kernfs/inode_impl_util.go b/pkg/sentry/fsimpl/kernfs/inode_impl_util.go
index 5c84b10c9..65f09af5d 100755
--- a/pkg/sentry/fsimpl/kernfs/inode_impl_util.go
+++ b/pkg/sentry/fsimpl/kernfs/inode_impl_util.go
@@ -181,6 +181,11 @@ func (InodeNotSymlink) Readlink(context.Context) (string, error) {
return "", syserror.EINVAL
}
+// Getlink implements Inode.Getlink.
+func (InodeNotSymlink) Getlink(context.Context) (vfs.VirtualDentry, string, error) {
+ return vfs.VirtualDentry{}, "", syserror.EINVAL
+}
+
// InodeAttrs partially implements the Inode interface, specifically the
// inodeMetadata sub interface. InodeAttrs provides functionality related to
// inode attributes.
diff --git a/pkg/sentry/fsimpl/kernfs/kernfs.go b/pkg/sentry/fsimpl/kernfs/kernfs.go
index 2cefef020..ad76b9f64 100755
--- a/pkg/sentry/fsimpl/kernfs/kernfs.go
+++ b/pkg/sentry/fsimpl/kernfs/kernfs.go
@@ -414,7 +414,21 @@ type inodeDynamicLookup interface {
}
type inodeSymlink interface {
- // Readlink resolves the target of a symbolic link. If an inode is not a
+ // Readlink returns the target of a symbolic link. If an inode is not a
// symlink, the implementation should return EINVAL.
Readlink(ctx context.Context) (string, error)
+
+ // Getlink returns the target of a symbolic link, as used by path
+ // resolution:
+ //
+ // - If the inode is a "magic link" (a link whose target is most accurately
+ // represented as a VirtualDentry), Getlink returns (ok VirtualDentry, "",
+ // nil). A reference is taken on the returned VirtualDentry.
+ //
+ // - If the inode is an ordinary symlink, Getlink returns (zero-value
+ // VirtualDentry, symlink target, nil).
+ //
+ // - If the inode is not a symlink, Getlink returns (zero-value
+ // VirtualDentry, "", EINVAL).
+ Getlink(ctx context.Context) (vfs.VirtualDentry, string, error)
}
diff --git a/pkg/sentry/fsimpl/kernfs/symlink.go b/pkg/sentry/fsimpl/kernfs/symlink.go
index 5918d3309..018aa503c 100755
--- a/pkg/sentry/fsimpl/kernfs/symlink.go
+++ b/pkg/sentry/fsimpl/kernfs/symlink.go
@@ -55,6 +55,11 @@ func (s *StaticSymlink) Readlink(_ context.Context) (string, error) {
return s.target, nil
}
+// Getlink implements Inode.Getlink.
+func (s *StaticSymlink) Getlink(_ context.Context) (vfs.VirtualDentry, string, error) {
+ return vfs.VirtualDentry{}, s.target, nil
+}
+
// SetStat implements Inode.SetStat not allowing inode attributes to be changed.
func (*StaticSymlink) SetStat(context.Context, *vfs.Filesystem, *auth.Credentials, vfs.SetStatOptions) error {
return syserror.EPERM