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