github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/vfs/anonfs.go (about)

     1  // Copyright 2020 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package vfs
    16  
    17  import (
    18  	"fmt"
    19  
    20  	"github.com/SagerNet/gvisor/pkg/abi/linux"
    21  	"github.com/SagerNet/gvisor/pkg/context"
    22  	"github.com/SagerNet/gvisor/pkg/errors/linuxerr"
    23  	"github.com/SagerNet/gvisor/pkg/fspath"
    24  	"github.com/SagerNet/gvisor/pkg/hostarch"
    25  	"github.com/SagerNet/gvisor/pkg/sentry/kernel/auth"
    26  	"github.com/SagerNet/gvisor/pkg/sentry/socket/unix/transport"
    27  	"github.com/SagerNet/gvisor/pkg/syserror"
    28  )
    29  
    30  // NewAnonVirtualDentry returns a VirtualDentry with the given synthetic name,
    31  // consistent with Linux's fs/anon_inodes.c:anon_inode_getfile(). References
    32  // are taken on the returned VirtualDentry.
    33  func (vfs *VirtualFilesystem) NewAnonVirtualDentry(name string) VirtualDentry {
    34  	d := anonDentry{
    35  		name: name,
    36  	}
    37  	d.vfsd.Init(&d)
    38  	vfs.anonMount.IncRef()
    39  	// anonDentry no-ops refcounting.
    40  	return VirtualDentry{
    41  		mount:  vfs.anonMount,
    42  		dentry: &d.vfsd,
    43  	}
    44  }
    45  
    46  const (
    47  	anonfsBlockSize = hostarch.PageSize // via fs/libfs.c:pseudo_fs_fill_super()
    48  
    49  	// Mode, UID, and GID for a generic anonfs file.
    50  	anonFileMode = 0600 // no type is correct
    51  	anonFileUID  = auth.RootKUID
    52  	anonFileGID  = auth.RootKGID
    53  )
    54  
    55  // anonFilesystemType implements FilesystemType.
    56  //
    57  // +stateify savable
    58  type anonFilesystemType struct{}
    59  
    60  // GetFilesystem implements FilesystemType.GetFilesystem.
    61  func (anonFilesystemType) GetFilesystem(context.Context, *VirtualFilesystem, *auth.Credentials, string, GetFilesystemOptions) (*Filesystem, *Dentry, error) {
    62  	panic("cannot instaniate an anon filesystem")
    63  }
    64  
    65  // Name implements FilesystemType.Name.
    66  func (anonFilesystemType) Name() string {
    67  	return "none"
    68  }
    69  
    70  // Release implemenents FilesystemType.Release.
    71  func (anonFilesystemType) Release(ctx context.Context) {}
    72  
    73  // anonFilesystem is the implementation of FilesystemImpl that backs
    74  // VirtualDentries returned by VirtualFilesystem.NewAnonVirtualDentry().
    75  //
    76  // Since all Dentries in anonFilesystem are non-directories, all FilesystemImpl
    77  // methods that would require an anonDentry to be a directory return ENOTDIR.
    78  //
    79  // +stateify savable
    80  type anonFilesystem struct {
    81  	vfsfs Filesystem
    82  
    83  	devMinor uint32
    84  }
    85  
    86  // +stateify savable
    87  type anonDentry struct {
    88  	vfsd Dentry
    89  
    90  	name string
    91  }
    92  
    93  // Release implements FilesystemImpl.Release.
    94  func (fs *anonFilesystem) Release(ctx context.Context) {
    95  }
    96  
    97  // Sync implements FilesystemImpl.Sync.
    98  func (fs *anonFilesystem) Sync(ctx context.Context) error {
    99  	return nil
   100  }
   101  
   102  // AccessAt implements vfs.Filesystem.Impl.AccessAt.
   103  func (fs *anonFilesystem) AccessAt(ctx context.Context, rp *ResolvingPath, creds *auth.Credentials, ats AccessTypes) error {
   104  	if !rp.Done() {
   105  		return syserror.ENOTDIR
   106  	}
   107  	return GenericCheckPermissions(creds, ats, anonFileMode, anonFileUID, anonFileGID)
   108  }
   109  
   110  // GetDentryAt implements FilesystemImpl.GetDentryAt.
   111  func (fs *anonFilesystem) GetDentryAt(ctx context.Context, rp *ResolvingPath, opts GetDentryOptions) (*Dentry, error) {
   112  	if !rp.Done() {
   113  		return nil, syserror.ENOTDIR
   114  	}
   115  	if opts.CheckSearchable {
   116  		return nil, syserror.ENOTDIR
   117  	}
   118  	// anonDentry no-ops refcounting.
   119  	return rp.Start(), nil
   120  }
   121  
   122  // GetParentDentryAt implements FilesystemImpl.GetParentDentryAt.
   123  func (fs *anonFilesystem) GetParentDentryAt(ctx context.Context, rp *ResolvingPath) (*Dentry, error) {
   124  	if !rp.Final() {
   125  		return nil, syserror.ENOTDIR
   126  	}
   127  	// anonDentry no-ops refcounting.
   128  	return rp.Start(), nil
   129  }
   130  
   131  // LinkAt implements FilesystemImpl.LinkAt.
   132  func (fs *anonFilesystem) LinkAt(ctx context.Context, rp *ResolvingPath, vd VirtualDentry) error {
   133  	if !rp.Final() {
   134  		return syserror.ENOTDIR
   135  	}
   136  	return linuxerr.EPERM
   137  }
   138  
   139  // MkdirAt implements FilesystemImpl.MkdirAt.
   140  func (fs *anonFilesystem) MkdirAt(ctx context.Context, rp *ResolvingPath, opts MkdirOptions) error {
   141  	if !rp.Final() {
   142  		return syserror.ENOTDIR
   143  	}
   144  	return linuxerr.EPERM
   145  }
   146  
   147  // MknodAt implements FilesystemImpl.MknodAt.
   148  func (fs *anonFilesystem) MknodAt(ctx context.Context, rp *ResolvingPath, opts MknodOptions) error {
   149  	if !rp.Final() {
   150  		return syserror.ENOTDIR
   151  	}
   152  	return linuxerr.EPERM
   153  }
   154  
   155  // OpenAt implements FilesystemImpl.OpenAt.
   156  func (fs *anonFilesystem) OpenAt(ctx context.Context, rp *ResolvingPath, opts OpenOptions) (*FileDescription, error) {
   157  	if !rp.Done() {
   158  		return nil, syserror.ENOTDIR
   159  	}
   160  	return nil, linuxerr.ENODEV
   161  }
   162  
   163  // ReadlinkAt implements FilesystemImpl.ReadlinkAt.
   164  func (fs *anonFilesystem) ReadlinkAt(ctx context.Context, rp *ResolvingPath) (string, error) {
   165  	if !rp.Done() {
   166  		return "", syserror.ENOTDIR
   167  	}
   168  	return "", linuxerr.EINVAL
   169  }
   170  
   171  // RenameAt implements FilesystemImpl.RenameAt.
   172  func (fs *anonFilesystem) RenameAt(ctx context.Context, rp *ResolvingPath, oldParentVD VirtualDentry, oldName string, opts RenameOptions) error {
   173  	if !rp.Final() {
   174  		return syserror.ENOTDIR
   175  	}
   176  	return linuxerr.EPERM
   177  }
   178  
   179  // RmdirAt implements FilesystemImpl.RmdirAt.
   180  func (fs *anonFilesystem) RmdirAt(ctx context.Context, rp *ResolvingPath) error {
   181  	if !rp.Final() {
   182  		return syserror.ENOTDIR
   183  	}
   184  	return linuxerr.EPERM
   185  }
   186  
   187  // SetStatAt implements FilesystemImpl.SetStatAt.
   188  func (fs *anonFilesystem) SetStatAt(ctx context.Context, rp *ResolvingPath, opts SetStatOptions) error {
   189  	if !rp.Done() {
   190  		return syserror.ENOTDIR
   191  	}
   192  	// Linux actually permits anon_inode_inode's metadata to be set, which is
   193  	// visible to all users of anon_inode_inode. We just silently ignore
   194  	// metadata changes.
   195  	return nil
   196  }
   197  
   198  // StatAt implements FilesystemImpl.StatAt.
   199  func (fs *anonFilesystem) StatAt(ctx context.Context, rp *ResolvingPath, opts StatOptions) (linux.Statx, error) {
   200  	if !rp.Done() {
   201  		return linux.Statx{}, syserror.ENOTDIR
   202  	}
   203  	// See fs/anon_inodes.c:anon_inode_init() => fs/libfs.c:alloc_anon_inode().
   204  	return linux.Statx{
   205  		Mask:     linux.STATX_TYPE | linux.STATX_MODE | linux.STATX_NLINK | linux.STATX_UID | linux.STATX_GID | linux.STATX_INO | linux.STATX_SIZE | linux.STATX_BLOCKS,
   206  		Blksize:  anonfsBlockSize,
   207  		Nlink:    1,
   208  		UID:      uint32(anonFileUID),
   209  		GID:      uint32(anonFileGID),
   210  		Mode:     anonFileMode,
   211  		Ino:      1,
   212  		Size:     0,
   213  		Blocks:   0,
   214  		DevMajor: linux.UNNAMED_MAJOR,
   215  		DevMinor: fs.devMinor,
   216  	}, nil
   217  }
   218  
   219  // StatFSAt implements FilesystemImpl.StatFSAt.
   220  func (fs *anonFilesystem) StatFSAt(ctx context.Context, rp *ResolvingPath) (linux.Statfs, error) {
   221  	if !rp.Done() {
   222  		return linux.Statfs{}, syserror.ENOTDIR
   223  	}
   224  	return linux.Statfs{
   225  		Type:      linux.ANON_INODE_FS_MAGIC,
   226  		BlockSize: anonfsBlockSize,
   227  	}, nil
   228  }
   229  
   230  // SymlinkAt implements FilesystemImpl.SymlinkAt.
   231  func (fs *anonFilesystem) SymlinkAt(ctx context.Context, rp *ResolvingPath, target string) error {
   232  	if !rp.Final() {
   233  		return syserror.ENOTDIR
   234  	}
   235  	return linuxerr.EPERM
   236  }
   237  
   238  // UnlinkAt implements FilesystemImpl.UnlinkAt.
   239  func (fs *anonFilesystem) UnlinkAt(ctx context.Context, rp *ResolvingPath) error {
   240  	if !rp.Final() {
   241  		return syserror.ENOTDIR
   242  	}
   243  	return linuxerr.EPERM
   244  }
   245  
   246  // BoundEndpointAt implements FilesystemImpl.BoundEndpointAt.
   247  func (fs *anonFilesystem) BoundEndpointAt(ctx context.Context, rp *ResolvingPath, opts BoundEndpointOptions) (transport.BoundEndpoint, error) {
   248  	if !rp.Final() {
   249  		return nil, syserror.ENOTDIR
   250  	}
   251  	if err := GenericCheckPermissions(rp.Credentials(), MayWrite, anonFileMode, anonFileUID, anonFileGID); err != nil {
   252  		return nil, err
   253  	}
   254  	return nil, linuxerr.ECONNREFUSED
   255  }
   256  
   257  // ListXattrAt implements FilesystemImpl.ListXattrAt.
   258  func (fs *anonFilesystem) ListXattrAt(ctx context.Context, rp *ResolvingPath, size uint64) ([]string, error) {
   259  	if !rp.Done() {
   260  		return nil, syserror.ENOTDIR
   261  	}
   262  	return nil, nil
   263  }
   264  
   265  // GetXattrAt implements FilesystemImpl.GetXattrAt.
   266  func (fs *anonFilesystem) GetXattrAt(ctx context.Context, rp *ResolvingPath, opts GetXattrOptions) (string, error) {
   267  	if !rp.Done() {
   268  		return "", syserror.ENOTDIR
   269  	}
   270  	return "", linuxerr.ENOTSUP
   271  }
   272  
   273  // SetXattrAt implements FilesystemImpl.SetXattrAt.
   274  func (fs *anonFilesystem) SetXattrAt(ctx context.Context, rp *ResolvingPath, opts SetXattrOptions) error {
   275  	if !rp.Done() {
   276  		return syserror.ENOTDIR
   277  	}
   278  	return linuxerr.EPERM
   279  }
   280  
   281  // RemoveXattrAt implements FilesystemImpl.RemoveXattrAt.
   282  func (fs *anonFilesystem) RemoveXattrAt(ctx context.Context, rp *ResolvingPath, name string) error {
   283  	if !rp.Done() {
   284  		return syserror.ENOTDIR
   285  	}
   286  	return linuxerr.EPERM
   287  }
   288  
   289  // PrependPath implements FilesystemImpl.PrependPath.
   290  func (fs *anonFilesystem) PrependPath(ctx context.Context, vfsroot, vd VirtualDentry, b *fspath.Builder) error {
   291  	b.PrependComponent(fmt.Sprintf("anon_inode:%s", vd.dentry.impl.(*anonDentry).name))
   292  	return PrependPathSyntheticError{}
   293  }
   294  
   295  // MountOptions implements FilesystemImpl.MountOptions.
   296  func (fs *anonFilesystem) MountOptions() string {
   297  	return ""
   298  }
   299  
   300  // IncRef implements DentryImpl.IncRef.
   301  func (d *anonDentry) IncRef() {
   302  	// no-op
   303  }
   304  
   305  // TryIncRef implements DentryImpl.TryIncRef.
   306  func (d *anonDentry) TryIncRef() bool {
   307  	return true
   308  }
   309  
   310  // DecRef implements DentryImpl.DecRef.
   311  func (d *anonDentry) DecRef(ctx context.Context) {
   312  	// no-op
   313  }
   314  
   315  // InotifyWithParent implements DentryImpl.InotifyWithParent.
   316  //
   317  // Although Linux technically supports inotify on pseudo filesystems (inotify
   318  // is implemented at the vfs layer), it is not particularly useful. It is left
   319  // unimplemented until someone actually needs it.
   320  func (d *anonDentry) InotifyWithParent(ctx context.Context, events, cookie uint32, et EventType) {}
   321  
   322  // Watches implements DentryImpl.Watches.
   323  func (d *anonDentry) Watches() *Watches {
   324  	return nil
   325  }
   326  
   327  // OnZeroWatches implements Dentry.OnZeroWatches.
   328  func (d *anonDentry) OnZeroWatches(context.Context) {}