github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/pkg/sentry/fsimpl/nsfs/nsfs.go (about)

     1  // Copyright 2023 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 nsfs provides the filesystem implementation backing
    16  // Kernel.NsfsMount.
    17  package nsfs
    18  
    19  import (
    20  	"fmt"
    21  
    22  	"github.com/metacubex/gvisor/pkg/abi/linux"
    23  	"github.com/metacubex/gvisor/pkg/context"
    24  	"github.com/metacubex/gvisor/pkg/errors/linuxerr"
    25  	"github.com/metacubex/gvisor/pkg/sentry/fsimpl/kernfs"
    26  	"github.com/metacubex/gvisor/pkg/sentry/kernel/auth"
    27  	"github.com/metacubex/gvisor/pkg/sentry/vfs"
    28  )
    29  
    30  // +stateify savable
    31  type filesystemType struct{}
    32  
    33  // Name implements vfs.FilesystemType.Name.
    34  func (filesystemType) Name() string {
    35  	return "nsfs"
    36  }
    37  
    38  // Release implements vfs.FilesystemType.Release.
    39  func (filesystemType) Release(ctx context.Context) {}
    40  
    41  // GetFilesystem implements vfs.FilesystemType.GetFilesystem.
    42  func (filesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.VirtualFilesystem, creds *auth.Credentials, source string, opts vfs.GetFilesystemOptions) (*vfs.Filesystem, *vfs.Dentry, error) {
    43  	panic("nsfs.filesystemType.GetFilesystem should never be called")
    44  }
    45  
    46  // +stateify savable
    47  type filesystem struct {
    48  	kernfs.Filesystem
    49  
    50  	devMinor uint32
    51  }
    52  
    53  // NewFilesystem sets up and returns a new vfs.Filesystem implemented by nsfs.
    54  func NewFilesystem(vfsObj *vfs.VirtualFilesystem) (*vfs.Filesystem, error) {
    55  	devMinor, err := vfsObj.GetAnonBlockDevMinor()
    56  	if err != nil {
    57  		return nil, err
    58  	}
    59  	fs := &filesystem{
    60  		devMinor: devMinor,
    61  	}
    62  	fs.Filesystem.VFSFilesystem().Init(vfsObj, filesystemType{}, fs)
    63  	return fs.Filesystem.VFSFilesystem(), nil
    64  }
    65  
    66  // Release implements vfs.FilesystemImpl.Release.
    67  func (fs *filesystem) Release(ctx context.Context) {
    68  	fs.Filesystem.VFSFilesystem().VirtualFilesystem().PutAnonBlockDevMinor(fs.devMinor)
    69  	fs.Filesystem.Release(ctx)
    70  }
    71  
    72  // MountOptions implements vfs.FilesystemImpl.MountOptions.
    73  func (fs *filesystem) MountOptions() string {
    74  	return ""
    75  }
    76  
    77  // Inode implements kernfs.Inode.
    78  //
    79  // +stateify savable
    80  type Inode struct {
    81  	kernfs.InodeAttrs
    82  	kernfs.InodeAnonymous
    83  	kernfs.InodeNotDirectory
    84  	kernfs.InodeNotSymlink
    85  	kernfs.InodeWatches
    86  	inodeRefs
    87  
    88  	locks     vfs.FileLocks
    89  	namespace vfs.Namespace
    90  
    91  	mnt *vfs.Mount
    92  }
    93  
    94  // DecRef implements kernfs.Inode.DecRef.
    95  func (i *Inode) DecRef(ctx context.Context) {
    96  	i.inodeRefs.DecRef(func() { i.namespace.Destroy(ctx) })
    97  }
    98  
    99  // Keep implements kernfs.Inode.Keep.
   100  func (i *Inode) Keep() bool {
   101  	return false
   102  }
   103  
   104  // NewInode creates a new nsfs inode.
   105  func NewInode(ctx context.Context, mnt *vfs.Mount, namespace vfs.Namespace) *Inode {
   106  	fs := mnt.Filesystem().Impl().(*filesystem)
   107  	creds := auth.CredentialsFromContext(ctx)
   108  	i := &Inode{
   109  		namespace: namespace,
   110  		mnt:       mnt,
   111  	}
   112  	i.InodeAttrs.Init(ctx, creds, linux.UNNAMED_MAJOR, fs.devMinor, fs.Filesystem.NextIno(), nsfsMode)
   113  	i.InitRefs()
   114  	return i
   115  }
   116  
   117  const nsfsMode = linux.S_IFREG | linux.ModeUserRead | linux.ModeGroupRead | linux.ModeOtherRead
   118  
   119  // Namespace returns the namespace associated with the inode.
   120  func (i *Inode) Namespace() vfs.Namespace {
   121  	return i.namespace
   122  }
   123  
   124  // Name returns the inode name that is used to implement readlink() of
   125  // /proc/pid/ns/ files.
   126  func (i *Inode) Name() string {
   127  	return fmt.Sprintf("%s:[%d]", i.namespace.Type(), i.Ino())
   128  }
   129  
   130  // VirtualDentry returns VirtualDentry for the inode.
   131  func (i *Inode) VirtualDentry() vfs.VirtualDentry {
   132  	dentry := &kernfs.Dentry{}
   133  	mnt := i.mnt
   134  	fs := mnt.Filesystem().Impl().(*filesystem)
   135  	i.IncRef()
   136  	mnt.IncRef()
   137  	dentry.Init(&fs.Filesystem, i)
   138  	vd := vfs.MakeVirtualDentry(mnt, dentry.VFSDentry())
   139  	return vd
   140  }
   141  
   142  // Mode implements kernfs.Inode.Mode.
   143  func (i *Inode) Mode() linux.FileMode {
   144  	return nsfsMode
   145  }
   146  
   147  // SetStat implements kernfs.Inode.SetStat.
   148  //
   149  // Linux sets S_IMMUTABLE to nsfs inodes that prevents any attribute changes on
   150  // them.
   151  func (i *Inode) SetStat(ctx context.Context, vfsfs *vfs.Filesystem, creds *auth.Credentials, opts vfs.SetStatOptions) error {
   152  	return linuxerr.EPERM
   153  }
   154  
   155  // namespace FD is a synthetic file that represents a namespace in
   156  // /proc/[pid]/ns/*.
   157  //
   158  // +stateify savable
   159  type namespaceFD struct {
   160  	vfs.FileDescriptionDefaultImpl
   161  	vfs.LockFD
   162  
   163  	vfsfd vfs.FileDescription
   164  	inode *Inode
   165  }
   166  
   167  // Stat implements vfs.FileDescriptionImpl.Stat.
   168  func (fd *namespaceFD) Stat(ctx context.Context, opts vfs.StatOptions) (linux.Statx, error) {
   169  	vfs := fd.vfsfd.VirtualDentry().Mount().Filesystem()
   170  	return fd.inode.Stat(ctx, vfs, opts)
   171  }
   172  
   173  // SetStat implements vfs.FileDescriptionImpl.SetStat.
   174  func (fd *namespaceFD) SetStat(ctx context.Context, opts vfs.SetStatOptions) error {
   175  	vfs := fd.vfsfd.VirtualDentry().Mount().Filesystem()
   176  	creds := auth.CredentialsFromContext(ctx)
   177  	return fd.inode.SetStat(ctx, vfs, creds, opts)
   178  }
   179  
   180  // Release implements vfs.FileDescriptionImpl.Release.
   181  func (fd *namespaceFD) Release(ctx context.Context) {
   182  	fd.inode.DecRef(ctx)
   183  }
   184  
   185  // Open implements kernfs.Inode.Open.
   186  func (i *Inode) Open(ctx context.Context, rp *vfs.ResolvingPath, d *kernfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
   187  	fd := &namespaceFD{inode: i}
   188  	i.IncRef()
   189  	fd.LockFD.Init(&i.locks)
   190  	if err := fd.vfsfd.Init(fd, opts.Flags, rp.Mount(), d.VFSDentry(), &vfs.FileDescriptionOptions{}); err != nil {
   191  		return nil, err
   192  	}
   193  	return &fd.vfsfd, nil
   194  }
   195  
   196  // StatFS implements kernfs.Inode.StatFS.
   197  func (i *Inode) StatFS(ctx context.Context, fs *vfs.Filesystem) (linux.Statfs, error) {
   198  	return vfs.GenericStatFS(linux.NSFS_MAGIC), nil
   199  }