github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/syscalls/linux/vfs2/path.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 vfs2 16 17 import ( 18 "github.com/SagerNet/gvisor/pkg/abi/linux" 19 "github.com/SagerNet/gvisor/pkg/errors/linuxerr" 20 "github.com/SagerNet/gvisor/pkg/fspath" 21 "github.com/SagerNet/gvisor/pkg/hostarch" 22 "github.com/SagerNet/gvisor/pkg/sentry/kernel" 23 "github.com/SagerNet/gvisor/pkg/sentry/vfs" 24 "github.com/SagerNet/gvisor/pkg/syserror" 25 ) 26 27 func copyInPath(t *kernel.Task, addr hostarch.Addr) (fspath.Path, error) { 28 pathname, err := t.CopyInString(addr, linux.PATH_MAX) 29 if err != nil { 30 return fspath.Path{}, err 31 } 32 return fspath.Parse(pathname), nil 33 } 34 35 type taskPathOperation struct { 36 pop vfs.PathOperation 37 haveStartRef bool 38 } 39 40 func getTaskPathOperation(t *kernel.Task, dirfd int32, path fspath.Path, shouldAllowEmptyPath shouldAllowEmptyPath, shouldFollowFinalSymlink shouldFollowFinalSymlink) (taskPathOperation, error) { 41 root := t.FSContext().RootDirectoryVFS2() 42 start := root 43 haveStartRef := false 44 if !path.Absolute { 45 if !path.HasComponents() && !bool(shouldAllowEmptyPath) { 46 root.DecRef(t) 47 return taskPathOperation{}, syserror.ENOENT 48 } 49 if dirfd == linux.AT_FDCWD { 50 start = t.FSContext().WorkingDirectoryVFS2() 51 haveStartRef = true 52 } else { 53 dirfile := t.GetFileVFS2(dirfd) 54 if dirfile == nil { 55 root.DecRef(t) 56 return taskPathOperation{}, linuxerr.EBADF 57 } 58 start = dirfile.VirtualDentry() 59 start.IncRef() 60 haveStartRef = true 61 dirfile.DecRef(t) 62 } 63 } 64 return taskPathOperation{ 65 pop: vfs.PathOperation{ 66 Root: root, 67 Start: start, 68 Path: path, 69 FollowFinalSymlink: bool(shouldFollowFinalSymlink), 70 }, 71 haveStartRef: haveStartRef, 72 }, nil 73 } 74 75 func (tpop *taskPathOperation) Release(t *kernel.Task) { 76 tpop.pop.Root.DecRef(t) 77 if tpop.haveStartRef { 78 tpop.pop.Start.DecRef(t) 79 tpop.haveStartRef = false 80 } 81 } 82 83 type shouldAllowEmptyPath bool 84 85 const ( 86 disallowEmptyPath shouldAllowEmptyPath = false 87 allowEmptyPath shouldAllowEmptyPath = true 88 ) 89 90 type shouldFollowFinalSymlink bool 91 92 const ( 93 nofollowFinalSymlink shouldFollowFinalSymlink = false 94 followFinalSymlink shouldFollowFinalSymlink = true 95 )