github.com/ttpreport/gvisor-ligolo@v0.0.0-20240123134145-a858404967ba/pkg/sentry/syscalls/linux/sys_stat.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 linux 16 17 import ( 18 "github.com/ttpreport/gvisor-ligolo/pkg/abi/linux" 19 "github.com/ttpreport/gvisor-ligolo/pkg/bits" 20 "github.com/ttpreport/gvisor-ligolo/pkg/errors/linuxerr" 21 "github.com/ttpreport/gvisor-ligolo/pkg/fspath" 22 "github.com/ttpreport/gvisor-ligolo/pkg/hostarch" 23 "github.com/ttpreport/gvisor-ligolo/pkg/sentry/arch" 24 "github.com/ttpreport/gvisor-ligolo/pkg/sentry/kernel" 25 "github.com/ttpreport/gvisor-ligolo/pkg/sentry/kernel/auth" 26 "github.com/ttpreport/gvisor-ligolo/pkg/sentry/vfs" 27 ) 28 29 // Stat implements Linux syscall stat(2). 30 func Stat(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 31 pathAddr := args[0].Pointer() 32 statAddr := args[1].Pointer() 33 return 0, nil, fstatat(t, linux.AT_FDCWD, pathAddr, statAddr, 0 /* flags */) 34 } 35 36 // Lstat implements Linux syscall lstat(2). 37 func Lstat(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 38 pathAddr := args[0].Pointer() 39 statAddr := args[1].Pointer() 40 return 0, nil, fstatat(t, linux.AT_FDCWD, pathAddr, statAddr, linux.AT_SYMLINK_NOFOLLOW) 41 } 42 43 // Newfstatat implements Linux syscall newfstatat, which backs fstatat(2). 44 func Newfstatat(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 45 dirfd := args[0].Int() 46 pathAddr := args[1].Pointer() 47 statAddr := args[2].Pointer() 48 flags := args[3].Int() 49 return 0, nil, fstatat(t, dirfd, pathAddr, statAddr, flags) 50 } 51 52 func fstatat(t *kernel.Task, dirfd int32, pathAddr, statAddr hostarch.Addr, flags int32) error { 53 if flags&^(linux.AT_EMPTY_PATH|linux.AT_SYMLINK_NOFOLLOW) != 0 { 54 return linuxerr.EINVAL 55 } 56 57 opts := vfs.StatOptions{ 58 Mask: linux.STATX_BASIC_STATS, 59 } 60 61 path, err := copyInPath(t, pathAddr) 62 if err != nil { 63 return err 64 } 65 66 root := t.FSContext().RootDirectory() 67 defer root.DecRef(t) 68 start := root 69 if !path.Absolute { 70 if !path.HasComponents() && flags&linux.AT_EMPTY_PATH == 0 { 71 return linuxerr.ENOENT 72 } 73 if dirfd == linux.AT_FDCWD { 74 start = t.FSContext().WorkingDirectory() 75 defer start.DecRef(t) 76 } else { 77 dirfile := t.GetFile(dirfd) 78 if dirfile == nil { 79 return linuxerr.EBADF 80 } 81 if !path.HasComponents() { 82 // Use FileDescription.Stat() instead of 83 // VirtualFilesystem.StatAt() for fstatat(fd, ""), since the 84 // former may be able to use opened file state to expedite the 85 // Stat. 86 statx, err := dirfile.Stat(t, opts) 87 dirfile.DecRef(t) 88 if err != nil { 89 return err 90 } 91 var stat linux.Stat 92 convertStatxToUserStat(t, &statx, &stat) 93 _, err = stat.CopyOut(t, statAddr) 94 return err 95 } 96 start = dirfile.VirtualDentry() 97 start.IncRef() 98 defer start.DecRef(t) 99 dirfile.DecRef(t) 100 } 101 } 102 103 statx, err := t.Kernel().VFS().StatAt(t, t.Credentials(), &vfs.PathOperation{ 104 Root: root, 105 Start: start, 106 Path: path, 107 FollowFinalSymlink: flags&linux.AT_SYMLINK_NOFOLLOW == 0, 108 }, &opts) 109 if err != nil { 110 return err 111 } 112 var stat linux.Stat 113 convertStatxToUserStat(t, &statx, &stat) 114 _, err = stat.CopyOut(t, statAddr) 115 return err 116 } 117 118 func timespecFromStatxTimestamp(sxts linux.StatxTimestamp) linux.Timespec { 119 return linux.Timespec{ 120 Sec: sxts.Sec, 121 Nsec: int64(sxts.Nsec), 122 } 123 } 124 125 // Fstat implements Linux syscall fstat(2). 126 func Fstat(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 127 fd := args[0].Int() 128 statAddr := args[1].Pointer() 129 130 file := t.GetFile(fd) 131 if file == nil { 132 return 0, nil, linuxerr.EBADF 133 } 134 defer file.DecRef(t) 135 136 statx, err := file.Stat(t, vfs.StatOptions{ 137 Mask: linux.STATX_BASIC_STATS, 138 }) 139 if err != nil { 140 return 0, nil, err 141 } 142 var stat linux.Stat 143 convertStatxToUserStat(t, &statx, &stat) 144 _, err = stat.CopyOut(t, statAddr) 145 return 0, nil, err 146 } 147 148 // Statx implements Linux syscall statx(2). 149 func Statx(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 150 dirfd := args[0].Int() 151 pathAddr := args[1].Pointer() 152 flags := args[2].Int() 153 mask := args[3].Uint() 154 statxAddr := args[4].Pointer() 155 156 // TODO(b/270247637): gVisor does not yet support automount, so 157 // AT_NO_AUTOMOUNT flag is a no-op. 158 flags &= ^linux.AT_NO_AUTOMOUNT 159 160 if flags&^(linux.AT_EMPTY_PATH|linux.AT_SYMLINK_NOFOLLOW|linux.AT_STATX_SYNC_TYPE) != 0 { 161 return 0, nil, linuxerr.EINVAL 162 } 163 // Make sure that only one sync type option is set. 164 syncType := uint32(flags & linux.AT_STATX_SYNC_TYPE) 165 if syncType != 0 && !bits.IsPowerOfTwo32(syncType) { 166 return 0, nil, linuxerr.EINVAL 167 } 168 if mask&linux.STATX__RESERVED != 0 { 169 return 0, nil, linuxerr.EINVAL 170 } 171 172 opts := vfs.StatOptions{ 173 Mask: mask, 174 Sync: uint32(flags & linux.AT_STATX_SYNC_TYPE), 175 } 176 177 path, err := copyInPath(t, pathAddr) 178 if err != nil { 179 return 0, nil, err 180 } 181 182 root := t.FSContext().RootDirectory() 183 defer root.DecRef(t) 184 start := root 185 if !path.Absolute { 186 if !path.HasComponents() && flags&linux.AT_EMPTY_PATH == 0 { 187 return 0, nil, linuxerr.ENOENT 188 } 189 if dirfd == linux.AT_FDCWD { 190 start = t.FSContext().WorkingDirectory() 191 defer start.DecRef(t) 192 } else { 193 dirfile := t.GetFile(dirfd) 194 if dirfile == nil { 195 return 0, nil, linuxerr.EBADF 196 } 197 if !path.HasComponents() { 198 // Use FileDescription.Stat() instead of 199 // VirtualFilesystem.StatAt() for statx(fd, ""), since the 200 // former may be able to use opened file state to expedite the 201 // Stat. 202 statx, err := dirfile.Stat(t, opts) 203 dirfile.DecRef(t) 204 if err != nil { 205 return 0, nil, err 206 } 207 userifyStatx(t, &statx) 208 _, err = statx.CopyOut(t, statxAddr) 209 return 0, nil, err 210 } 211 start = dirfile.VirtualDentry() 212 start.IncRef() 213 defer start.DecRef(t) 214 dirfile.DecRef(t) 215 } 216 } 217 218 statx, err := t.Kernel().VFS().StatAt(t, t.Credentials(), &vfs.PathOperation{ 219 Root: root, 220 Start: start, 221 Path: path, 222 FollowFinalSymlink: flags&linux.AT_SYMLINK_NOFOLLOW == 0, 223 }, &opts) 224 if err != nil { 225 return 0, nil, err 226 } 227 userifyStatx(t, &statx) 228 _, err = statx.CopyOut(t, statxAddr) 229 return 0, nil, err 230 } 231 232 func userifyStatx(t *kernel.Task, statx *linux.Statx) { 233 userns := t.UserNamespace() 234 statx.UID = uint32(auth.KUID(statx.UID).In(userns).OrOverflow()) 235 statx.GID = uint32(auth.KGID(statx.GID).In(userns).OrOverflow()) 236 } 237 238 // Statfs implements Linux syscall statfs(2). 239 func Statfs(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 240 pathAddr := args[0].Pointer() 241 bufAddr := args[1].Pointer() 242 243 path, err := copyInPath(t, pathAddr) 244 if err != nil { 245 return 0, nil, err 246 } 247 tpop, err := getTaskPathOperation(t, linux.AT_FDCWD, path, disallowEmptyPath, followFinalSymlink) 248 if err != nil { 249 return 0, nil, err 250 } 251 defer tpop.Release(t) 252 253 statfs, err := t.Kernel().VFS().StatFSAt(t, t.Credentials(), &tpop.pop) 254 if err != nil { 255 return 0, nil, err 256 } 257 _, err = statfs.CopyOut(t, bufAddr) 258 return 0, nil, err 259 } 260 261 // Fstatfs implements Linux syscall fstatfs(2). 262 func Fstatfs(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 263 fd := args[0].Int() 264 bufAddr := args[1].Pointer() 265 266 tpop, err := getTaskPathOperation(t, fd, fspath.Path{}, allowEmptyPath, nofollowFinalSymlink) 267 if err != nil { 268 return 0, nil, err 269 } 270 defer tpop.Release(t) 271 272 statfs, err := t.Kernel().VFS().StatFSAt(t, t.Credentials(), &tpop.pop) 273 if err != nil { 274 return 0, nil, err 275 } 276 _, err = statfs.CopyOut(t, bufAddr) 277 return 0, nil, err 278 }