github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/vfs/resolving_path.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 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/sentry/kernel/auth" 25 "github.com/SagerNet/gvisor/pkg/sync" 26 "github.com/SagerNet/gvisor/pkg/syserror" 27 ) 28 29 // ResolvingPath represents the state of an in-progress path resolution, shared 30 // between VFS and FilesystemImpl methods that take a path. 31 // 32 // From the perspective of FilesystemImpl methods, a ResolvingPath represents a 33 // starting Dentry on the associated Filesystem (on which a reference is 34 // already held), a stream of path components relative to that Dentry, and 35 // elements of the invoking Context that are commonly required by 36 // FilesystemImpl methods. 37 // 38 // ResolvingPath is loosely analogous to Linux's struct nameidata. 39 // 40 // +stateify savable 41 type ResolvingPath struct { 42 vfs *VirtualFilesystem 43 root VirtualDentry // refs borrowed from PathOperation 44 mount *Mount 45 start *Dentry 46 pit fspath.Iterator 47 48 flags uint16 49 mustBeDir bool // final file must be a directory? 50 symlinks uint8 // number of symlinks traversed 51 curPart uint8 // index into parts 52 53 creds *auth.Credentials 54 55 // Data associated with resolve*Errors, stored in ResolvingPath so that 56 // those errors don't need to allocate. 57 nextMount *Mount // ref held if not nil 58 nextStart *Dentry // ref held if not nil 59 absSymlinkTarget fspath.Path 60 61 // ResolvingPath tracks relative paths, which is updated whenever a relative 62 // symlink is encountered. 63 parts [1 + linux.MaxSymlinkTraversals]fspath.Iterator 64 } 65 66 const ( 67 rpflagsHaveMountRef = 1 << iota // do we hold a reference on mount? 68 rpflagsHaveStartRef // do we hold a reference on start? 69 rpflagsFollowFinalSymlink // same as PathOperation.FollowFinalSymlink 70 ) 71 72 func init() { 73 if maxParts := len(ResolvingPath{}.parts); maxParts > 255 { 74 panic(fmt.Sprintf("uint8 is insufficient to accommodate len(ResolvingPath.parts) (%d)", maxParts)) 75 } 76 } 77 78 // Error types that communicate state from the FilesystemImpl-caller, 79 // VFS-callee side of path resolution (i.e. errors returned by 80 // ResolvingPath.Resolve*()) to the VFS-caller, FilesystemImpl-callee side 81 // (i.e. VFS methods => ResolvingPath.handleError()). These are empty structs 82 // rather than error values because Go doesn't support non-primitive constants, 83 // so error "constants" are really mutable vars, necessitating somewhat 84 // expensive interface object comparisons. 85 86 // +stateify savable 87 type resolveMountRootOrJumpError struct{} 88 89 // Error implements error.Error. 90 func (resolveMountRootOrJumpError) Error() string { 91 return "resolving mount root or jump" 92 } 93 94 // +stateify savable 95 type resolveMountPointError struct{} 96 97 // Error implements error.Error. 98 func (resolveMountPointError) Error() string { 99 return "resolving mount point" 100 } 101 102 // +stateify savable 103 type resolveAbsSymlinkError struct{} 104 105 // Error implements error.Error. 106 func (resolveAbsSymlinkError) Error() string { 107 return "resolving absolute symlink" 108 } 109 110 var resolvingPathPool = sync.Pool{ 111 New: func() interface{} { 112 return &ResolvingPath{} 113 }, 114 } 115 116 // getResolvingPath gets a new ResolvingPath from the pool. Caller must call 117 // ResolvingPath.Release() when done. 118 func (vfs *VirtualFilesystem) getResolvingPath(creds *auth.Credentials, pop *PathOperation) *ResolvingPath { 119 rp := resolvingPathPool.Get().(*ResolvingPath) 120 rp.vfs = vfs 121 rp.root = pop.Root 122 rp.mount = pop.Start.mount 123 rp.start = pop.Start.dentry 124 rp.pit = pop.Path.Begin 125 rp.flags = 0 126 if pop.FollowFinalSymlink { 127 rp.flags |= rpflagsFollowFinalSymlink 128 } 129 rp.mustBeDir = pop.Path.Dir 130 rp.symlinks = 0 131 rp.curPart = 0 132 rp.creds = creds 133 rp.parts[0] = pop.Path.Begin 134 return rp 135 } 136 137 // Copy creates another ResolvingPath with the same state as the original. 138 // Copies are independent, using the copy does not change the original and 139 // vice-versa. 140 // 141 // Caller must call Resease() when done. 142 func (rp *ResolvingPath) Copy() *ResolvingPath { 143 copy := resolvingPathPool.Get().(*ResolvingPath) 144 *copy = *rp // All fields all shallow copiable. 145 146 // Take extra reference for the copy if the original had them. 147 if copy.flags&rpflagsHaveStartRef != 0 { 148 copy.start.IncRef() 149 } 150 if copy.flags&rpflagsHaveMountRef != 0 { 151 copy.mount.IncRef() 152 } 153 // Reset error state. 154 copy.nextStart = nil 155 copy.nextMount = nil 156 return copy 157 } 158 159 // Release decrements references if needed and returns the object to the pool. 160 func (rp *ResolvingPath) Release(ctx context.Context) { 161 rp.root = VirtualDentry{} 162 rp.decRefStartAndMount(ctx) 163 rp.mount = nil 164 rp.start = nil 165 rp.releaseErrorState(ctx) 166 resolvingPathPool.Put(rp) 167 } 168 169 func (rp *ResolvingPath) decRefStartAndMount(ctx context.Context) { 170 if rp.flags&rpflagsHaveStartRef != 0 { 171 rp.start.DecRef(ctx) 172 } 173 if rp.flags&rpflagsHaveMountRef != 0 { 174 rp.mount.DecRef(ctx) 175 } 176 } 177 178 func (rp *ResolvingPath) releaseErrorState(ctx context.Context) { 179 if rp.nextStart != nil { 180 rp.nextStart.DecRef(ctx) 181 rp.nextStart = nil 182 } 183 if rp.nextMount != nil { 184 rp.nextMount.DecRef(ctx) 185 rp.nextMount = nil 186 } 187 } 188 189 // VirtualFilesystem returns the containing VirtualFilesystem. 190 func (rp *ResolvingPath) VirtualFilesystem() *VirtualFilesystem { 191 return rp.vfs 192 } 193 194 // Credentials returns the credentials of rp's provider. 195 func (rp *ResolvingPath) Credentials() *auth.Credentials { 196 return rp.creds 197 } 198 199 // Mount returns the Mount on which path resolution is currently occurring. It 200 // does not take a reference on the returned Mount. 201 func (rp *ResolvingPath) Mount() *Mount { 202 return rp.mount 203 } 204 205 // Start returns the starting Dentry represented by rp. It does not take a 206 // reference on the returned Dentry. 207 func (rp *ResolvingPath) Start() *Dentry { 208 return rp.start 209 } 210 211 // Done returns true if there are no remaining path components in the stream 212 // represented by rp. 213 func (rp *ResolvingPath) Done() bool { 214 // We don't need to check for rp.curPart == 0 because rp.Advance() won't 215 // set rp.pit to a terminal iterator otherwise. 216 return !rp.pit.Ok() 217 } 218 219 // Final returns true if there is exactly one remaining path component in the 220 // stream represented by rp. 221 // 222 // Preconditions: !rp.Done(). 223 func (rp *ResolvingPath) Final() bool { 224 return rp.curPart == 0 && !rp.pit.NextOk() 225 } 226 227 // Component returns the current path component in the stream represented by 228 // rp. 229 // 230 // Preconditions: !rp.Done(). 231 func (rp *ResolvingPath) Component() string { 232 if checkInvariants { 233 if !rp.pit.Ok() { 234 panic("ResolvingPath.Component() called at end of relative path") 235 } 236 } 237 return rp.pit.String() 238 } 239 240 // Advance advances the stream of path components represented by rp. 241 // 242 // Preconditions: !rp.Done(). 243 func (rp *ResolvingPath) Advance() { 244 if checkInvariants { 245 if !rp.pit.Ok() { 246 panic("ResolvingPath.Advance() called at end of relative path") 247 } 248 } 249 next := rp.pit.Next() 250 if next.Ok() || rp.curPart == 0 { // have next component, or at end of path 251 rp.pit = next 252 } else { // at end of path segment, continue with next one 253 rp.curPart-- 254 rp.pit = rp.parts[rp.curPart] 255 } 256 } 257 258 // CheckRoot is called before resolving the parent of the Dentry d. If the 259 // Dentry is contextually a VFS root, such that path resolution should treat 260 // d's parent as itself, CheckRoot returns (true, nil). If the Dentry is the 261 // root of a non-root mount, such that path resolution should switch to another 262 // Mount, CheckRoot returns (unspecified, non-nil error). Otherwise, path 263 // resolution should resolve d's parent normally, and CheckRoot returns (false, 264 // nil). 265 func (rp *ResolvingPath) CheckRoot(ctx context.Context, d *Dentry) (bool, error) { 266 if d == rp.root.dentry && rp.mount == rp.root.mount { 267 // At contextual VFS root (due to e.g. chroot(2)). 268 return true, nil 269 } else if d == rp.mount.root { 270 // At mount root ... 271 vd := rp.vfs.getMountpointAt(ctx, rp.mount, rp.root) 272 if vd.Ok() { 273 // ... of non-root mount. 274 rp.nextMount = vd.mount 275 rp.nextStart = vd.dentry 276 return false, resolveMountRootOrJumpError{} 277 } 278 // ... of root mount. 279 return true, nil 280 } 281 return false, nil 282 } 283 284 // CheckMount is called after resolving the parent or child of another Dentry 285 // to d. If d is a mount point, such that path resolution should switch to 286 // another Mount, CheckMount returns a non-nil error. Otherwise, CheckMount 287 // returns nil. 288 func (rp *ResolvingPath) CheckMount(ctx context.Context, d *Dentry) error { 289 if !d.isMounted() { 290 return nil 291 } 292 if mnt := rp.vfs.getMountAt(ctx, rp.mount, d); mnt != nil { 293 rp.nextMount = mnt 294 return resolveMountPointError{} 295 } 296 return nil 297 } 298 299 // ShouldFollowSymlink returns true if, supposing that the current path 300 // component in pcs represents a symbolic link, the symbolic link should be 301 // followed. 302 // 303 // If path is terminated with '/', the '/' is considered the last element and 304 // any symlink before that is followed: 305 // - For most non-creating walks, the last path component is handled by 306 // fs/namei.c:lookup_last(), which sets LOOKUP_FOLLOW if the first byte 307 // after the path component is non-NULL (which is only possible if it's '/') 308 // and the path component is of type LAST_NORM. 309 // 310 // - For open/openat/openat2 without O_CREAT, the last path component is 311 // handled by fs/namei.c:do_last(), which does the same, though without the 312 // LAST_NORM check. 313 // 314 // Preconditions: !rp.Done(). 315 func (rp *ResolvingPath) ShouldFollowSymlink() bool { 316 // Non-final symlinks are always followed. Paths terminated with '/' are also 317 // always followed. 318 return rp.flags&rpflagsFollowFinalSymlink != 0 || !rp.Final() || rp.MustBeDir() 319 } 320 321 // HandleSymlink is called when the current path component is a symbolic link 322 // to the given target. If the calling Filesystem method should continue path 323 // traversal, HandleSymlink updates the path component stream to reflect the 324 // symlink target and returns nil. Otherwise it returns a non-nil error. 325 // 326 // Preconditions: !rp.Done(). 327 // 328 // Postconditions: If HandleSymlink returns a nil error, then !rp.Done(). 329 func (rp *ResolvingPath) HandleSymlink(target string) error { 330 if rp.symlinks >= linux.MaxSymlinkTraversals { 331 return linuxerr.ELOOP 332 } 333 if len(target) == 0 { 334 return syserror.ENOENT 335 } 336 rp.symlinks++ 337 targetPath := fspath.Parse(target) 338 if targetPath.Absolute { 339 rp.absSymlinkTarget = targetPath 340 return resolveAbsSymlinkError{} 341 } 342 // Consume the path component that represented the symlink. 343 rp.Advance() 344 // Prepend the symlink target to the relative path. 345 if checkInvariants { 346 if !targetPath.HasComponents() { 347 panic(fmt.Sprintf("non-empty pathname %q parsed to relative path with no components", target)) 348 } 349 } 350 rp.relpathPrepend(targetPath) 351 return nil 352 } 353 354 // Preconditions: path.HasComponents(). 355 func (rp *ResolvingPath) relpathPrepend(path fspath.Path) { 356 if rp.pit.Ok() { 357 rp.parts[rp.curPart] = rp.pit 358 rp.pit = path.Begin 359 rp.curPart++ 360 } else { 361 // The symlink was the final path component, so now the symlink target 362 // is the whole path. 363 rp.pit = path.Begin 364 // Symlink targets can set rp.mustBeDir (if they end in a trailing /), 365 // but can't unset it. 366 if path.Dir { 367 rp.mustBeDir = true 368 } 369 } 370 } 371 372 // HandleJump is called when the current path component is a "magic" link to 373 // the given VirtualDentry, like /proc/[pid]/fd/[fd]. If the calling Filesystem 374 // method should continue path traversal, HandleMagicSymlink updates the path 375 // component stream to reflect the magic link target and returns nil. Otherwise 376 // it returns a non-nil error. 377 // 378 // Preconditions: !rp.Done(). 379 func (rp *ResolvingPath) HandleJump(target VirtualDentry) error { 380 if rp.symlinks >= linux.MaxSymlinkTraversals { 381 return linuxerr.ELOOP 382 } 383 rp.symlinks++ 384 // Consume the path component that represented the magic link. 385 rp.Advance() 386 // Unconditionally return a resolveMountRootOrJumpError, even if the Mount 387 // isn't changing, to force restarting at the new Dentry. 388 target.IncRef() 389 rp.nextMount = target.mount 390 rp.nextStart = target.dentry 391 return resolveMountRootOrJumpError{} 392 } 393 394 func (rp *ResolvingPath) handleError(ctx context.Context, err error) bool { 395 switch err.(type) { 396 case resolveMountRootOrJumpError: 397 // Switch to the new Mount. We hold references on the Mount and Dentry. 398 rp.decRefStartAndMount(ctx) 399 rp.mount = rp.nextMount 400 rp.start = rp.nextStart 401 rp.flags |= rpflagsHaveMountRef | rpflagsHaveStartRef 402 rp.nextMount = nil 403 rp.nextStart = nil 404 // Don't consume the path component that caused us to traverse 405 // through the mount root - i.e. the ".." - because we still need to 406 // resolve the mount point's parent in the new FilesystemImpl. 407 // 408 // Restart path resolution on the new Mount. Don't bother calling 409 // rp.releaseErrorState() since we already set nextMount and nextStart 410 // to nil above. 411 return true 412 413 case resolveMountPointError: 414 // Switch to the new Mount. We hold a reference on the Mount, but 415 // borrow the reference on the mount root from the Mount. 416 rp.decRefStartAndMount(ctx) 417 rp.mount = rp.nextMount 418 rp.start = rp.nextMount.root 419 rp.flags = rp.flags&^rpflagsHaveStartRef | rpflagsHaveMountRef 420 rp.nextMount = nil 421 // Consume the path component that represented the mount point. 422 rp.Advance() 423 // Restart path resolution on the new Mount. 424 rp.releaseErrorState(ctx) 425 return true 426 427 case resolveAbsSymlinkError: 428 // Switch to the new Mount. References are borrowed from rp.root. 429 rp.decRefStartAndMount(ctx) 430 rp.mount = rp.root.mount 431 rp.start = rp.root.dentry 432 rp.flags &^= rpflagsHaveMountRef | rpflagsHaveStartRef 433 // Consume the path component that represented the symlink. 434 rp.Advance() 435 // Prepend the symlink target to the relative path. 436 rp.relpathPrepend(rp.absSymlinkTarget) 437 // Restart path resolution on the new Mount. 438 rp.releaseErrorState(ctx) 439 return true 440 441 default: 442 // Not an error we can handle. 443 return false 444 } 445 } 446 447 // canHandleError returns true if err is an error returned by rp.Resolve*() 448 // that rp.handleError() may attempt to handle. 449 func (rp *ResolvingPath) canHandleError(err error) bool { 450 switch err.(type) { 451 case resolveMountRootOrJumpError, resolveMountPointError, resolveAbsSymlinkError: 452 return true 453 default: 454 return false 455 } 456 } 457 458 // MustBeDir returns true if the file traversed by rp must be a directory. 459 func (rp *ResolvingPath) MustBeDir() bool { 460 return rp.mustBeDir 461 }