github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/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/SagerNet/gvisor/pkg/abi/linux" 23 "github.com/SagerNet/gvisor/pkg/context" 24 "github.com/SagerNet/gvisor/pkg/errors/linuxerr" 25 "github.com/SagerNet/gvisor/pkg/fspath" 26 "github.com/SagerNet/gvisor/pkg/hostarch" 27 "github.com/SagerNet/gvisor/pkg/sentry/fsimpl/kernfs" 28 "github.com/SagerNet/gvisor/pkg/sentry/kernel/auth" 29 "github.com/SagerNet/gvisor/pkg/sentry/kernel/pipe" 30 ktime "github.com/SagerNet/gvisor/pkg/sentry/kernel/time" 31 "github.com/SagerNet/gvisor/pkg/sentry/vfs" 32 ) 33 34 // +stateify savable 35 type filesystemType struct{} 36 37 // Name implements vfs.FilesystemType.Name. 38 func (filesystemType) Name() string { 39 return "pipefs" 40 } 41 42 // Release implements vfs.FilesystemType.Release. 43 func (filesystemType) Release(ctx context.Context) {} 44 45 // GetFilesystem implements vfs.FilesystemType.GetFilesystem. 46 func (filesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.VirtualFilesystem, creds *auth.Credentials, source string, opts vfs.GetFilesystemOptions) (*vfs.Filesystem, *vfs.Dentry, error) { 47 panic("pipefs.filesystemType.GetFilesystem should never be called") 48 } 49 50 // +stateify savable 51 type filesystem struct { 52 kernfs.Filesystem 53 54 devMinor uint32 55 } 56 57 // NewFilesystem sets up and returns a new vfs.Filesystem implemented by pipefs. 58 func NewFilesystem(vfsObj *vfs.VirtualFilesystem) (*vfs.Filesystem, error) { 59 devMinor, err := vfsObj.GetAnonBlockDevMinor() 60 if err != nil { 61 return nil, err 62 } 63 fs := &filesystem{ 64 devMinor: devMinor, 65 } 66 fs.Filesystem.VFSFilesystem().Init(vfsObj, filesystemType{}, fs) 67 return fs.Filesystem.VFSFilesystem(), nil 68 } 69 70 // Release implements vfs.FilesystemImpl.Release. 71 func (fs *filesystem) Release(ctx context.Context) { 72 fs.Filesystem.VFSFilesystem().VirtualFilesystem().PutAnonBlockDevMinor(fs.devMinor) 73 fs.Filesystem.Release(ctx) 74 } 75 76 // PrependPath implements vfs.FilesystemImpl.PrependPath. 77 func (fs *filesystem) PrependPath(ctx context.Context, vfsroot, vd vfs.VirtualDentry, b *fspath.Builder) error { 78 inode := vd.Dentry().Impl().(*kernfs.Dentry).Inode().(*inode) 79 b.PrependComponent(fmt.Sprintf("pipe:[%d]", inode.ino)) 80 return vfs.PrependPathSyntheticError{} 81 } 82 83 // MountOptions implements vfs.FilesystemImpl.MountOptions. 84 func (fs *filesystem) MountOptions() string { 85 return "" 86 } 87 88 // inode implements kernfs.Inode. 89 // 90 // +stateify savable 91 type inode struct { 92 kernfs.InodeNotDirectory 93 kernfs.InodeNotSymlink 94 kernfs.InodeNoopRefCount 95 96 locks vfs.FileLocks 97 pipe *pipe.VFSPipe 98 99 ino uint64 100 uid auth.KUID 101 gid auth.KGID 102 // We use the creation timestamp for all of atime, mtime, and ctime. 103 ctime ktime.Time 104 } 105 106 func newInode(ctx context.Context, fs *filesystem) *inode { 107 creds := auth.CredentialsFromContext(ctx) 108 return &inode{ 109 pipe: pipe.NewVFSPipe(false /* isNamed */, pipe.DefaultPipeSize), 110 ino: fs.Filesystem.NextIno(), 111 uid: creds.EffectiveKUID, 112 gid: creds.EffectiveKGID, 113 ctime: ktime.NowFromContext(ctx), 114 } 115 } 116 117 const pipeMode = 0600 | linux.S_IFIFO 118 119 // CheckPermissions implements kernfs.Inode.CheckPermissions. 120 func (i *inode) CheckPermissions(ctx context.Context, creds *auth.Credentials, ats vfs.AccessTypes) error { 121 return vfs.GenericCheckPermissions(creds, ats, pipeMode, i.uid, i.gid) 122 } 123 124 // Mode implements kernfs.Inode.Mode. 125 func (i *inode) Mode() linux.FileMode { 126 return pipeMode 127 } 128 129 // Stat implements kernfs.Inode.Stat. 130 func (i *inode) Stat(_ context.Context, vfsfs *vfs.Filesystem, opts vfs.StatOptions) (linux.Statx, error) { 131 ts := linux.NsecToStatxTimestamp(i.ctime.Nanoseconds()) 132 return linux.Statx{ 133 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, 134 Blksize: hostarch.PageSize, 135 Nlink: 1, 136 UID: uint32(i.uid), 137 GID: uint32(i.gid), 138 Mode: pipeMode, 139 Ino: i.ino, 140 Size: 0, 141 Blocks: 0, 142 Atime: ts, 143 Ctime: ts, 144 Mtime: ts, 145 DevMajor: linux.UNNAMED_MAJOR, 146 DevMinor: vfsfs.Impl().(*filesystem).devMinor, 147 }, nil 148 } 149 150 // SetStat implements kernfs.Inode.SetStat. 151 func (i *inode) SetStat(ctx context.Context, vfsfs *vfs.Filesystem, creds *auth.Credentials, opts vfs.SetStatOptions) error { 152 if opts.Stat.Mask == 0 { 153 return nil 154 } 155 return linuxerr.EPERM 156 } 157 158 // Open implements kernfs.Inode.Open. 159 func (i *inode) Open(ctx context.Context, rp *vfs.ResolvingPath, d *kernfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) { 160 return i.pipe.Open(ctx, rp.Mount(), d.VFSDentry(), opts.Flags, &i.locks) 161 } 162 163 // StatFS implements kernfs.Inode.StatFS. 164 func (i *inode) StatFS(ctx context.Context, fs *vfs.Filesystem) (linux.Statfs, error) { 165 return vfs.GenericStatFS(linux.PIPEFS_MAGIC), nil 166 } 167 168 // NewConnectedPipeFDs returns a pair of FileDescriptions representing the read 169 // and write ends of a newly-created pipe, as for pipe(2) and pipe2(2). 170 // 171 // Preconditions: mnt.Filesystem() must have been returned by NewFilesystem(). 172 func NewConnectedPipeFDs(ctx context.Context, mnt *vfs.Mount, flags uint32) (*vfs.FileDescription, *vfs.FileDescription, error) { 173 fs := mnt.Filesystem().Impl().(*filesystem) 174 inode := newInode(ctx, fs) 175 var d kernfs.Dentry 176 d.Init(&fs.Filesystem, inode) 177 defer d.DecRef(ctx) 178 return inode.pipe.ReaderWriterPair(ctx, mnt, d.VFSDentry(), flags) 179 }