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