gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/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 "gvisor.dev/gvisor/pkg/abi/linux" 23 "gvisor.dev/gvisor/pkg/context" 24 "gvisor.dev/gvisor/pkg/errors/linuxerr" 25 "gvisor.dev/gvisor/pkg/sentry/fsimpl/kernfs" 26 "gvisor.dev/gvisor/pkg/sentry/kernel" 27 "gvisor.dev/gvisor/pkg/sentry/kernel/auth" 28 "gvisor.dev/gvisor/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 func (fs *filesystem) StatFSAt(ctx context.Context, rp *vfs.ResolvingPath) (linux.Statfs, error) { 58 d, err := fs.GetDentryAt(ctx, rp, vfs.GetDentryOptions{}) 59 if err != nil { 60 return linux.Statfs{}, err 61 } 62 d.DecRef(ctx) 63 return vfs.GenericStatFS(linux.PROC_SUPER_MAGIC), nil 64 } 65 66 // GetFilesystem implements vfs.FilesystemType.GetFilesystem. 67 func (ft FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.VirtualFilesystem, creds *auth.Credentials, source string, opts vfs.GetFilesystemOptions) (*vfs.Filesystem, *vfs.Dentry, error) { 68 k := kernel.KernelFromContext(ctx) 69 if k == nil { 70 return nil, nil, fmt.Errorf("procfs requires a kernel") 71 } 72 pidns := kernel.PIDNamespaceFromContext(ctx) 73 if pidns == nil { 74 return nil, nil, fmt.Errorf("procfs requires a PID namespace") 75 } 76 devMinor, err := vfsObj.GetAnonBlockDevMinor() 77 if err != nil { 78 return nil, nil, err 79 } 80 81 mopts := vfs.GenericParseMountOptions(opts.Data) 82 maxCachedDentries := defaultMaxCachedDentries 83 if str, ok := mopts["dentry_cache_limit"]; ok { 84 delete(mopts, "dentry_cache_limit") 85 maxCachedDentries, err = strconv.ParseUint(str, 10, 64) 86 if err != nil { 87 ctx.Warningf("proc.FilesystemType.GetFilesystem: invalid dentry cache limit: dentry_cache_limit=%s", str) 88 return nil, nil, linuxerr.EINVAL 89 } 90 } 91 92 procfs := &filesystem{ 93 devMinor: devMinor, 94 } 95 procfs.MaxCachedDentries = maxCachedDentries 96 procfs.VFSFilesystem().Init(vfsObj, &ft, procfs) 97 98 var fakeCgroupControllers map[string]string 99 if opts.InternalData != nil { 100 data := opts.InternalData.(*InternalData) 101 fakeCgroupControllers = data.Cgroups 102 } 103 104 inode := procfs.newTasksInode(ctx, k, pidns, fakeCgroupControllers) 105 var dentry kernfs.Dentry 106 dentry.InitRoot(&procfs.Filesystem, inode) 107 return procfs.VFSFilesystem(), dentry.VFSDentry(), nil 108 } 109 110 // Release implements vfs.FilesystemImpl.Release. 111 func (fs *filesystem) Release(ctx context.Context) { 112 fs.Filesystem.VFSFilesystem().VirtualFilesystem().PutAnonBlockDevMinor(fs.devMinor) 113 fs.Filesystem.Release(ctx) 114 } 115 116 // MountOptions implements vfs.FilesystemImpl.MountOptions. 117 func (fs *filesystem) MountOptions() string { 118 return fmt.Sprintf("dentry_cache_limit=%d", fs.MaxCachedDentries) 119 } 120 121 // dynamicInode is an overfitted interface for common Inodes with 122 // dynamicByteSource types used in procfs. 123 // 124 // +stateify savable 125 type dynamicInode interface { 126 kernfs.Inode 127 vfs.DynamicBytesSource 128 129 Init(ctx context.Context, creds *auth.Credentials, devMajor, devMinor uint32, ino uint64, data vfs.DynamicBytesSource, perm linux.FileMode) 130 } 131 132 func (fs *filesystem) newInode(ctx context.Context, creds *auth.Credentials, perm linux.FileMode, inode dynamicInode) dynamicInode { 133 inode.Init(ctx, creds, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), inode, perm) 134 return inode 135 } 136 137 // +stateify savable 138 type staticFile struct { 139 kernfs.DynamicBytesFile 140 vfs.StaticData 141 } 142 143 var _ dynamicInode = (*staticFile)(nil) 144 145 func newStaticFile(data string) *staticFile { 146 return &staticFile{StaticData: vfs.StaticData{Data: data}} 147 } 148 149 func (fs *filesystem) newStaticDir(ctx context.Context, creds *auth.Credentials, children map[string]kernfs.Inode) kernfs.Inode { 150 return kernfs.NewStaticDir(ctx, creds, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), 0555, children, kernfs.GenericDirectoryFDOptions{ 151 SeekEnd: kernfs.SeekEndZero, 152 }) 153 } 154 155 // InternalData contains internal data passed in to the procfs mount via 156 // vfs.GetFilesystemOptions.InternalData. 157 // 158 // +stateify savable 159 type InternalData struct { 160 Cgroups map[string]string 161 } 162 163 // +stateify savable 164 type implStatFS struct{} 165 166 // StatFS implements kernfs.Inode.StatFS. 167 func (*implStatFS) StatFS(context.Context, *vfs.Filesystem) (linux.Statfs, error) { 168 return vfs.GenericStatFS(linux.PROC_SUPER_MAGIC), nil 169 }