aboutsummaryrefslogtreecommitdiff
path: root/src/syscall/exec_linux_test.go
diff options
context:
space:
mode:
authorKir Kolyshkin <kolyshkin@gmail.com>2023-08-16 19:20:54 -0700
committerGopher Robot <gobot@golang.org>2023-09-07 19:11:15 +0000
commitda7ee57f40069eda3488b2e51dfa878bdd5816af (patch)
treed0830dc406737df376008d1ff52f684a66ed1039 /src/syscall/exec_linux_test.go
parent584d646559eb6c5942410f2ba2d2806f2627c2a2 (diff)
downloadgo-da7ee57f40069eda3488b2e51dfa878bdd5816af.tar.xz
syscall: add support to get pidfd from ForkExec on Linux
Add PidFD support, so that if the PidFD pointer in SysProcAttr is not nil, ForkExec (and thus all its users) obtains a pidfd from the kernel during clone(), and writes the result (or -1, if the functionality is not supported by the kernel) into *PidFD. The functionality to get pidfd is implemented for both clone3 and clone. For the latter, an extra argument to rawVforkSyscall is needed, thus the change in asm files. Add a trivial test case checking the obtained pidfd can be used to send a signal to a process, using pidfd_send_signal. To test clone3 code path, add a flag available to tests only. Updates #51246. Change-Id: I2212b69e1a657163c31b4a6245b076bc495777a3 Reviewed-on: https://go-review.googlesource.com/c/go/+/520266 Auto-Submit: Ian Lance Taylor <iant@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Cherry Mui <cherryyz@google.com> Reviewed-by: Ian Lance Taylor <iant@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Run-TryBot: Kirill Kolyshkin <kolyshkin@gmail.com>
Diffstat (limited to 'src/syscall/exec_linux_test.go')
-rw-r--r--src/syscall/exec_linux_test.go68
1 files changed, 68 insertions, 0 deletions
diff --git a/src/syscall/exec_linux_test.go b/src/syscall/exec_linux_test.go
index ca92a153f8..7883096b88 100644
--- a/src/syscall/exec_linux_test.go
+++ b/src/syscall/exec_linux_test.go
@@ -24,6 +24,7 @@ import (
"strings"
"syscall"
"testing"
+ "time"
"unsafe"
)
@@ -522,6 +523,73 @@ func TestCloneTimeNamespace(t *testing.T) {
}
}
+func testPidFD(t *testing.T) error {
+ testenv.MustHaveExec(t)
+
+ if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
+ // Child: wait for a signal.
+ time.Sleep(time.Hour)
+ }
+
+ exe, err := os.Executable()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var pidfd int
+ cmd := testenv.Command(t, exe, "-test.run=^TestPidFD$")
+ cmd.Env = append(cmd.Environ(), "GO_WANT_HELPER_PROCESS=1")
+ cmd.SysProcAttr = &syscall.SysProcAttr{
+ PidFD: &pidfd,
+ }
+ if err := cmd.Start(); err != nil {
+ return err
+ }
+ defer func() {
+ cmd.Process.Kill()
+ cmd.Wait()
+ }()
+ t.Log("got pidfd:", pidfd)
+ // If pidfd is not supported by the kernel, -1 is returned.
+ if pidfd == -1 {
+ t.Skip("pidfd not supported")
+ }
+ defer syscall.Close(pidfd)
+
+ // Use pidfd to send a signal to the child.
+ sig := syscall.SIGINT
+ if _, _, e := syscall.Syscall(syscall.Sys_pidfd_send_signal, uintptr(pidfd), uintptr(sig), 0); e != 0 {
+ if e != syscall.EINVAL && testenv.SyscallIsNotSupported(e) {
+ t.Skip("pidfd_send_signal syscall not supported:", e)
+ }
+ t.Fatal("pidfd_send_signal syscall failed:", e)
+ }
+ // Check if the child received our signal.
+ err = cmd.Wait()
+ if cmd.ProcessState == nil || cmd.ProcessState.Sys().(syscall.WaitStatus).Signal() != sig {
+ t.Fatal("unexpected child error:", err)
+ }
+ return nil
+}
+
+func TestPidFD(t *testing.T) {
+ if err := testPidFD(t); err != nil {
+ t.Fatal("can't start a process:", err)
+ }
+}
+
+func TestPidFDClone3(t *testing.T) {
+ *syscall.ForceClone3 = true
+ defer func() { *syscall.ForceClone3 = false }()
+
+ if err := testPidFD(t); err != nil {
+ if testenv.SyscallIsNotSupported(err) {
+ t.Skip("clone3 not supported:", err)
+ }
+ t.Fatal("can't start a process:", err)
+ }
+}
+
type capHeader struct {
version uint32
pid int32