github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/vfs/anonfs.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 vfs 16 17 import ( 18 "fmt" 19 20 "github.com/SagerNet/gvisor/pkg/abi/linux" 21 "github.com/SagerNet/gvisor/pkg/context" 22 "github.com/SagerNet/gvisor/pkg/errors/linuxerr" 23 "github.com/SagerNet/gvisor/pkg/fspath" 24 "github.com/SagerNet/gvisor/pkg/hostarch" 25 "github.com/SagerNet/gvisor/pkg/sentry/kernel/auth" 26 "github.com/SagerNet/gvisor/pkg/sentry/socket/unix/transport" 27 "github.com/SagerNet/gvisor/pkg/syserror" 28 ) 29 30 // NewAnonVirtualDentry returns a VirtualDentry with the given synthetic name, 31 // consistent with Linux's fs/anon_inodes.c:anon_inode_getfile(). References 32 // are taken on the returned VirtualDentry. 33 func (vfs *VirtualFilesystem) NewAnonVirtualDentry(name string) VirtualDentry { 34 d := anonDentry{ 35 name: name, 36 } 37 d.vfsd.Init(&d) 38 vfs.anonMount.IncRef() 39 // anonDentry no-ops refcounting. 40 return VirtualDentry{ 41 mount: vfs.anonMount, 42 dentry: &d.vfsd, 43 } 44 } 45 46 const ( 47 anonfsBlockSize = hostarch.PageSize // via fs/libfs.c:pseudo_fs_fill_super() 48 49 // Mode, UID, and GID for a generic anonfs file. 50 anonFileMode = 0600 // no type is correct 51 anonFileUID = auth.RootKUID 52 anonFileGID = auth.RootKGID 53 ) 54 55 // anonFilesystemType implements FilesystemType. 56 // 57 // +stateify savable 58 type anonFilesystemType struct{} 59 60 // GetFilesystem implements FilesystemType.GetFilesystem. 61 func (anonFilesystemType) GetFilesystem(context.Context, *VirtualFilesystem, *auth.Credentials, string, GetFilesystemOptions) (*Filesystem, *Dentry, error) { 62 panic("cannot instaniate an anon filesystem") 63 } 64 65 // Name implements FilesystemType.Name. 66 func (anonFilesystemType) Name() string { 67 return "none" 68 } 69 70 // Release implemenents FilesystemType.Release. 71 func (anonFilesystemType) Release(ctx context.Context) {} 72 73 // anonFilesystem is the implementation of FilesystemImpl that backs 74 // VirtualDentries returned by VirtualFilesystem.NewAnonVirtualDentry(). 75 // 76 // Since all Dentries in anonFilesystem are non-directories, all FilesystemImpl 77 // methods that would require an anonDentry to be a directory return ENOTDIR. 78 // 79 // +stateify savable 80 type anonFilesystem struct { 81 vfsfs Filesystem 82 83 devMinor uint32 84 } 85 86 // +stateify savable 87 type anonDentry struct { 88 vfsd Dentry 89 90 name string 91 } 92 93 // Release implements FilesystemImpl.Release. 94 func (fs *anonFilesystem) Release(ctx context.Context) { 95 } 96 97 // Sync implements FilesystemImpl.Sync. 98 func (fs *anonFilesystem) Sync(ctx context.Context) error { 99 return nil 100 } 101 102 // AccessAt implements vfs.Filesystem.Impl.AccessAt. 103 func (fs *anonFilesystem) AccessAt(ctx context.Context, rp *ResolvingPath, creds *auth.Credentials, ats AccessTypes) error { 104 if !rp.Done() { 105 return syserror.ENOTDIR 106 } 107 return GenericCheckPermissions(creds, ats, anonFileMode, anonFileUID, anonFileGID) 108 } 109 110 // GetDentryAt implements FilesystemImpl.GetDentryAt. 111 func (fs *anonFilesystem) GetDentryAt(ctx context.Context, rp *ResolvingPath, opts GetDentryOptions) (*Dentry, error) { 112 if !rp.Done() { 113 return nil, syserror.ENOTDIR 114 } 115 if opts.CheckSearchable { 116 return nil, syserror.ENOTDIR 117 } 118 // anonDentry no-ops refcounting. 119 return rp.Start(), nil 120 } 121 122 // GetParentDentryAt implements FilesystemImpl.GetParentDentryAt. 123 func (fs *anonFilesystem) GetParentDentryAt(ctx context.Context, rp *ResolvingPath) (*Dentry, error) { 124 if !rp.Final() { 125 return nil, syserror.ENOTDIR 126 } 127 // anonDentry no-ops refcounting. 128 return rp.Start(), nil 129 } 130 131 // LinkAt implements FilesystemImpl.LinkAt. 132 func (fs *anonFilesystem) LinkAt(ctx context.Context, rp *ResolvingPath, vd VirtualDentry) error { 133 if !rp.Final() { 134 return syserror.ENOTDIR 135 } 136 return linuxerr.EPERM 137 } 138 139 // MkdirAt implements FilesystemImpl.MkdirAt. 140 func (fs *anonFilesystem) MkdirAt(ctx context.Context, rp *ResolvingPath, opts MkdirOptions) error { 141 if !rp.Final() { 142 return syserror.ENOTDIR 143 } 144 return linuxerr.EPERM 145 } 146 147 // MknodAt implements FilesystemImpl.MknodAt. 148 func (fs *anonFilesystem) MknodAt(ctx context.Context, rp *ResolvingPath, opts MknodOptions) error { 149 if !rp.Final() { 150 return syserror.ENOTDIR 151 } 152 return linuxerr.EPERM 153 } 154 155 // OpenAt implements FilesystemImpl.OpenAt. 156 func (fs *anonFilesystem) OpenAt(ctx context.Context, rp *ResolvingPath, opts OpenOptions) (*FileDescription, error) { 157 if !rp.Done() { 158 return nil, syserror.ENOTDIR 159 } 160 return nil, linuxerr.ENODEV 161 } 162 163 // ReadlinkAt implements FilesystemImpl.ReadlinkAt. 164 func (fs *anonFilesystem) ReadlinkAt(ctx context.Context, rp *ResolvingPath) (string, error) { 165 if !rp.Done() { 166 return "", syserror.ENOTDIR 167 } 168 return "", linuxerr.EINVAL 169 } 170 171 // RenameAt implements FilesystemImpl.RenameAt. 172 func (fs *anonFilesystem) RenameAt(ctx context.Context, rp *ResolvingPath, oldParentVD VirtualDentry, oldName string, opts RenameOptions) error { 173 if !rp.Final() { 174 return syserror.ENOTDIR 175 } 176 return linuxerr.EPERM 177 } 178 179 // RmdirAt implements FilesystemImpl.RmdirAt. 180 func (fs *anonFilesystem) RmdirAt(ctx context.Context, rp *ResolvingPath) error { 181 if !rp.Final() { 182 return syserror.ENOTDIR 183 } 184 return linuxerr.EPERM 185 } 186 187 // SetStatAt implements FilesystemImpl.SetStatAt. 188 func (fs *anonFilesystem) SetStatAt(ctx context.Context, rp *ResolvingPath, opts SetStatOptions) error { 189 if !rp.Done() { 190 return syserror.ENOTDIR 191 } 192 // Linux actually permits anon_inode_inode's metadata to be set, which is 193 // visible to all users of anon_inode_inode. We just silently ignore 194 // metadata changes. 195 return nil 196 } 197 198 // StatAt implements FilesystemImpl.StatAt. 199 func (fs *anonFilesystem) StatAt(ctx context.Context, rp *ResolvingPath, opts StatOptions) (linux.Statx, error) { 200 if !rp.Done() { 201 return linux.Statx{}, syserror.ENOTDIR 202 } 203 // See fs/anon_inodes.c:anon_inode_init() => fs/libfs.c:alloc_anon_inode(). 204 return linux.Statx{ 205 Mask: linux.STATX_TYPE | linux.STATX_MODE | linux.STATX_NLINK | linux.STATX_UID | linux.STATX_GID | linux.STATX_INO | linux.STATX_SIZE | linux.STATX_BLOCKS, 206 Blksize: anonfsBlockSize, 207 Nlink: 1, 208 UID: uint32(anonFileUID), 209 GID: uint32(anonFileGID), 210 Mode: anonFileMode, 211 Ino: 1, 212 Size: 0, 213 Blocks: 0, 214 DevMajor: linux.UNNAMED_MAJOR, 215 DevMinor: fs.devMinor, 216 }, nil 217 } 218 219 // StatFSAt implements FilesystemImpl.StatFSAt. 220 func (fs *anonFilesystem) StatFSAt(ctx context.Context, rp *ResolvingPath) (linux.Statfs, error) { 221 if !rp.Done() { 222 return linux.Statfs{}, syserror.ENOTDIR 223 } 224 return linux.Statfs{ 225 Type: linux.ANON_INODE_FS_MAGIC, 226 BlockSize: anonfsBlockSize, 227 }, nil 228 } 229 230 // SymlinkAt implements FilesystemImpl.SymlinkAt. 231 func (fs *anonFilesystem) SymlinkAt(ctx context.Context, rp *ResolvingPath, target string) error { 232 if !rp.Final() { 233 return syserror.ENOTDIR 234 } 235 return linuxerr.EPERM 236 } 237 238 // UnlinkAt implements FilesystemImpl.UnlinkAt. 239 func (fs *anonFilesystem) UnlinkAt(ctx context.Context, rp *ResolvingPath) error { 240 if !rp.Final() { 241 return syserror.ENOTDIR 242 } 243 return linuxerr.EPERM 244 } 245 246 // BoundEndpointAt implements FilesystemImpl.BoundEndpointAt. 247 func (fs *anonFilesystem) BoundEndpointAt(ctx context.Context, rp *ResolvingPath, opts BoundEndpointOptions) (transport.BoundEndpoint, error) { 248 if !rp.Final() { 249 return nil, syserror.ENOTDIR 250 } 251 if err := GenericCheckPermissions(rp.Credentials(), MayWrite, anonFileMode, anonFileUID, anonFileGID); err != nil { 252 return nil, err 253 } 254 return nil, linuxerr.ECONNREFUSED 255 } 256 257 // ListXattrAt implements FilesystemImpl.ListXattrAt. 258 func (fs *anonFilesystem) ListXattrAt(ctx context.Context, rp *ResolvingPath, size uint64) ([]string, error) { 259 if !rp.Done() { 260 return nil, syserror.ENOTDIR 261 } 262 return nil, nil 263 } 264 265 // GetXattrAt implements FilesystemImpl.GetXattrAt. 266 func (fs *anonFilesystem) GetXattrAt(ctx context.Context, rp *ResolvingPath, opts GetXattrOptions) (string, error) { 267 if !rp.Done() { 268 return "", syserror.ENOTDIR 269 } 270 return "", linuxerr.ENOTSUP 271 } 272 273 // SetXattrAt implements FilesystemImpl.SetXattrAt. 274 func (fs *anonFilesystem) SetXattrAt(ctx context.Context, rp *ResolvingPath, opts SetXattrOptions) error { 275 if !rp.Done() { 276 return syserror.ENOTDIR 277 } 278 return linuxerr.EPERM 279 } 280 281 // RemoveXattrAt implements FilesystemImpl.RemoveXattrAt. 282 func (fs *anonFilesystem) RemoveXattrAt(ctx context.Context, rp *ResolvingPath, name string) error { 283 if !rp.Done() { 284 return syserror.ENOTDIR 285 } 286 return linuxerr.EPERM 287 } 288 289 // PrependPath implements FilesystemImpl.PrependPath. 290 func (fs *anonFilesystem) PrependPath(ctx context.Context, vfsroot, vd VirtualDentry, b *fspath.Builder) error { 291 b.PrependComponent(fmt.Sprintf("anon_inode:%s", vd.dentry.impl.(*anonDentry).name)) 292 return PrependPathSyntheticError{} 293 } 294 295 // MountOptions implements FilesystemImpl.MountOptions. 296 func (fs *anonFilesystem) MountOptions() string { 297 return "" 298 } 299 300 // IncRef implements DentryImpl.IncRef. 301 func (d *anonDentry) IncRef() { 302 // no-op 303 } 304 305 // TryIncRef implements DentryImpl.TryIncRef. 306 func (d *anonDentry) TryIncRef() bool { 307 return true 308 } 309 310 // DecRef implements DentryImpl.DecRef. 311 func (d *anonDentry) DecRef(ctx context.Context) { 312 // no-op 313 } 314 315 // InotifyWithParent implements DentryImpl.InotifyWithParent. 316 // 317 // Although Linux technically supports inotify on pseudo filesystems (inotify 318 // is implemented at the vfs layer), it is not particularly useful. It is left 319 // unimplemented until someone actually needs it. 320 func (d *anonDentry) InotifyWithParent(ctx context.Context, events, cookie uint32, et EventType) {} 321 322 // Watches implements DentryImpl.Watches. 323 func (d *anonDentry) Watches() *Watches { 324 return nil 325 } 326 327 // OnZeroWatches implements Dentry.OnZeroWatches. 328 func (d *anonDentry) OnZeroWatches(context.Context) {}