From 3435758f68b4a731dd03d3903bcc2b196715ff76 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Fri, 4 Mar 2022 09:49:32 +0100 Subject: [PATCH] syscall: use dup3 in forkAndExecInChild on OpenBSD Use dup3(oldfd, newfd, O_CLOEXEC) to atomically duplicate the file descriptor and mark is as close-on-exec instead of dup2 & fcntl. The dup3 system call first appeared in OpenBSD 5.7. Change-Id: Ic06c2c7089dcdbd931ee24e5e8c316879d81474e Reviewed-on: https://go-review.googlesource.com/c/go/+/389974 Trust: Tobias Klauser Run-TryBot: Tobias Klauser Reviewed-by: Ian Lance Taylor --- src/syscall/exec_bsd.go | 26 ++++++++++++-------------- src/syscall/exec_libc2.go | 23 +++++++++++++++++++---- src/syscall/syscall_darwin.go | 2 ++ src/syscall/syscall_openbsd.go | 1 + src/syscall/syscall_openbsd_libc.go | 2 ++ src/syscall/syscall_openbsd_mips64.go | 2 +- src/syscall/zsyscall_openbsd_386.go | 14 ++++++++++++++ src/syscall/zsyscall_openbsd_386.s | 2 ++ src/syscall/zsyscall_openbsd_amd64.go | 14 ++++++++++++++ src/syscall/zsyscall_openbsd_amd64.s | 2 ++ src/syscall/zsyscall_openbsd_arm.go | 14 ++++++++++++++ src/syscall/zsyscall_openbsd_arm.s | 2 ++ src/syscall/zsyscall_openbsd_arm64.go | 14 ++++++++++++++ src/syscall/zsyscall_openbsd_arm64.s | 2 ++ 14 files changed, 101 insertions(+), 19 deletions(-) diff --git a/src/syscall/exec_bsd.go b/src/syscall/exec_bsd.go index 148f5a91aa00e8..530b48cb707df7 100644 --- a/src/syscall/exec_bsd.go +++ b/src/syscall/exec_bsd.go @@ -181,18 +181,17 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr // Pass 1: look for fd[i] < i and move those up above len(fd) // so that pass 2 won't stomp on an fd it needs later. if pipe < nextfd { - switch runtime.GOOS { - case "netbsd": + if runtime.GOOS == "netbsd" || (runtime.GOOS == "openbsd" && runtime.GOARCH == "mips64") { _, _, err1 = RawSyscall(_SYS_DUP3, uintptr(pipe), uintptr(nextfd), O_CLOEXEC) - if err1 != 0 { - goto childerror - } - default: + } else { _, _, err1 = RawSyscall(SYS_DUP2, uintptr(pipe), uintptr(nextfd), 0) if err1 != 0 { goto childerror } - RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEXEC) + _, _, err1 = RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEXEC) + } + if err1 != 0 { + goto childerror } pipe = nextfd nextfd++ @@ -202,18 +201,17 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr if nextfd == pipe { // don't stomp on pipe nextfd++ } - switch runtime.GOOS { - case "netbsd": + if runtime.GOOS == "netbsd" || (runtime.GOOS == "openbsd" && runtime.GOARCH == "mips64") { _, _, err1 = RawSyscall(_SYS_DUP3, uintptr(fd[i]), uintptr(nextfd), O_CLOEXEC) - if err1 != 0 { - goto childerror - } - default: + } else { _, _, err1 = RawSyscall(SYS_DUP2, uintptr(fd[i]), uintptr(nextfd), 0) if err1 != 0 { goto childerror } - RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEXEC) + _, _, err1 = RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEXEC) + } + if err1 != 0 { + goto childerror } fd[i] = nextfd nextfd++ diff --git a/src/syscall/exec_libc2.go b/src/syscall/exec_libc2.go index b05f053bbf3fa7..91a39ba1b8f617 100644 --- a/src/syscall/exec_libc2.go +++ b/src/syscall/exec_libc2.go @@ -8,6 +8,7 @@ package syscall import ( "internal/abi" + "runtime" "unsafe" ) @@ -180,11 +181,18 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr // Pass 1: look for fd[i] < i and move those up above len(fd) // so that pass 2 won't stomp on an fd it needs later. if pipe < nextfd { - _, _, err1 = rawSyscall(abi.FuncPCABI0(libc_dup2_trampoline), uintptr(pipe), uintptr(nextfd), 0) + if runtime.GOOS == "openbsd" { + _, _, err1 = rawSyscall(dupTrampoline, uintptr(pipe), uintptr(nextfd), O_CLOEXEC) + } else { + _, _, err1 = rawSyscall(dupTrampoline, uintptr(pipe), uintptr(nextfd), 0) + if err1 != 0 { + goto childerror + } + _, _, err1 = rawSyscall(abi.FuncPCABI0(libc_fcntl_trampoline), uintptr(nextfd), F_SETFD, FD_CLOEXEC) + } if err1 != 0 { goto childerror } - rawSyscall(abi.FuncPCABI0(libc_fcntl_trampoline), uintptr(nextfd), F_SETFD, FD_CLOEXEC) pipe = nextfd nextfd++ } @@ -193,11 +201,18 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr if nextfd == pipe { // don't stomp on pipe nextfd++ } - _, _, err1 = rawSyscall(abi.FuncPCABI0(libc_dup2_trampoline), uintptr(fd[i]), uintptr(nextfd), 0) + if runtime.GOOS == "openbsd" { + _, _, err1 = rawSyscall(dupTrampoline, uintptr(fd[i]), uintptr(nextfd), O_CLOEXEC) + } else { + _, _, err1 = rawSyscall(dupTrampoline, uintptr(fd[i]), uintptr(nextfd), 0) + if err1 != 0 { + goto childerror + } + _, _, err1 = rawSyscall(abi.FuncPCABI0(libc_fcntl_trampoline), uintptr(nextfd), F_SETFD, FD_CLOEXEC) + } if err1 != 0 { goto childerror } - rawSyscall(abi.FuncPCABI0(libc_fcntl_trampoline), uintptr(nextfd), F_SETFD, FD_CLOEXEC) fd[i] = nextfd nextfd++ } diff --git a/src/syscall/syscall_darwin.go b/src/syscall/syscall_darwin.go index 902d6e77e11cb2..87fb5c2f62d204 100644 --- a/src/syscall/syscall_darwin.go +++ b/src/syscall/syscall_darwin.go @@ -17,6 +17,8 @@ import ( "unsafe" ) +var dupTrampoline = abi.FuncPCABI0(libc_dup2_trampoline) + type SockaddrDatalink struct { Len uint8 Family uint8 diff --git a/src/syscall/syscall_openbsd.go b/src/syscall/syscall_openbsd.go index fa939ec5c88495..30a95316e85d9a 100644 --- a/src/syscall/syscall_openbsd.go +++ b/src/syscall/syscall_openbsd.go @@ -136,6 +136,7 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) { //sys Close(fd int) (err error) //sys Dup(fd int) (nfd int, err error) //sys Dup2(from int, to int) (err error) +//sys dup3(from int, to int, flags int) (err error) //sys Fchdir(fd int) (err error) //sys Fchflags(fd int, flags int) (err error) //sys Fchmod(fd int, mode uint32) (err error) diff --git a/src/syscall/syscall_openbsd_libc.go b/src/syscall/syscall_openbsd_libc.go index 15b68fd0fcf51c..516d02975c530a 100644 --- a/src/syscall/syscall_openbsd_libc.go +++ b/src/syscall/syscall_openbsd_libc.go @@ -10,6 +10,8 @@ import ( "internal/abi" ) +var dupTrampoline = abi.FuncPCABI0(libc_dup3_trampoline) + func init() { execveOpenBSD = execve } diff --git a/src/syscall/syscall_openbsd_mips64.go b/src/syscall/syscall_openbsd_mips64.go index e8ae2e9911bafa..4508ad99b492a5 100644 --- a/src/syscall/syscall_openbsd_mips64.go +++ b/src/syscall/syscall_openbsd_mips64.go @@ -4,7 +4,7 @@ package syscall -const _SYS_DUP3 = 0 +const _SYS_DUP3 = SYS_DUP3 func setTimespec(sec, nsec int64) Timespec { return Timespec{Sec: sec, Nsec: nsec} diff --git a/src/syscall/zsyscall_openbsd_386.go b/src/syscall/zsyscall_openbsd_386.go index 5f95d7a9c6dbce..2dcc4b2739dd4b 100644 --- a/src/syscall/zsyscall_openbsd_386.go +++ b/src/syscall/zsyscall_openbsd_386.go @@ -551,6 +551,20 @@ func libc_dup2_trampoline() // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func dup3(from int, to int, flags int) (err error) { + _, _, e1 := syscall(abi.FuncPCABI0(libc_dup3_trampoline), uintptr(from), uintptr(to), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_dup3_trampoline() + +//go:cgo_import_dynamic libc_dup3 dup3 "libc.so" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fchdir(fd int) (err error) { _, _, e1 := syscall(abi.FuncPCABI0(libc_fchdir_trampoline), uintptr(fd), 0, 0) if e1 != 0 { diff --git a/src/syscall/zsyscall_openbsd_386.s b/src/syscall/zsyscall_openbsd_386.s index d47a4f480d914a..e2c58625bb3b1c 100644 --- a/src/syscall/zsyscall_openbsd_386.s +++ b/src/syscall/zsyscall_openbsd_386.s @@ -69,6 +69,8 @@ TEXT ·libc_dup_trampoline(SB),NOSPLIT,$0-0 JMP libc_dup(SB) TEXT ·libc_dup2_trampoline(SB),NOSPLIT,$0-0 JMP libc_dup2(SB) +TEXT ·libc_dup3_trampoline(SB),NOSPLIT,$0-0 + JMP libc_dup3(SB) TEXT ·libc_fchdir_trampoline(SB),NOSPLIT,$0-0 JMP libc_fchdir(SB) TEXT ·libc_fchflags_trampoline(SB),NOSPLIT,$0-0 diff --git a/src/syscall/zsyscall_openbsd_amd64.go b/src/syscall/zsyscall_openbsd_amd64.go index 189bf887e6223f..8d4cb9c1e1ce11 100644 --- a/src/syscall/zsyscall_openbsd_amd64.go +++ b/src/syscall/zsyscall_openbsd_amd64.go @@ -551,6 +551,20 @@ func libc_dup2_trampoline() // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func dup3(from int, to int, flags int) (err error) { + _, _, e1 := syscall(abi.FuncPCABI0(libc_dup3_trampoline), uintptr(from), uintptr(to), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_dup3_trampoline() + +//go:cgo_import_dynamic libc_dup3 dup3 "libc.so" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fchdir(fd int) (err error) { _, _, e1 := syscall(abi.FuncPCABI0(libc_fchdir_trampoline), uintptr(fd), 0, 0) if e1 != 0 { diff --git a/src/syscall/zsyscall_openbsd_amd64.s b/src/syscall/zsyscall_openbsd_amd64.s index e5c5dde930bb60..964c9ed9e1236d 100644 --- a/src/syscall/zsyscall_openbsd_amd64.s +++ b/src/syscall/zsyscall_openbsd_amd64.s @@ -69,6 +69,8 @@ TEXT ·libc_dup_trampoline(SB),NOSPLIT,$0-0 JMP libc_dup(SB) TEXT ·libc_dup2_trampoline(SB),NOSPLIT,$0-0 JMP libc_dup2(SB) +TEXT ·libc_dup3_trampoline(SB),NOSPLIT,$0-0 + JMP libc_dup3(SB) TEXT ·libc_fchdir_trampoline(SB),NOSPLIT,$0-0 JMP libc_fchdir(SB) TEXT ·libc_fchflags_trampoline(SB),NOSPLIT,$0-0 diff --git a/src/syscall/zsyscall_openbsd_arm.go b/src/syscall/zsyscall_openbsd_arm.go index c7513a3ac9af4c..d45bc02fbd3ec7 100644 --- a/src/syscall/zsyscall_openbsd_arm.go +++ b/src/syscall/zsyscall_openbsd_arm.go @@ -551,6 +551,20 @@ func libc_dup2_trampoline() // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func dup3(from int, to int, flags int) (err error) { + _, _, e1 := syscall(abi.FuncPCABI0(libc_dup3_trampoline), uintptr(from), uintptr(to), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_dup3_trampoline() + +//go:cgo_import_dynamic libc_dup3 dup3 "libc.so" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fchdir(fd int) (err error) { _, _, e1 := syscall(abi.FuncPCABI0(libc_fchdir_trampoline), uintptr(fd), 0, 0) if e1 != 0 { diff --git a/src/syscall/zsyscall_openbsd_arm.s b/src/syscall/zsyscall_openbsd_arm.s index d33f3aa3e05cf0..5975780edb272b 100644 --- a/src/syscall/zsyscall_openbsd_arm.s +++ b/src/syscall/zsyscall_openbsd_arm.s @@ -69,6 +69,8 @@ TEXT ·libc_dup_trampoline(SB),NOSPLIT,$0-0 JMP libc_dup(SB) TEXT ·libc_dup2_trampoline(SB),NOSPLIT,$0-0 JMP libc_dup2(SB) +TEXT ·libc_dup3_trampoline(SB),NOSPLIT,$0-0 + JMP libc_dup3(SB) TEXT ·libc_fchdir_trampoline(SB),NOSPLIT,$0-0 JMP libc_fchdir(SB) TEXT ·libc_fchflags_trampoline(SB),NOSPLIT,$0-0 diff --git a/src/syscall/zsyscall_openbsd_arm64.go b/src/syscall/zsyscall_openbsd_arm64.go index 293b7036002189..e060b092fe316f 100644 --- a/src/syscall/zsyscall_openbsd_arm64.go +++ b/src/syscall/zsyscall_openbsd_arm64.go @@ -551,6 +551,20 @@ func libc_dup2_trampoline() // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func dup3(from int, to int, flags int) (err error) { + _, _, e1 := syscall(abi.FuncPCABI0(libc_dup3_trampoline), uintptr(from), uintptr(to), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_dup3_trampoline() + +//go:cgo_import_dynamic libc_dup3 dup3 "libc.so" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fchdir(fd int) (err error) { _, _, e1 := syscall(abi.FuncPCABI0(libc_fchdir_trampoline), uintptr(fd), 0, 0) if e1 != 0 { diff --git a/src/syscall/zsyscall_openbsd_arm64.s b/src/syscall/zsyscall_openbsd_arm64.s index 37778b1db5417b..2c4a0b0faf57d3 100644 --- a/src/syscall/zsyscall_openbsd_arm64.s +++ b/src/syscall/zsyscall_openbsd_arm64.s @@ -69,6 +69,8 @@ TEXT ·libc_dup_trampoline(SB),NOSPLIT,$0-0 JMP libc_dup(SB) TEXT ·libc_dup2_trampoline(SB),NOSPLIT,$0-0 JMP libc_dup2(SB) +TEXT ·libc_dup3_trampoline(SB),NOSPLIT,$0-0 + JMP libc_dup3(SB) TEXT ·libc_fchdir_trampoline(SB),NOSPLIT,$0-0 JMP libc_fchdir(SB) TEXT ·libc_fchflags_trampoline(SB),NOSPLIT,$0-0