github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/sentry/fsimpl/proc/filesystem.go (about)

     1  // Copyright 2019 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 proc implements a partial in-memory file system for procfs.
    16  package proc
    17  
    18  import (
    19  	"fmt"
    20  	"strconv"
    21  
    22  	"github.com/nicocha30/gvisor-ligolo/pkg/abi/linux"
    23  	"github.com/nicocha30/gvisor-ligolo/pkg/context"
    24  	"github.com/nicocha30/gvisor-ligolo/pkg/errors/linuxerr"
    25  	"github.com/nicocha30/gvisor-ligolo/pkg/sentry/fsimpl/kernfs"
    26  	"github.com/nicocha30/gvisor-ligolo/pkg/sentry/kernel"
    27  	"github.com/nicocha30/gvisor-ligolo/pkg/sentry/kernel/auth"
    28  	"github.com/nicocha30/gvisor-ligolo/pkg/sentry/vfs"
    29  )
    30  
    31  const (
    32  	// Name is the default filesystem name.
    33  	Name                     = "proc"
    34  	defaultMaxCachedDentries = uint64(1000)
    35  )
    36  
    37  // FilesystemType is the factory class for procfs.
    38  //
    39  // +stateify savable
    40  type FilesystemType struct{}
    41  
    42  // Name implements vfs.FilesystemType.Name.
    43  func (FilesystemType) Name() string {
    44  	return Name
    45  }
    46  
    47  // Release implements vfs.FilesystemType.Release.
    48  func (FilesystemType) Release(ctx context.Context) {}
    49  
    50  // +stateify savable
    51  type filesystem struct {
    52  	kernfs.Filesystem
    53  
    54  	devMinor uint32
    55  }
    56  
    57  // GetFilesystem implements vfs.FilesystemType.GetFilesystem.
    58  func (ft FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.VirtualFilesystem, creds *auth.Credentials, source string, opts vfs.GetFilesystemOptions) (*vfs.Filesystem, *vfs.Dentry, error) {
    59  	k := kernel.KernelFromContext(ctx)
    60  	if k == nil {
    61  		return nil, nil, fmt.Errorf("procfs requires a kernel")
    62  	}
    63  	pidns := kernel.PIDNamespaceFromContext(ctx)
    64  	if pidns == nil {
    65  		return nil, nil, fmt.Errorf("procfs requires a PID namespace")
    66  	}
    67  	devMinor, err := vfsObj.GetAnonBlockDevMinor()
    68  	if err != nil {
    69  		return nil, nil, err
    70  	}
    71  
    72  	mopts := vfs.GenericParseMountOptions(opts.Data)
    73  	maxCachedDentries := defaultMaxCachedDentries
    74  	if str, ok := mopts["dentry_cache_limit"]; ok {
    75  		delete(mopts, "dentry_cache_limit")
    76  		maxCachedDentries, err = strconv.ParseUint(str, 10, 64)
    77  		if err != nil {
    78  			ctx.Warningf("proc.FilesystemType.GetFilesystem: invalid dentry cache limit: dentry_cache_limit=%s", str)
    79  			return nil, nil, linuxerr.EINVAL
    80  		}
    81  	}
    82  
    83  	procfs := &filesystem{
    84  		devMinor: devMinor,
    85  	}
    86  	procfs.MaxCachedDentries = maxCachedDentries
    87  	procfs.VFSFilesystem().Init(vfsObj, &ft, procfs)
    88  
    89  	var fakeCgroupControllers map[string]string
    90  	if opts.InternalData != nil {
    91  		data := opts.InternalData.(*InternalData)
    92  		fakeCgroupControllers = data.Cgroups
    93  	}
    94  
    95  	inode := procfs.newTasksInode(ctx, k, pidns, fakeCgroupControllers)
    96  	var dentry kernfs.Dentry
    97  	dentry.InitRoot(&procfs.Filesystem, inode)
    98  	return procfs.VFSFilesystem(), dentry.VFSDentry(), nil
    99  }
   100  
   101  // Release implements vfs.FilesystemImpl.Release.
   102  func (fs *filesystem) Release(ctx context.Context) {
   103  	fs.Filesystem.VFSFilesystem().VirtualFilesystem().PutAnonBlockDevMinor(fs.devMinor)
   104  	fs.Filesystem.Release(ctx)
   105  }
   106  
   107  // MountOptions implements vfs.FilesystemImpl.MountOptions.
   108  func (fs *filesystem) MountOptions() string {
   109  	return fmt.Sprintf("dentry_cache_limit=%d", fs.MaxCachedDentries)
   110  }
   111  
   112  // dynamicInode is an overfitted interface for common Inodes with
   113  // dynamicByteSource types used in procfs.
   114  //
   115  // +stateify savable
   116  type dynamicInode interface {
   117  	kernfs.Inode
   118  	vfs.DynamicBytesSource
   119  
   120  	Init(ctx context.Context, creds *auth.Credentials, devMajor, devMinor uint32, ino uint64, data vfs.DynamicBytesSource, perm linux.FileMode)
   121  }
   122  
   123  func (fs *filesystem) newInode(ctx context.Context, creds *auth.Credentials, perm linux.FileMode, inode dynamicInode) dynamicInode {
   124  	inode.Init(ctx, creds, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), inode, perm)
   125  	return inode
   126  }
   127  
   128  // +stateify savable
   129  type staticFile struct {
   130  	kernfs.DynamicBytesFile
   131  	vfs.StaticData
   132  }
   133  
   134  var _ dynamicInode = (*staticFile)(nil)
   135  
   136  func newStaticFile(data string) *staticFile {
   137  	return &staticFile{StaticData: vfs.StaticData{Data: data}}
   138  }
   139  
   140  func (fs *filesystem) newStaticDir(ctx context.Context, creds *auth.Credentials, children map[string]kernfs.Inode) kernfs.Inode {
   141  	return kernfs.NewStaticDir(ctx, creds, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), 0555, children, kernfs.GenericDirectoryFDOptions{
   142  		SeekEnd: kernfs.SeekEndZero,
   143  	})
   144  }
   145  
   146  // InternalData contains internal data passed in to the procfs mount via
   147  // vfs.GetFilesystemOptions.InternalData.
   148  //
   149  // +stateify savable
   150  type InternalData struct {
   151  	Cgroups map[string]string
   152  }
   153  
   154  // +stateify savable
   155  type implStatFS struct{}
   156  
   157  // StatFS implements kernfs.Inode.StatFS.
   158  func (*implStatFS) StatFS(context.Context, *vfs.Filesystem) (linux.Statfs, error) {
   159  	return vfs.GenericStatFS(linux.PROC_SUPER_MAGIC), nil
   160  }