github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/sentry/syscalls/linux/sys_xattr.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 "bytes" 19 20 "github.com/nicocha30/gvisor-ligolo/pkg/abi/linux" 21 "github.com/nicocha30/gvisor-ligolo/pkg/errors/linuxerr" 22 "github.com/nicocha30/gvisor-ligolo/pkg/gohacks" 23 "github.com/nicocha30/gvisor-ligolo/pkg/hostarch" 24 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/arch" 25 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/kernel" 26 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/vfs" 27 ) 28 29 // ListXattr implements Linux syscall listxattr(2). 30 func ListXattr(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 31 return listxattr(t, args, followFinalSymlink) 32 } 33 34 // Llistxattr implements Linux syscall llistxattr(2). 35 func Llistxattr(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 36 return listxattr(t, args, nofollowFinalSymlink) 37 } 38 39 func listxattr(t *kernel.Task, args arch.SyscallArguments, shouldFollowFinalSymlink shouldFollowFinalSymlink) (uintptr, *kernel.SyscallControl, error) { 40 pathAddr := args[0].Pointer() 41 listAddr := args[1].Pointer() 42 size := args[2].SizeT() 43 44 path, err := copyInPath(t, pathAddr) 45 if err != nil { 46 return 0, nil, err 47 } 48 tpop, err := getTaskPathOperation(t, linux.AT_FDCWD, path, disallowEmptyPath, shouldFollowFinalSymlink) 49 if err != nil { 50 return 0, nil, err 51 } 52 defer tpop.Release(t) 53 54 names, err := t.Kernel().VFS().ListXattrAt(t, t.Credentials(), &tpop.pop, uint64(size)) 55 if err != nil { 56 return 0, nil, err 57 } 58 n, err := copyOutXattrNameList(t, listAddr, size, names) 59 if err != nil { 60 return 0, nil, err 61 } 62 return uintptr(n), nil, nil 63 } 64 65 // Flistxattr implements Linux syscall flistxattr(2). 66 func Flistxattr(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 67 fd := args[0].Int() 68 listAddr := args[1].Pointer() 69 size := args[2].SizeT() 70 71 file := t.GetFile(fd) 72 if file == nil { 73 return 0, nil, linuxerr.EBADF 74 } 75 defer file.DecRef(t) 76 77 names, err := file.ListXattr(t, uint64(size)) 78 if err != nil { 79 return 0, nil, err 80 } 81 n, err := copyOutXattrNameList(t, listAddr, size, names) 82 if err != nil { 83 return 0, nil, err 84 } 85 return uintptr(n), nil, nil 86 } 87 88 // GetXattr implements Linux syscall getxattr(2). 89 func GetXattr(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 90 return getxattr(t, args, followFinalSymlink) 91 } 92 93 // Lgetxattr implements Linux syscall lgetxattr(2). 94 func Lgetxattr(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 95 return getxattr(t, args, nofollowFinalSymlink) 96 } 97 98 func getxattr(t *kernel.Task, args arch.SyscallArguments, shouldFollowFinalSymlink shouldFollowFinalSymlink) (uintptr, *kernel.SyscallControl, error) { 99 pathAddr := args[0].Pointer() 100 nameAddr := args[1].Pointer() 101 valueAddr := args[2].Pointer() 102 size := args[3].SizeT() 103 104 path, err := copyInPath(t, pathAddr) 105 if err != nil { 106 return 0, nil, err 107 } 108 tpop, err := getTaskPathOperation(t, linux.AT_FDCWD, path, disallowEmptyPath, shouldFollowFinalSymlink) 109 if err != nil { 110 return 0, nil, err 111 } 112 defer tpop.Release(t) 113 114 name, err := copyInXattrName(t, nameAddr) 115 if err != nil { 116 return 0, nil, err 117 } 118 119 value, err := t.Kernel().VFS().GetXattrAt(t, t.Credentials(), &tpop.pop, &vfs.GetXattrOptions{ 120 Name: name, 121 Size: uint64(size), 122 }) 123 if err != nil { 124 return 0, nil, err 125 } 126 n, err := copyOutXattrValue(t, valueAddr, size, value) 127 if err != nil { 128 return 0, nil, err 129 } 130 return uintptr(n), nil, nil 131 } 132 133 // Fgetxattr implements Linux syscall fgetxattr(2). 134 func Fgetxattr(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 135 fd := args[0].Int() 136 nameAddr := args[1].Pointer() 137 valueAddr := args[2].Pointer() 138 size := args[3].SizeT() 139 140 file := t.GetFile(fd) 141 if file == nil { 142 return 0, nil, linuxerr.EBADF 143 } 144 defer file.DecRef(t) 145 146 name, err := copyInXattrName(t, nameAddr) 147 if err != nil { 148 return 0, nil, err 149 } 150 151 value, err := file.GetXattr(t, &vfs.GetXattrOptions{Name: name, Size: uint64(size)}) 152 if err != nil { 153 return 0, nil, err 154 } 155 n, err := copyOutXattrValue(t, valueAddr, size, value) 156 if err != nil { 157 return 0, nil, err 158 } 159 return uintptr(n), nil, nil 160 } 161 162 // SetXattr implements Linux syscall setxattr(2). 163 func SetXattr(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 164 return 0, nil, setxattr(t, args, followFinalSymlink) 165 } 166 167 // Lsetxattr implements Linux syscall lsetxattr(2). 168 func Lsetxattr(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 169 return 0, nil, setxattr(t, args, nofollowFinalSymlink) 170 } 171 172 func setxattr(t *kernel.Task, args arch.SyscallArguments, shouldFollowFinalSymlink shouldFollowFinalSymlink) error { 173 pathAddr := args[0].Pointer() 174 nameAddr := args[1].Pointer() 175 valueAddr := args[2].Pointer() 176 size := args[3].SizeT() 177 flags := args[4].Int() 178 179 if flags&^(linux.XATTR_CREATE|linux.XATTR_REPLACE) != 0 { 180 return linuxerr.EINVAL 181 } 182 183 path, err := copyInPath(t, pathAddr) 184 if err != nil { 185 return err 186 } 187 tpop, err := getTaskPathOperation(t, linux.AT_FDCWD, path, disallowEmptyPath, shouldFollowFinalSymlink) 188 if err != nil { 189 return err 190 } 191 defer tpop.Release(t) 192 193 name, err := copyInXattrName(t, nameAddr) 194 if err != nil { 195 return err 196 } 197 value, err := copyInXattrValue(t, valueAddr, size) 198 if err != nil { 199 return err 200 } 201 202 return t.Kernel().VFS().SetXattrAt(t, t.Credentials(), &tpop.pop, &vfs.SetXattrOptions{ 203 Name: name, 204 Value: value, 205 Flags: uint32(flags), 206 }) 207 } 208 209 // Fsetxattr implements Linux syscall fsetxattr(2). 210 func Fsetxattr(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 211 fd := args[0].Int() 212 nameAddr := args[1].Pointer() 213 valueAddr := args[2].Pointer() 214 size := args[3].SizeT() 215 flags := args[4].Int() 216 217 if flags&^(linux.XATTR_CREATE|linux.XATTR_REPLACE) != 0 { 218 return 0, nil, linuxerr.EINVAL 219 } 220 221 file := t.GetFile(fd) 222 if file == nil { 223 return 0, nil, linuxerr.EBADF 224 } 225 defer file.DecRef(t) 226 227 name, err := copyInXattrName(t, nameAddr) 228 if err != nil { 229 return 0, nil, err 230 } 231 value, err := copyInXattrValue(t, valueAddr, size) 232 if err != nil { 233 return 0, nil, err 234 } 235 236 return 0, nil, file.SetXattr(t, &vfs.SetXattrOptions{ 237 Name: name, 238 Value: value, 239 Flags: uint32(flags), 240 }) 241 } 242 243 // RemoveXattr implements Linux syscall removexattr(2). 244 func RemoveXattr(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 245 return 0, nil, removexattr(t, args, followFinalSymlink) 246 } 247 248 // Lremovexattr implements Linux syscall lremovexattr(2). 249 func Lremovexattr(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 250 return 0, nil, removexattr(t, args, nofollowFinalSymlink) 251 } 252 253 func removexattr(t *kernel.Task, args arch.SyscallArguments, shouldFollowFinalSymlink shouldFollowFinalSymlink) error { 254 pathAddr := args[0].Pointer() 255 nameAddr := args[1].Pointer() 256 257 path, err := copyInPath(t, pathAddr) 258 if err != nil { 259 return err 260 } 261 tpop, err := getTaskPathOperation(t, linux.AT_FDCWD, path, disallowEmptyPath, shouldFollowFinalSymlink) 262 if err != nil { 263 return err 264 } 265 defer tpop.Release(t) 266 267 name, err := copyInXattrName(t, nameAddr) 268 if err != nil { 269 return err 270 } 271 272 return t.Kernel().VFS().RemoveXattrAt(t, t.Credentials(), &tpop.pop, name) 273 } 274 275 // Fremovexattr implements Linux syscall fremovexattr(2). 276 func Fremovexattr(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 277 fd := args[0].Int() 278 nameAddr := args[1].Pointer() 279 280 file := t.GetFile(fd) 281 if file == nil { 282 return 0, nil, linuxerr.EBADF 283 } 284 defer file.DecRef(t) 285 286 name, err := copyInXattrName(t, nameAddr) 287 if err != nil { 288 return 0, nil, err 289 } 290 291 return 0, nil, file.RemoveXattr(t, name) 292 } 293 294 func copyInXattrName(t *kernel.Task, nameAddr hostarch.Addr) (string, error) { 295 name, err := t.CopyInString(nameAddr, linux.XATTR_NAME_MAX+1) 296 if err != nil { 297 if linuxerr.Equals(linuxerr.ENAMETOOLONG, err) { 298 return "", linuxerr.ERANGE 299 } 300 return "", err 301 } 302 if len(name) == 0 { 303 return "", linuxerr.ERANGE 304 } 305 return name, nil 306 } 307 308 func copyOutXattrNameList(t *kernel.Task, listAddr hostarch.Addr, size uint, names []string) (int, error) { 309 if size > linux.XATTR_LIST_MAX { 310 size = linux.XATTR_LIST_MAX 311 } 312 var buf bytes.Buffer 313 for _, name := range names { 314 buf.WriteString(name) 315 buf.WriteByte(0) 316 } 317 if size == 0 { 318 // Return the size that would be required to accommodate the list. 319 return buf.Len(), nil 320 } 321 if buf.Len() > int(size) { 322 if size >= linux.XATTR_LIST_MAX { 323 return 0, linuxerr.E2BIG 324 } 325 return 0, linuxerr.ERANGE 326 } 327 return t.CopyOutBytes(listAddr, buf.Bytes()) 328 } 329 330 func copyInXattrValue(t *kernel.Task, valueAddr hostarch.Addr, size uint) (string, error) { 331 if size > linux.XATTR_SIZE_MAX { 332 return "", linuxerr.E2BIG 333 } 334 buf := make([]byte, size) 335 if _, err := t.CopyInBytes(valueAddr, buf); err != nil { 336 return "", err 337 } 338 return gohacks.StringFromImmutableBytes(buf), nil 339 } 340 341 func copyOutXattrValue(t *kernel.Task, valueAddr hostarch.Addr, size uint, value string) (int, error) { 342 if size > linux.XATTR_SIZE_MAX { 343 size = linux.XATTR_SIZE_MAX 344 } 345 if size == 0 { 346 // Return the size that would be required to accommodate the value. 347 return len(value), nil 348 } 349 if len(value) > int(size) { 350 if size >= linux.XATTR_SIZE_MAX { 351 return 0, linuxerr.E2BIG 352 } 353 return 0, linuxerr.ERANGE 354 } 355 return t.CopyOutBytes(valueAddr, gohacks.ImmutableBytesFromString(value)) 356 }