OpenTree implements Linux syscall open_tree(2).
(t *kernel.Task, sysno uintptr, args arch.SyscallArguments)
| 293 | |
| 294 | // OpenTree implements Linux syscall open_tree(2). |
| 295 | func OpenTree(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { |
| 296 | dirfd := args[0].Int() |
| 297 | fromAddr := args[1].Pointer() |
| 298 | flags := args[2].Uint() |
| 299 | |
| 300 | // TODO(b/270247637): gVisor does not yet support automount, so |
| 301 | // AT_NO_AUTOMOUNT flag is a no-op. |
| 302 | flags &= ^(uint32(linux.AT_NO_AUTOMOUNT)) |
| 303 | |
| 304 | if flags&^(linux.AT_EMPTY_PATH|linux.AT_SYMLINK_NOFOLLOW|linux.OPEN_TREE_CLOEXEC|linux.OPEN_TREE_CLONE|linux.AT_RECURSIVE) != 0 { |
| 305 | return 0, nil, linuxerr.EINVAL |
| 306 | } |
| 307 | |
| 308 | recursive := flags&linux.AT_RECURSIVE == linux.AT_RECURSIVE |
| 309 | clone := flags&linux.OPEN_TREE_CLONE == linux.OPEN_TREE_CLONE |
| 310 | noFollow := flags&linux.AT_SYMLINK_NOFOLLOW == linux.AT_SYMLINK_NOFOLLOW |
| 311 | emptyPath := flags&linux.AT_EMPTY_PATH == linux.AT_EMPTY_PATH |
| 312 | closeOnExec := flags&linux.OPEN_TREE_CLOEXEC == linux.OPEN_TREE_CLOEXEC |
| 313 | |
| 314 | // AT_RECURSIVE requires OPEN_TREE_CLONE |
| 315 | if recursive && !clone { |
| 316 | return 0, nil, linuxerr.EINVAL |
| 317 | } |
| 318 | |
| 319 | // OPEN_TREE_CLONE: Must have CAP_SYS_ADMIN in the current mount namespace's |
| 320 | // associated user namespace. |
| 321 | creds := t.Credentials() |
| 322 | if clone && !creds.HasCapabilityIn(linux.CAP_SYS_ADMIN, t.MountNamespace().Owner) { |
| 323 | return 0, nil, linuxerr.EPERM |
| 324 | } |
| 325 | |
| 326 | // Lookup the specified path |
| 327 | fromPath, err := copyInPath(t, fromAddr) |
| 328 | if err != nil { |
| 329 | return 0, nil, err |
| 330 | } |
| 331 | from, err := getTaskPathOperation(t, dirfd, fromPath, shouldAllowEmptyPath(emptyPath), shouldFollowFinalSymlink(!noFollow)) |
| 332 | if err != nil { |
| 333 | return 0, nil, err |
| 334 | } |
| 335 | defer from.Release(t) |
| 336 | |
| 337 | vfsObj := t.Kernel().VFS() |
| 338 | |
| 339 | if clone { |
| 340 | // OPEN_TREE_CLONE: clone the mount tree into an anonymous mount ns |
| 341 | |
| 342 | // Fetch the path's mount vd |
| 343 | fromVd, err := vfsObj.GetDentryAt(t, t.Credentials(), &from.pop, &vfs.GetDentryOptions{CheckSearchable: true}) |
| 344 | if err != nil { |
| 345 | return 0, nil, err |
| 346 | } |
| 347 | defer fromVd.DecRef(t) |
| 348 | |
| 349 | // Clone the mount (or the mount tree, depending on AT_RECURSIVE) into a new anonymous NS |
| 350 | anonNS, err := vfsObj.CloneTreeToAnonNS(t, t.MountNamespace(), fromVd, t.Kernel(), recursive) |
| 351 | if err != nil { |
| 352 | return 0, nil, err |
nothing calls this directly
no test coverage detected
searching dependent graphs…