1
0
mirror of https://github.com/golang/go synced 2024-11-17 17:24:45 -07:00

syscall: fix getting pidfd when using CLONE_NEWUSER

While working on CL 528798, I found out that sys.PidFD field (added
in CL 520266) is not filled in when CLONE_NEWUSER is used.

This happens because the code assumed that the parent and the child
run in the same memory space. This assumption is right only when
CLONE_VM is used for clone syscall, and the code only sets CLONE_VM
when CLONE_NEWUSER is not used.

Fix this, and add a test case (which fails before the fix).

Updates #51246.

Change-Id: I805203c1369cadd63d769568b132a9ffd92cc184
Reviewed-on: https://go-review.googlesource.com/c/go/+/542698
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Auto-Submit: Michael Pratt <mpratt@google.com>
This commit is contained in:
Kir Kolyshkin 2023-11-16 00:42:04 -08:00 committed by Gopher Robot
parent cfb281754e
commit f7b2779086
2 changed files with 18 additions and 10 deletions

View File

@ -133,7 +133,7 @@ func runtime_AfterForkInChild()
func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) { 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 // Set up and fork. This returns immediately in the parent or
// if there's an error. // 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 { if locked {
runtime_AfterFork() runtime_AfterFork()
} }
@ -143,6 +143,9 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
// parent; return PID // parent; return PID
pid = int(upid) pid = int(upid)
if sys.PidFD != nil {
*sys.PidFD = int(pidfd)
}
if sys.UidMappings != nil || sys.GidMappings != nil { if sys.UidMappings != nil || sys.GidMappings != nil {
Close(mapPipe[0]) Close(mapPipe[0])
@ -210,7 +213,7 @@ type cloneArgs struct {
//go:noinline //go:noinline
//go:norace //go:norace
//go:nocheckptr //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. // Defined in linux/prctl.h starting with Linux 4.3.
const ( const (
PR_CAP_AMBIENT = 0x2f PR_CAP_AMBIENT = 0x2f
@ -241,12 +244,12 @@ func forkAndExecInChild1(argv0 *byte, argv, envv []*byte, chroot, dir *byte, att
uidmap, setgroups, gidmap []byte uidmap, setgroups, gidmap []byte
clone3 *cloneArgs clone3 *cloneArgs
pgrp int32 pgrp int32
pidfd _C_int = -1
dirfd int dirfd int
cred *Credential cred *Credential
ngroups, groups uintptr ngroups, groups uintptr
c uintptr c uintptr
) )
pidfd = -1
rlim := origRlimitNofile.Load() rlim := origRlimitNofile.Load()
@ -341,10 +344,6 @@ func forkAndExecInChild1(argv0 *byte, argv, envv []*byte, chroot, dir *byte, att
// Fork succeeded, now in child. // Fork succeeded, now in child.
if sys.PidFD != nil {
*sys.PidFD = int(pidfd)
}
// Enable the "keep capabilities" flag to set ambient capabilities later. // Enable the "keep capabilities" flag to set ambient capabilities later.
if len(sys.AmbientCaps) > 0 { if len(sys.AmbientCaps) > 0 {
_, _, err1 = RawSyscall6(SYS_PRCTL, PR_SET_KEEPCAPS, 1, 0, 0, 0, 0) _, _, err1 = RawSyscall6(SYS_PRCTL, PR_SET_KEEPCAPS, 1, 0, 0, 0, 0)

View File

@ -522,7 +522,7 @@ func TestCloneTimeNamespace(t *testing.T) {
} }
} }
func testPidFD(t *testing.T) error { func testPidFD(t *testing.T, userns bool) error {
testenv.MustHaveExec(t) testenv.MustHaveExec(t)
if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
@ -541,6 +541,9 @@ func testPidFD(t *testing.T) error {
cmd.SysProcAttr = &syscall.SysProcAttr{ cmd.SysProcAttr = &syscall.SysProcAttr{
PidFD: &pidfd, PidFD: &pidfd,
} }
if userns {
cmd.SysProcAttr.Cloneflags = syscall.CLONE_NEWUSER
}
if err := cmd.Start(); err != nil { if err := cmd.Start(); err != nil {
return err return err
} }
@ -572,7 +575,13 @@ func testPidFD(t *testing.T) error {
} }
func TestPidFD(t *testing.T) { 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) t.Fatal("can't start a process:", err)
} }
} }
@ -581,7 +590,7 @@ func TestPidFDClone3(t *testing.T) {
*syscall.ForceClone3 = true *syscall.ForceClone3 = true
defer func() { *syscall.ForceClone3 = false }() defer func() { *syscall.ForceClone3 = false }()
if err := testPidFD(t); err != nil { if err := testPidFD(t, false); err != nil {
if testenv.SyscallIsNotSupported(err) { if testenv.SyscallIsNotSupported(err) {
t.Skip("clone3 not supported:", err) t.Skip("clone3 not supported:", err)
} }