github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/sentry/fsimpl/pipefs/pipefs.go (about) 1 // Copyright 2020 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 pipefs provides the filesystem implementation backing 16 // Kernel.PipeMount. 17 package pipefs 18 19 import ( 20 "fmt" 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/fspath" 26 "github.com/nicocha30/gvisor-ligolo/pkg/hostarch" 27 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/fsimpl/kernfs" 28 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/kernel/auth" 29 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/kernel/pipe" 30 ktime "github.com/nicocha30/gvisor-ligolo/pkg/sentry/kernel/time" 31 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/vfs" 32 "github.com/nicocha30/gvisor-ligolo/pkg/sync" 33 ) 34 35 // +stateify savable 36 type filesystemType struct{} 37 38 // Name implements vfs.FilesystemType.Name. 39 func (filesystemType) Name() string { 40 return "pipefs" 41 } 42 43 // Release implements vfs.FilesystemType.Release. 44 func (filesystemType) Release(ctx context.Context) {} 45 46 // GetFilesystem implements vfs.FilesystemType.GetFilesystem. 47 func (filesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.VirtualFilesystem, creds *auth.Credentials, source string, opts vfs.GetFilesystemOptions) (*vfs.Filesystem, *vfs.Dentry, error) { 48 panic("pipefs.filesystemType.GetFilesystem should never be called") 49 } 50 51 // +stateify savable 52 type filesystem struct { 53 kernfs.Filesystem 54 55 devMinor uint32 56 } 57 58 // NewFilesystem sets up and returns a new vfs.Filesystem implemented by pipefs. 59 func NewFilesystem(vfsObj *vfs.VirtualFilesystem) (*vfs.Filesystem, error) { 60 devMinor, err := vfsObj.GetAnonBlockDevMinor() 61 if err != nil { 62 return nil, err 63 } 64 fs := &filesystem{ 65 devMinor: devMinor, 66 } 67 fs.Filesystem.VFSFilesystem().Init(vfsObj, filesystemType{}, fs) 68 return fs.Filesystem.VFSFilesystem(), nil 69 } 70 71 // Release implements vfs.FilesystemImpl.Release. 72 func (fs *filesystem) Release(ctx context.Context) { 73 fs.Filesystem.VFSFilesystem().VirtualFilesystem().PutAnonBlockDevMinor(fs.devMinor) 74 fs.Filesystem.Release(ctx) 75 } 76 77 // PrependPath implements vfs.FilesystemImpl.PrependPath. 78 func (fs *filesystem) PrependPath(ctx context.Context, vfsroot, vd vfs.VirtualDentry, b *fspath.Builder) error { 79 inode := vd.Dentry().Impl().(*kernfs.Dentry).Inode().(*inode) 80 b.PrependComponent(fmt.Sprintf("pipe:[%d]", inode.ino)) 81 return vfs.PrependPathSyntheticError{} 82 } 83 84 // MountOptions implements vfs.FilesystemImpl.MountOptions. 85 func (fs *filesystem) MountOptions() string { 86 return "" 87 } 88 89 // inode implements kernfs.Inode. 90 // 91 // +stateify savable 92 type inode struct { 93 kernfs.InodeAnonymous 94 kernfs.InodeNotDirectory 95 kernfs.InodeNotSymlink 96 kernfs.InodeNoopRefCount 97 kernfs.InodeWatches 98 99 locks vfs.FileLocks 100 pipe *pipe.VFSPipe 101 attrMu sync.Mutex `state:"nosave"` 102 103 ino uint64 104 uid auth.KUID 105 gid auth.KGID 106 // We use the creation timestamp for all of atime, mtime, and ctime. 107 ctime ktime.Time 108 } 109 110 func newInode(ctx context.Context, fs *filesystem) *inode { 111 creds := auth.CredentialsFromContext(ctx) 112 return &inode{ 113 pipe: pipe.NewVFSPipe(false /* isNamed */, pipe.DefaultPipeSize), 114 ino: fs.Filesystem.NextIno(), 115 uid: creds.EffectiveKUID, 116 gid: creds.EffectiveKGID, 117 ctime: ktime.NowFromContext(ctx), 118 } 119 } 120 121 const pipeMode = 0600 | linux.S_IFIFO 122 123 // CheckPermissions implements kernfs.Inode.CheckPermissions. 124 func (i *inode) CheckPermissions(ctx context.Context, creds *auth.Credentials, ats vfs.AccessTypes) error { 125 i.attrMu.Lock() 126 defer i.attrMu.Unlock() 127 return vfs.GenericCheckPermissions(creds, ats, pipeMode, i.uid, i.gid) 128 } 129 130 // Mode implements kernfs.Inode.Mode. 131 func (i *inode) Mode() linux.FileMode { 132 return pipeMode 133 } 134 135 // UID implements kernfs.Inode.UID. 136 func (i *inode) UID() auth.KUID { 137 i.attrMu.Lock() 138 defer i.attrMu.Unlock() 139 return auth.KUID(i.uid) 140 } 141 142 // GID implements kernfs.Inode.GID. 143 func (i *inode) GID() auth.KGID { 144 i.attrMu.Lock() 145 defer i.attrMu.Unlock() 146 return auth.KGID(i.gid) 147 } 148 149 // Stat implements kernfs.Inode.Stat. 150 func (i *inode) Stat(_ context.Context, vfsfs *vfs.Filesystem, opts vfs.StatOptions) (linux.Statx, error) { 151 ts := linux.NsecToStatxTimestamp(i.ctime.Nanoseconds()) 152 i.attrMu.Lock() 153 defer i.attrMu.Unlock() 154 return linux.Statx{ 155 Mask: linux.STATX_TYPE | linux.STATX_MODE | linux.STATX_NLINK | linux.STATX_UID | linux.STATX_GID | linux.STATX_ATIME | linux.STATX_MTIME | linux.STATX_CTIME | linux.STATX_INO | linux.STATX_SIZE | linux.STATX_BLOCKS, 156 Blksize: hostarch.PageSize, 157 Nlink: 1, 158 UID: uint32(i.uid), 159 GID: uint32(i.gid), 160 Mode: pipeMode, 161 Ino: i.ino, 162 Size: 0, 163 Blocks: 0, 164 Atime: ts, 165 Ctime: ts, 166 Mtime: ts, 167 DevMajor: linux.UNNAMED_MAJOR, 168 DevMinor: vfsfs.Impl().(*filesystem).devMinor, 169 }, nil 170 } 171 172 // SetStat implements kernfs.Inode.SetStat. 173 func (i *inode) SetStat(ctx context.Context, vfsfs *vfs.Filesystem, creds *auth.Credentials, opts vfs.SetStatOptions) error { 174 if opts.Stat.Mask&^(linux.STATX_UID|linux.STATX_GID) != 0 { 175 return linuxerr.EPERM 176 } 177 i.attrMu.Lock() 178 defer i.attrMu.Unlock() 179 if err := vfs.CheckSetStat(ctx, creds, &opts, pipeMode, auth.KUID(i.uid), auth.KGID(i.gid)); err != nil { 180 return err 181 } 182 if opts.Stat.Mask&linux.STATX_UID != 0 { 183 i.uid = auth.KUID(opts.Stat.UID) 184 } 185 if opts.Stat.Mask&linux.STATX_GID != 0 { 186 i.gid = auth.KGID(opts.Stat.GID) 187 } 188 return nil 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 opts.Flags &= linux.O_ACCMODE | linux.O_CREAT | linux.O_EXCL | linux.O_TRUNC | 194 linux.O_DIRECTORY | linux.O_NOFOLLOW | linux.O_NONBLOCK | linux.O_NOCTTY 195 return i.pipe.Open(ctx, rp.Mount(), d.VFSDentry(), opts.Flags, &i.locks) 196 } 197 198 // StatFS implements kernfs.Inode.StatFS. 199 func (i *inode) StatFS(ctx context.Context, fs *vfs.Filesystem) (linux.Statfs, error) { 200 return vfs.GenericStatFS(linux.PIPEFS_MAGIC), nil 201 } 202 203 // NewConnectedPipeFDs returns a pair of FileDescriptions representing the read 204 // and write ends of a newly-created pipe, as for pipe(2) and pipe2(2). 205 // 206 // Preconditions: mnt.Filesystem() must have been returned by NewFilesystem(). 207 func NewConnectedPipeFDs(ctx context.Context, mnt *vfs.Mount, flags uint32) (*vfs.FileDescription, *vfs.FileDescription, error) { 208 fs := mnt.Filesystem().Impl().(*filesystem) 209 inode := newInode(ctx, fs) 210 var d kernfs.Dentry 211 d.Init(&fs.Filesystem, inode) 212 defer d.DecRef(ctx) 213 return inode.pipe.ReaderWriterPair(ctx, mnt, d.VFSDentry(), flags) 214 }