//go:build linux package instanceexec import ( "errors" "os" "os/exec" "runtime" "testing" "golang.org/x/sys/unix" ) func TestPlan14ClaimGenerationDescriptorBoundary(t *testing.T) { if os.Getenv("PLAN14_CLAIM_GENERATION_CHILD") == "1" { runtime.LockOSThread() if err := ScopeClaimGeneration(); err != nil { t.Fatal(err) } for _, call := range []uintptr{unix.SYS_RECVMSG, unix.SYS_RECVMMSG, unix.SYS_PTRACE, unix.SYS_PIDFD_GETFD, unix.SYS_OPEN_BY_HANDLE_AT, unix.SYS_IO_URING_SETUP, unix.SYS_IO_URING_ENTER, unix.SYS_IO_URING_REGISTER, unix.SYS_SETNS, unix.SYS_UNSHARE} { _, _, err := unix.RawSyscall6(call, ^uintptr(0), 0, 0, 0, 0, 0) if err != unix.EPERM { t.Fatalf("syscall %d: %v; want EPERM", call, err) } } data, control := make([]byte, 1), make([]byte, unix.CmsgSpace(4)) if _, _, _, _, err := unix.Recvmsg(3, data, control, 0); !errors.Is(err, unix.EPERM) { t.Fatal("descriptor receipt permitted", err) } if n, err := unix.Read(3, data); err != nil || n != 1 || data[0] != 'x' { t.Fatal("ordinary socket read failed", n, err) } return } sockets, err := unix.Socketpair(unix.AF_UNIX, unix.SOCK_STREAM|unix.SOCK_CLOEXEC, 0) if err != nil { t.Fatal(err) } parent, child := os.NewFile(uintptr(sockets[0]), "parent"), os.NewFile(uintptr(sockets[1]), "child") defer parent.Close() defer child.Close() file, err := os.CreateTemp(t.TempDir(), "staged") if err != nil { t.Fatal(err) } defer file.Close() if err := unix.Sendmsg(int(parent.Fd()), []byte{'x'}, unix.UnixRights(int(file.Fd())), nil, 0); err != nil { t.Fatal(err) } cmd := exec.Command(os.Args[0], "-test.run=^TestPlan14ClaimGenerationDescriptorBoundary$") cmd.Env = append(os.Environ(), "PLAN14_CLAIM_GENERATION_CHILD=1") cmd.ExtraFiles = []*os.File{child} if out, err := cmd.CombinedOutput(); err != nil { t.Fatalf("boundary child: %v\n%s", err, out) } } func TestPlan14ClaimGenerationNamespaceBoundary(t *testing.T) { if os.Getenv("PLAN14_CLAIM_NAMESPACE_CHILD") == "1" { runtime.LockOSThread() if err := ScopeClaimGeneration(); err != nil { t.Fatal(err) } _, _, err := unix.RawSyscall6(unix.SYS_CLONE, uintptr(unix.CLONE_NEWUSER|unix.CLONE_THREAD), 0, 0, 0, 0, 0) if err != unix.EPERM { t.Fatal("namespace clone permitted", err) } _, _, err = unix.RawSyscall6(unix.SYS_CLONE3, 0, 0, 0, 0, 0, 0) if err != unix.ENOSYS { t.Fatal("clone3 permitted", err) } cmd := exec.Command("/bin/true") if out, err := cmd.CombinedOutput(); err != nil { t.Fatalf("ordinary fork/exec: %v %s", err, out) } return } cmd := exec.Command(os.Args[0], "-test.run=^TestPlan14ClaimGenerationNamespaceBoundary$") cmd.Env = append(os.Environ(), "PLAN14_CLAIM_NAMESPACE_CHILD=1") if out, err := cmd.CombinedOutput(); err != nil { t.Fatalf("namespace boundary: %v\n%s", err, out) } }