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 }