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