github.com/ttpreport/gvisor-ligolo@v0.0.0-20240123134145-a858404967ba/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/ttpreport/gvisor-ligolo/pkg/abi/linux"
    23  	"github.com/ttpreport/gvisor-ligolo/pkg/context"
    24  	"github.com/ttpreport/gvisor-ligolo/pkg/errors/linuxerr"
    25  	"github.com/ttpreport/gvisor-ligolo/pkg/sentry/fsimpl/kernfs"
    26  	"github.com/ttpreport/gvisor-ligolo/pkg/sentry/kernel/auth"
    27  	"github.com/ttpreport/gvisor-ligolo/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.InodeNotAnonymous
    83  	kernfs.InodeNotDirectory
    84  	kernfs.InodeNotSymlink
    85  	kernfs.InodeWatches
    86  	inodeRefs
    87  
    88  	locks     vfs.FileLocks
    89  	namespace 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  // Namespace is the namespace interface.
   105  type Namespace interface {
   106  	Type() string
   107  	Destroy(ctx context.Context)
   108  }
   109  
   110  // NewInode creates a new nsfs inode.
   111  func NewInode(ctx context.Context, mnt *vfs.Mount, namespace Namespace) *Inode {
   112  	fs := mnt.Filesystem().Impl().(*filesystem)
   113  	creds := auth.CredentialsFromContext(ctx)
   114  	i := &Inode{
   115  		namespace: namespace,
   116  		mnt:       mnt,
   117  	}
   118  	i.InodeAttrs.Init(ctx, creds, linux.UNNAMED_MAJOR, fs.devMinor, fs.Filesystem.NextIno(), nsfsMode)
   119  	i.InitRefs()
   120  	return i
   121  }
   122  
   123  const nsfsMode = linux.S_IFREG | linux.ModeUserRead | linux.ModeGroupRead | linux.ModeOtherRead
   124  
   125  // Namespace returns the namespace associated with the inode.
   126  func (i *Inode) Namespace() Namespace {
   127  	return i.namespace
   128  }
   129  
   130  // Name returns the inode name that is used to implement readlink() of
   131  // /proc/pid/ns/ files.
   132  func (i *Inode) Name() string {
   133  	return fmt.Sprintf("%s:[%d]", i.namespace.Type(), i.Ino())
   134  }
   135  
   136  // VirtualDentry returns VirtualDentry for the inode.
   137  func (i *Inode) VirtualDentry() vfs.VirtualDentry {
   138  	dentry := &kernfs.Dentry{}
   139  	mnt := i.mnt
   140  	fs := mnt.Filesystem().Impl().(*filesystem)
   141  	i.IncRef()
   142  	mnt.IncRef()
   143  	dentry.Init(&fs.Filesystem, i)
   144  	vd := vfs.MakeVirtualDentry(mnt, dentry.VFSDentry())
   145  	return vd
   146  }
   147  
   148  // Mode implements kernfs.Inode.Mode.
   149  func (i *Inode) Mode() linux.FileMode {
   150  	return nsfsMode
   151  }
   152  
   153  // SetStat implements kernfs.Inode.SetStat.
   154  //
   155  // Linux sets S_IMMUTABLE to nsfs inodes that prevents any attribute changes on
   156  // them.
   157  func (i *Inode) SetStat(ctx context.Context, vfsfs *vfs.Filesystem, creds *auth.Credentials, opts vfs.SetStatOptions) error {
   158  	return linuxerr.EPERM
   159  }
   160  
   161  // namespace FD is a synthetic file that represents a namespace in
   162  // /proc/[pid]/ns/*.
   163  //
   164  // +stateify savable
   165  type namespaceFD struct {
   166  	vfs.FileDescriptionDefaultImpl
   167  	vfs.LockFD
   168  
   169  	vfsfd vfs.FileDescription
   170  	inode *Inode
   171  }
   172  
   173  // Stat implements vfs.FileDescriptionImpl.Stat.
   174  func (fd *namespaceFD) Stat(ctx context.Context, opts vfs.StatOptions) (linux.Statx, error) {
   175  	vfs := fd.vfsfd.VirtualDentry().Mount().Filesystem()
   176  	return fd.inode.Stat(ctx, vfs, opts)
   177  }
   178  
   179  // SetStat implements vfs.FileDescriptionImpl.SetStat.
   180  func (fd *namespaceFD) SetStat(ctx context.Context, opts vfs.SetStatOptions) error {
   181  	vfs := fd.vfsfd.VirtualDentry().Mount().Filesystem()
   182  	creds := auth.CredentialsFromContext(ctx)
   183  	return fd.inode.SetStat(ctx, vfs, creds, opts)
   184  }
   185  
   186  // Release implements vfs.FileDescriptionImpl.Release.
   187  func (fd *namespaceFD) Release(ctx context.Context) {
   188  	fd.inode.DecRef(ctx)
   189  }
   190  
   191  // Open implements kernfs.Inode.Open.
   192  func (i *Inode) Open(ctx context.Context, rp *vfs.ResolvingPath, d *kernfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
   193  	fd := &namespaceFD{inode: i}
   194  	i.IncRef()
   195  	fd.LockFD.Init(&i.locks)
   196  	if err := fd.vfsfd.Init(fd, opts.Flags, rp.Mount(), d.VFSDentry(), &vfs.FileDescriptionOptions{}); err != nil {
   197  		return nil, err
   198  	}
   199  	return &fd.vfsfd, nil
   200  }
   201  
   202  // StatFS implements kernfs.Inode.StatFS.
   203  func (i *Inode) StatFS(ctx context.Context, fs *vfs.Filesystem) (linux.Statfs, error) {
   204  	return vfs.GenericStatFS(linux.NSFS_MAGIC), nil
   205  }