func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) {
// Set up and fork. This returns immediately in the parent or
// if there's an error.
- upid, err, mapPipe, locked := forkAndExecInChild1(argv0, argv, envv, chroot, dir, attr, sys, pipe)
+ upid, pidfd, err, mapPipe, locked := forkAndExecInChild1(argv0, argv, envv, chroot, dir, attr, sys, pipe)
if locked {
runtime_AfterFork()
}
// parent; return PID
pid = int(upid)
+ if sys.PidFD != nil {
+ *sys.PidFD = int(pidfd)
+ }
if sys.UidMappings != nil || sys.GidMappings != nil {
Close(mapPipe[0])
//go:noinline
//go:norace
//go:nocheckptr
-func forkAndExecInChild1(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid uintptr, err1 Errno, mapPipe [2]int, locked bool) {
+func forkAndExecInChild1(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid uintptr, pidfd int32, err1 Errno, mapPipe [2]int, locked bool) {
// Defined in linux/prctl.h starting with Linux 4.3.
const (
PR_CAP_AMBIENT = 0x2f
uidmap, setgroups, gidmap []byte
clone3 *cloneArgs
pgrp int32
- pidfd _C_int = -1
dirfd int
cred *Credential
ngroups, groups uintptr
c uintptr
)
+ pidfd = -1
rlim := origRlimitNofile.Load()
// Fork succeeded, now in child.
- if sys.PidFD != nil {
- *sys.PidFD = int(pidfd)
- }
-
// Enable the "keep capabilities" flag to set ambient capabilities later.
if len(sys.AmbientCaps) > 0 {
_, _, err1 = RawSyscall6(SYS_PRCTL, PR_SET_KEEPCAPS, 1, 0, 0, 0, 0)
}
}
-func testPidFD(t *testing.T) error {
+func testPidFD(t *testing.T, userns bool) error {
testenv.MustHaveExec(t)
if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
cmd.SysProcAttr = &syscall.SysProcAttr{
PidFD: &pidfd,
}
+ if userns {
+ cmd.SysProcAttr.Cloneflags = syscall.CLONE_NEWUSER
+ }
if err := cmd.Start(); err != nil {
return err
}
}
func TestPidFD(t *testing.T) {
- if err := testPidFD(t); err != nil {
+ if err := testPidFD(t, false); err != nil {
+ t.Fatal("can't start a process:", err)
+ }
+}
+
+func TestPidFDWithUserNS(t *testing.T) {
+ if err := testPidFD(t, true); err != nil {
t.Fatal("can't start a process:", err)
}
}
*syscall.ForceClone3 = true
defer func() { *syscall.ForceClone3 = false }()
- if err := testPidFD(t); err != nil {
+ if err := testPidFD(t, false); err != nil {
if testenv.SyscallIsNotSupported(err) {
t.Skip("clone3 not supported:", err)
}