]> Cypherpunks.ru repositories - gostls13.git/commitdiff
syscall: add support to get pidfd from ForkExec on Linux
authorKir Kolyshkin <kolyshkin@gmail.com>
Thu, 17 Aug 2023 02:20:54 +0000 (19:20 -0700)
committerGopher Robot <gobot@golang.org>
Thu, 7 Sep 2023 19:11:15 +0000 (19:11 +0000)
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>

25 files changed:
api/next/51246.txt [new file with mode: 0644]
src/syscall/asm_linux_386.s
src/syscall/asm_linux_amd64.s
src/syscall/asm_linux_arm.s
src/syscall/asm_linux_arm64.s
src/syscall/asm_linux_loong64.s
src/syscall/asm_linux_mips64x.s
src/syscall/asm_linux_mipsx.s
src/syscall/asm_linux_ppc64x.s
src/syscall/asm_linux_riscv64.s
src/syscall/asm_linux_s390x.s
src/syscall/exec_linux.go
src/syscall/exec_linux_test.go
src/syscall/export_linux_test.go
src/syscall/syscall_linux.go
src/syscall/syscall_linux_386.go
src/syscall/syscall_linux_amd64.go
src/syscall/syscall_linux_arm.go
src/syscall/syscall_linux_arm64.go
src/syscall/syscall_linux_loong64.go
src/syscall/syscall_linux_mips64x.go
src/syscall/syscall_linux_mipsx.go
src/syscall/syscall_linux_ppc64x.go
src/syscall/syscall_linux_riscv64.go
src/syscall/syscall_linux_s390x.go

diff --git a/api/next/51246.txt b/api/next/51246.txt
new file mode 100644 (file)
index 0000000..c8806c6
--- /dev/null
@@ -0,0 +1,6 @@
+pkg syscall (linux-386), type SysProcAttr struct, PidFD *int #51246
+pkg syscall (linux-386-cgo), type SysProcAttr struct, PidFD *int #51246
+pkg syscall (linux-amd64), type SysProcAttr struct, PidFD *int #51246
+pkg syscall (linux-amd64-cgo), type SysProcAttr struct, PidFD *int #51246
+pkg syscall (linux-arm), type SysProcAttr struct, PidFD *int #51246
+pkg syscall (linux-arm-cgo), type SysProcAttr struct, PidFD *int #51246
index a8e63f70798afd3359859680f99eca06f1c27fb9..d14df50a0ae348a8b60e8c4f48aff2c823945e65 100644 (file)
 // instead of the glibc-specific "CALL 0x10(GS)".
 #define INVOKE_SYSCALL INT     $0x80
 
-// func rawVforkSyscall(trap, a1, a2 uintptr) (r1, err uintptr)
-TEXT ·rawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-20
+// func rawVforkSyscall(trap, a1, a2, a3 uintptr) (r1, err uintptr)
+TEXT ·rawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-24
        MOVL    trap+0(FP), AX  // syscall entry
        MOVL    a1+4(FP), BX
        MOVL    a2+8(FP), CX
-       MOVL    $0, DX
+       MOVL    a3+12(FP), DX
        POPL    SI // preserve return address
        INVOKE_SYSCALL
        PUSHL   SI
        CMPL    AX, $0xfffff001
        JLS     ok
-       MOVL    $-1, r1+12(FP)
+       MOVL    $-1, r1+16(FP)
        NEGL    AX
-       MOVL    AX, err+16(FP)
+       MOVL    AX, err+20(FP)
        RET
 ok:
-       MOVL    AX, r1+12(FP)
-       MOVL    $0, err+16(FP)
+       MOVL    AX, r1+16(FP)
+       MOVL    $0, err+20(FP)
        RET
 
 // func rawSyscallNoError(trap uintptr, a1, a2, a3 uintptr) (r1, r2 uintptr);
index 00d6fedc62b77591049be169f5e8fc24550deb99..da170c52ed92ec88ebed1ec13ea0a897d44dccac 100644 (file)
 
 #define SYS_gettimeofday 96
 
-// func rawVforkSyscall(trap, a1, a2 uintptr) (r1, err uintptr)
-TEXT ·rawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-40
+// func rawVforkSyscall(trap, a1, a2, a3 uintptr) (r1, err uintptr)
+TEXT ·rawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-48
        MOVQ    a1+8(FP), DI
        MOVQ    a2+16(FP), SI
-       MOVQ    $0, DX
+       MOVQ    a3+24(FP), DX
        MOVQ    $0, R10
        MOVQ    $0, R8
        MOVQ    $0, R9
@@ -25,13 +25,13 @@ TEXT ·rawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-40
        PUSHQ   R12
        CMPQ    AX, $0xfffffffffffff001
        JLS     ok2
-       MOVQ    $-1, r1+24(FP)
+       MOVQ    $-1, r1+32(FP)
        NEGQ    AX
-       MOVQ    AX, err+32(FP)
+       MOVQ    AX, err+40(FP)
        RET
 ok2:
-       MOVQ    AX, r1+24(FP)
-       MOVQ    $0, err+32(FP)
+       MOVQ    AX, r1+32(FP)
+       MOVQ    $0, err+40(FP)
        RET
 
 // func rawSyscallNoError(trap, a1, a2, a3 uintptr) (r1, r2 uintptr)
index d3995416c22e8c766dad8971d03d01476d4fd6ac..06a35b55cb14b6301409b572b06ee2bf2a7088ce 100644 (file)
@@ -41,25 +41,25 @@ okseek:
        BL      runtime·exitsyscall(SB)
        RET
 
-// func rawVforkSyscall(trap, a1, a2 uintptr) (r1, err uintptr)
-TEXT ·rawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-20
+// func rawVforkSyscall(trap, a1, a2, a3 uintptr) (r1, err uintptr)
+TEXT ·rawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-24
        MOVW    trap+0(FP), R7  // syscall entry
        MOVW    a1+4(FP), R0
        MOVW    a2+8(FP), R1
-       MOVW    $0, R2
+       MOVW    a3+12(FP), R2
        SWI     $0
        MOVW    $0xfffff001, R1
        CMP     R1, R0
        BLS     ok
        MOVW    $-1, R1
-       MOVW    R1, r1+12(FP)
+       MOVW    R1, r1+16(FP)
        RSB     $0, R0, R0
-       MOVW    R0, err+16(FP)
+       MOVW    R0, err+20(FP)
        RET
 ok:
-       MOVW    R0, r1+12(FP)
+       MOVW    R0, r1+16(FP)
        MOVW    $0, R0
-       MOVW    R0, err+16(FP)
+       MOVW    R0, err+20(FP)
        RET
 
 // func rawSyscallNoError(trap uintptr, a1, a2, a3 uintptr) (r1, r2 uintptr);
index 7fa789a349daa771b08ba52730d913a7d5c4a69d..883645f9757853382c016ce97e3cf184d3a929c7 100644 (file)
@@ -4,11 +4,11 @@
 
 #include "textflag.h"
 
-// func rawVforkSyscall(trap, a1, a2 uintptr) (r1, err uintptr)
-TEXT ·rawVforkSyscall(SB),NOSPLIT,$0-40
+// func rawVforkSyscall(trap, a1, a2, a3 uintptr) (r1, err uintptr)
+TEXT ·rawVforkSyscall(SB),NOSPLIT,$0-48
        MOVD    a1+8(FP), R0
        MOVD    a2+16(FP), R1
-       MOVD    $0, R2
+       MOVD    a3+24(FP), R2
        MOVD    $0, R3
        MOVD    $0, R4
        MOVD    $0, R5
@@ -17,13 +17,13 @@ TEXT ·rawVforkSyscall(SB),NOSPLIT,$0-40
        CMN     $4095, R0
        BCC     ok
        MOVD    $-1, R4
-       MOVD    R4, r1+24(FP)   // r1
+       MOVD    R4, r1+32(FP)   // r1
        NEG     R0, R0
-       MOVD    R0, err+32(FP)  // errno
+       MOVD    R0, err+40(FP)  // errno
        RET
 ok:
-       MOVD    R0, r1+24(FP)   // r1
-       MOVD    ZR, err+32(FP)  // errno
+       MOVD    R0, r1+32(FP)   // r1
+       MOVD    ZR, err+40(FP)  // errno
        RET
 
 // func rawSyscallNoError(trap uintptr, a1, a2, a3 uintptr) (r1, r2 uintptr);
index 1a7457c7ead893f7ec29e9ea9a91040e22a10163..2bbf0f1df12ffe59233f454901b72892cb57df93 100644 (file)
@@ -8,11 +8,11 @@
 // System calls for loong64, Linux
 //
 
-// func rawVforkSyscall(trap, a1, a2 uintptr) (r1, err uintptr)
-TEXT ·rawVforkSyscall(SB),NOSPLIT,$0-40
+// func rawVforkSyscall(trap, a1, a2, a3 uintptr) (r1, err uintptr)
+TEXT ·rawVforkSyscall(SB),NOSPLIT,$0-48
        MOVV    a1+8(FP), R4
        MOVV    a2+16(FP), R5
-       MOVV    $0, R6
+       MOVV    a3+24(FP), R6
        MOVV    $0, R7
        MOVV    $0, R8
        MOVV    $0, R9
@@ -21,13 +21,13 @@ TEXT ·rawVforkSyscall(SB),NOSPLIT,$0-40
        MOVW    $-4096, R12
        BGEU    R12, R4, ok
        MOVV    $-1, R12
-       MOVV    R12, r1+24(FP)          // r1
+       MOVV    R12, r1+32(FP)  // r1
        SUBVU   R4, R0, R4
-       MOVV    R4, err+32(FP)          // errno
+       MOVV    R4, err+40(FP)  // errno
        RET
 ok:
-       MOVV    R4, r1+24(FP)   // r1
-       MOVV    R0, err+32(FP)  // errno
+       MOVV    R4, r1+32(FP)   // r1
+       MOVV    R0, err+40(FP)  // errno
        RET
 
 TEXT ·rawSyscallNoError(SB),NOSPLIT,$0-48
index 6c7a6bc16fbf3b989ac8cf59a1ee6b6f390edba6..1784e3a57a442df863fb126e8d167a1254fb7665 100644 (file)
 // System calls for mips64, Linux
 //
 
-// func rawVforkSyscall(trap, a1, a2 uintptr) (r1, err uintptr)
-TEXT ·rawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-40
+// func rawVforkSyscall(trap, a1, a2, a3 uintptr) (r1, err uintptr)
+TEXT ·rawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-48
        MOVV    a1+8(FP), R4
        MOVV    a2+16(FP), R5
-       MOVV    R0, R6
+       MOVV    a3+24(FP), R6
        MOVV    R0, R7
        MOVV    R0, R8
        MOVV    R0, R9
@@ -22,12 +22,12 @@ TEXT ·rawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-40
        SYSCALL
        BEQ     R7, ok
        MOVV    $-1, R1
-       MOVV    R1, r1+24(FP)   // r1
-       MOVV    R2, err+32(FP)  // errno
+       MOVV    R1, r1+32(FP)   // r1
+       MOVV    R2, err+40(FP)  // errno
        RET
 ok:
-       MOVV    R2, r1+24(FP)   // r1
-       MOVV    R0, err+32(FP)  // errno
+       MOVV    R2, r1+32(FP)   // r1
+       MOVV    R0, err+40(FP)  // errno
        RET
 
 TEXT ·rawSyscallNoError(SB),NOSPLIT,$0-48
index 99f0154d1bb4f92e97a19ac2cc0810dc5adabba8..7544abbd48068055d299c503977840dfabce774d 100644 (file)
@@ -45,21 +45,21 @@ ok9:
        JAL     runtime·exitsyscall(SB)
        RET
 
-// func rawVforkSyscall(trap, a1, a2 uintptr) (r1, err uintptr)
-TEXT ·rawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-20
+// func rawVforkSyscall(trap, a1, a2, a3 uintptr) (r1, err uintptr)
+TEXT ·rawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-24
        MOVW    a1+4(FP), R4
        MOVW    a2+8(FP), R5
-       MOVW    R0, R6
+       MOVW    a3+12(FP), R6
        MOVW    trap+0(FP), R2  // syscall entry
        SYSCALL
        BEQ     R7, ok
        MOVW    $-1, R1
-       MOVW    R1, r1+12(FP)   // r1
-       MOVW    R2, err+16(FP)  // errno
+       MOVW    R1, r1+16(FP)   // r1
+       MOVW    R2, err+20(FP)  // errno
        RET
 ok:
-       MOVW    R2, r1+12(FP)   // r1
-       MOVW    R0, err+16(FP)  // errno
+       MOVW    R2, r1+16(FP)   // r1
+       MOVW    R0, err+20(FP)  // errno
        RET
 
 TEXT ·rawSyscallNoError(SB),NOSPLIT,$20-24
index b9412fec1d418d4e89fedcd1cff9f87794b5aea1..6c29868f2962afc0643739ae5646804f63633d9a 100644 (file)
 // System calls for ppc64, Linux
 //
 
-// func rawVforkSyscall(trap, a1, a2 uintptr) (r1, err uintptr)
-TEXT ·rawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-40
+// func rawVforkSyscall(trap, a1, a2, a3 uintptr) (r1, err uintptr)
+TEXT ·rawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-48
        MOVD    a1+8(FP), R3
        MOVD    a2+16(FP), R4
-       MOVD    R0, R5
+       MOVD    a3+24(FP), R5
        MOVD    R0, R6
        MOVD    R0, R7
        MOVD    R0, R8
@@ -22,12 +22,12 @@ TEXT ·rawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-40
        SYSCALL R9
        BVC     ok
        MOVD    $-1, R4
-       MOVD    R4, r1+24(FP)   // r1
-       MOVD    R3, err+32(FP)  // errno
+       MOVD    R4, r1+32(FP)   // r1
+       MOVD    R3, err+40(FP)  // errno
        RET
 ok:
-       MOVD    R3, r1+24(FP)   // r1
-       MOVD    R0, err+32(FP)  // errno
+       MOVD    R3, r1+32(FP)   // r1
+       MOVD    R0, err+40(FP)  // errno
        RET
 
 TEXT ·rawSyscallNoError(SB),NOSPLIT,$0-48
index 6fd09ec4222a93ddf4355b10ab03b70e499f6b98..0386b36384a3259891abf904ee990060e04bc463 100644 (file)
@@ -8,11 +8,11 @@
 // System calls for riscv64, Linux
 //
 
-// func rawVforkSyscall(trap, a1, a2 uintptr) (r1, err uintptr)
-TEXT ·rawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-40
+// func rawVforkSyscall(trap, a1, a2, a3 uintptr) (r1, err uintptr)
+TEXT ·rawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-48
        MOV     a1+8(FP), A0
        MOV     a2+16(FP), A1
-       MOV     ZERO, A2
+       MOV     a3+24(FP), A2
        MOV     ZERO, A3
        MOV     ZERO, A4
        MOV     ZERO, A5
@@ -20,14 +20,14 @@ TEXT ·rawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-40
        ECALL
        MOV     $-4096, T0
        BLTU    T0, A0, err
-       MOV     A0, r1+24(FP)   // r1
-       MOV     ZERO, err+32(FP)        // errno
+       MOV     A0, r1+32(FP)   // r1
+       MOV     ZERO, err+40(FP)        // errno
        RET
 err:
        MOV     $-1, T0
-       MOV     T0, r1+24(FP)   // r1
+       MOV     T0, r1+32(FP)   // r1
        SUB     A0, ZERO, A0
-       MOV     A0, err+32(FP)  // errno
+       MOV     A0, err+40(FP)  // errno
        RET
 
 TEXT ·rawSyscallNoError(SB),NOSPLIT,$0-48
index 41c34b1e178e267bf0c87e48ddf71954b445f202..e76b1e30821d0ce46fbaf8a743c887c95b9815cc 100644 (file)
@@ -8,11 +8,11 @@
 // System calls for s390x, Linux
 //
 
-// func rawVforkSyscall(trap, a1, a2 uintptr) (r1, err uintptr)
-TEXT ·rawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-40
+// func rawVforkSyscall(trap, a1, a2, a3 uintptr) (r1, err uintptr)
+TEXT ·rawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-48
        MOVD    a1+8(FP), R2
        MOVD    a2+16(FP), R3
-       MOVD    $0, R4
+       MOVD    a3+24(FP), R4
        MOVD    $0, R5
        MOVD    $0, R6
        MOVD    $0, R7
@@ -20,13 +20,13 @@ TEXT ·rawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-40
        SYSCALL
        MOVD    $0xfffffffffffff001, R8
        CMPUBLT R2, R8, ok2
-       MOVD    $-1, r1+24(FP)
+       MOVD    $-1, r1+32(FP)
        NEG     R2, R2
-       MOVD    R2, err+32(FP)  // errno
+       MOVD    R2, err+40(FP)  // errno
        RET
 ok2:
-       MOVD    R2, r1+24(FP)
-       MOVD    $0, err+32(FP)  // errno
+       MOVD    R2, r1+32(FP)
+       MOVD    $0, err+40(FP)  // errno
        RET
 
 // func rawSyscallNoError(trap, a1, a2, a3 uintptr) (r1, r2 uintptr)
index dfbb38ac1678c74275085a00149c73b1c8a9bb86..791b263b2a906a92e0e55de2b9fe23b8a2cb6dbd 100644 (file)
@@ -101,11 +101,17 @@ type SysProcAttr struct {
        AmbientCaps                []uintptr // Ambient capabilities (Linux only)
        UseCgroupFD                bool      // Whether to make use of the CgroupFD field.
        CgroupFD                   int       // File descriptor of a cgroup to put the new process into.
+       // PidFD, if not nil, is used to store the pidfd of a child, if the
+       // functionality is supported by the kernel, or -1. Note *PidFD is
+       // changed only if the process starts successfully.
+       PidFD *int
 }
 
 var (
        none  = [...]byte{'n', 'o', 'n', 'e', 0}
        slash = [...]byte{'/', 0}
+
+       forceClone3 = false // Used by unit tests only.
 )
 
 // Implemented in runtime package.
@@ -235,6 +241,7 @@ func forkAndExecInChild1(argv0 *byte, argv, envv []*byte, chroot, dir *byte, att
                uidmap, setgroups, gidmap []byte
                clone3                    *cloneArgs
                pgrp                      int32
+               pidfd                     _C_int = -1
                dirfd                     int
                cred                      *Credential
                ngroups, groups           uintptr
@@ -289,18 +296,22 @@ func forkAndExecInChild1(argv0 *byte, argv, envv []*byte, chroot, dir *byte, att
        if sys.Cloneflags&CLONE_NEWUSER == 0 && sys.Unshareflags&CLONE_NEWUSER == 0 {
                flags |= CLONE_VFORK | CLONE_VM
        }
+       if sys.PidFD != nil {
+               flags |= CLONE_PIDFD
+       }
        // Whether to use clone3.
-       if sys.UseCgroupFD {
-               clone3 = &cloneArgs{
-                       flags:      uint64(flags) | CLONE_INTO_CGROUP,
-                       exitSignal: uint64(SIGCHLD),
-                       cgroup:     uint64(sys.CgroupFD),
-               }
-       } else if flags&CLONE_NEWTIME != 0 {
+       if sys.UseCgroupFD || flags&CLONE_NEWTIME != 0 || forceClone3 {
                clone3 = &cloneArgs{
                        flags:      uint64(flags),
                        exitSignal: uint64(SIGCHLD),
                }
+               if sys.UseCgroupFD {
+                       clone3.flags |= CLONE_INTO_CGROUP
+                       clone3.cgroup = uint64(sys.CgroupFD)
+               }
+               if sys.PidFD != nil {
+                       clone3.pidFD = uint64(uintptr(unsafe.Pointer(&pidfd)))
+               }
        }
 
        // About to call fork.
@@ -308,14 +319,14 @@ func forkAndExecInChild1(argv0 *byte, argv, envv []*byte, chroot, dir *byte, att
        runtime_BeforeFork()
        locked = true
        if clone3 != nil {
-               pid, err1 = rawVforkSyscall(_SYS_clone3, uintptr(unsafe.Pointer(clone3)), unsafe.Sizeof(*clone3))
+               pid, err1 = rawVforkSyscall(_SYS_clone3, uintptr(unsafe.Pointer(clone3)), unsafe.Sizeof(*clone3), 0)
        } else {
                flags |= uintptr(SIGCHLD)
                if runtime.GOARCH == "s390x" {
                        // On Linux/s390, the first two arguments of clone(2) are swapped.
-                       pid, err1 = rawVforkSyscall(SYS_CLONE, 0, flags)
+                       pid, err1 = rawVforkSyscall(SYS_CLONE, 0, flags, uintptr(unsafe.Pointer(&pidfd)))
                } else {
-                       pid, err1 = rawVforkSyscall(SYS_CLONE, flags, 0)
+                       pid, err1 = rawVforkSyscall(SYS_CLONE, flags, 0, uintptr(unsafe.Pointer(&pidfd)))
                }
        }
        if err1 != 0 || pid != 0 {
@@ -330,6 +341,10 @@ func forkAndExecInChild1(argv0 *byte, argv, envv []*byte, chroot, dir *byte, att
 
        // 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)
index ca92a153f863624f9585a73e6f43ed47c31846b5..7883096b888814c5c13a2cb6466490756012d418 100644 (file)
@@ -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
index 274849e2ea2b34dc80a2dfd40f68459df263ef5f..a09db6075308880f00b233ad4a9971263c11b4a7 100644 (file)
@@ -4,6 +4,12 @@
 
 package syscall
 
-var RawSyscallNoError = rawSyscallNoError
+var (
+       RawSyscallNoError = rawSyscallNoError
+       ForceClone3       = &forceClone3
+)
 
-const Sys_GETEUID = sys_GETEUID
+const (
+       Sys_GETEUID           = sys_GETEUID
+       Sys_pidfd_send_signal = _SYS_pidfd_send_signal
+)
index 8b0a57b5020ef1a85281fcfecfc2808003863e9c..e012c1b9437a2c32cf020e120d630ea3efacb0ca 100644 (file)
@@ -95,7 +95,7 @@ func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
 }
 
 func rawSyscallNoError(trap, a1, a2, a3 uintptr) (r1, r2 uintptr)
-func rawVforkSyscall(trap, a1, a2 uintptr) (r1 uintptr, err Errno)
+func rawVforkSyscall(trap, a1, a2, a3 uintptr) (r1 uintptr, err Errno)
 
 /*
  * Wrapped
index 9cbd9ac9f03113b34b280f9c2c97b21054dda77c..f9d47236e57fdd349d66b016a100bb96dc55c6a1 100644 (file)
@@ -7,9 +7,10 @@ package syscall
 import "unsafe"
 
 const (
-       _SYS_setgroups  = SYS_SETGROUPS32
-       _SYS_clone3     = 435
-       _SYS_faccessat2 = 439
+       _SYS_setgroups         = SYS_SETGROUPS32
+       _SYS_clone3            = 435
+       _SYS_faccessat2        = 439
+       _SYS_pidfd_send_signal = 424
 )
 
 func setTimespec(sec, nsec int64) Timespec {
index aa85a523b20b99907fb0aa52e8ed9f8d67325324..0652590cfe5a635f8e7485cfb57b42c0139e7361 100644 (file)
@@ -9,9 +9,10 @@ import (
 )
 
 const (
-       _SYS_setgroups  = SYS_SETGROUPS
-       _SYS_clone3     = 435
-       _SYS_faccessat2 = 439
+       _SYS_setgroups         = SYS_SETGROUPS
+       _SYS_clone3            = 435
+       _SYS_faccessat2        = 439
+       _SYS_pidfd_send_signal = 424
 )
 
 //sys  Dup2(oldfd int, newfd int) (err error)
index 600ec3552db520bfe637271f3ef3ac7a3ac072a7..15c53d64b6df837be3ec833cf755eda13f17f210 100644 (file)
@@ -7,9 +7,10 @@ package syscall
 import "unsafe"
 
 const (
-       _SYS_setgroups  = SYS_SETGROUPS32
-       _SYS_clone3     = 435
-       _SYS_faccessat2 = 439
+       _SYS_setgroups         = SYS_SETGROUPS32
+       _SYS_clone3            = 435
+       _SYS_faccessat2        = 439
+       _SYS_pidfd_send_signal = 424
 )
 
 func setTimespec(sec, nsec int64) Timespec {
index 42984ba2eddaa415d7bd917a188cf6f1b2105e75..56b492e810bff0c3966e47eb0f989966b866fcb1 100644 (file)
@@ -7,9 +7,10 @@ package syscall
 import "unsafe"
 
 const (
-       _SYS_setgroups  = SYS_SETGROUPS
-       _SYS_clone3     = 435
-       _SYS_faccessat2 = 439
+       _SYS_setgroups         = SYS_SETGROUPS
+       _SYS_clone3            = 435
+       _SYS_faccessat2        = 439
+       _SYS_pidfd_send_signal = 424
 )
 
 //sys  EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) = SYS_EPOLL_PWAIT
index f8f01c2d225e50b6103ea91168bef3740c98124d..62533e80116479c9ef2155a97fad00591fdc89cf 100644 (file)
@@ -7,9 +7,10 @@ package syscall
 import "unsafe"
 
 const (
-       _SYS_setgroups  = SYS_SETGROUPS
-       _SYS_clone3     = 435
-       _SYS_faccessat2 = 439
+       _SYS_setgroups         = SYS_SETGROUPS
+       _SYS_clone3            = 435
+       _SYS_faccessat2        = 439
+       _SYS_pidfd_send_signal = 424
 )
 
 //sys  EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) = SYS_EPOLL_PWAIT
index 47410d42601c6975c735aa9c8d18746b2b205891..061585a1bfaed998e5bc0e13e7d676ee14e2285b 100644 (file)
@@ -11,9 +11,10 @@ import (
 )
 
 const (
-       _SYS_setgroups  = SYS_SETGROUPS
-       _SYS_clone3     = 5435
-       _SYS_faccessat2 = 5439
+       _SYS_setgroups         = SYS_SETGROUPS
+       _SYS_clone3            = 5435
+       _SYS_faccessat2        = 5439
+       _SYS_pidfd_send_signal = 5424
 )
 
 //sys  Dup2(oldfd int, newfd int) (err error)
index d8d5044b81aa632385e9648d4679ba7df66efc56..168148ab244c8d3f19f26e41f1d5e05faa3eb615 100644 (file)
@@ -9,9 +9,10 @@ package syscall
 import "unsafe"
 
 const (
-       _SYS_setgroups  = SYS_SETGROUPS
-       _SYS_clone3     = 4435
-       _SYS_faccessat2 = 4439
+       _SYS_setgroups         = SYS_SETGROUPS
+       _SYS_clone3            = 4435
+       _SYS_faccessat2        = 4439
+       _SYS_pidfd_send_signal = 4424
 )
 
 func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
index 36f7711dfa31185893775b5e5cd78851fcc514ca..91cd9838c39d71bc27ca307cad6f90703701655d 100644 (file)
@@ -11,9 +11,10 @@ import (
 )
 
 const (
-       _SYS_setgroups  = SYS_SETGROUPS
-       _SYS_clone3     = 435
-       _SYS_faccessat2 = 439
+       _SYS_setgroups         = SYS_SETGROUPS
+       _SYS_clone3            = 435
+       _SYS_faccessat2        = 439
+       _SYS_pidfd_send_signal = 424
 )
 
 //sys  Dup2(oldfd int, newfd int) (err error)
index 44ff1d733e910b404554df1c41aa69357870c61d..50c3988e82f5721250ce885e5893eb283c13d5e5 100644 (file)
@@ -7,9 +7,10 @@ package syscall
 import "unsafe"
 
 const (
-       _SYS_setgroups  = SYS_SETGROUPS
-       _SYS_clone3     = 435
-       _SYS_faccessat2 = 439
+       _SYS_setgroups         = SYS_SETGROUPS
+       _SYS_clone3            = 435
+       _SYS_faccessat2        = 439
+       _SYS_pidfd_send_signal = 424
 )
 
 //sys  EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) = SYS_EPOLL_PWAIT
index 44990f2b1bf99df81c1908403c4c184a91cfc01c..ecdabbf98f80cecfb523f885c9417233d10e6409 100644 (file)
@@ -7,9 +7,10 @@ package syscall
 import "unsafe"
 
 const (
-       _SYS_setgroups  = SYS_SETGROUPS
-       _SYS_clone3     = 435
-       _SYS_faccessat2 = 439
+       _SYS_setgroups         = SYS_SETGROUPS
+       _SYS_clone3            = 435
+       _SYS_faccessat2        = 439
+       _SYS_pidfd_send_signal = 424
 )
 
 //sys  Dup2(oldfd int, newfd int) (err error)