syscall: use dup3 in forkAndExecInChild on NetBSD

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 syscall was added in NetBSD 6.0.

Change-Id: I01a4f8c62bfa8fb7f9f3166070380dd2002bb564
Reviewed-on: https://go-review.googlesource.com/c/go/+/358755
Trust: Tobias Klauser <tobias.klauser@gmail.com>
Trust: Benny Siegert <bsiegert@gmail.com>
Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com>
Reviewed-by: Benny Siegert <bsiegert@gmail.com>
TryBot-Result: Go Bot <gobot@golang.org>
This commit is contained in:
Tobias Klauser 2021-10-26 09:13:16 +02:00 committed by Tobias Klauser
parent ca5f65d771
commit 5786a54cfe
4 changed files with 31 additions and 8 deletions

View File

@ -8,6 +8,7 @@
package syscall package syscall
import ( import (
"runtime"
"unsafe" "unsafe"
) )
@ -181,11 +182,19 @@ 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) // 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. // so that pass 2 won't stomp on an fd it needs later.
if pipe < nextfd { if pipe < nextfd {
_, _, err1 = RawSyscall(SYS_DUP2, uintptr(pipe), uintptr(nextfd), 0) switch runtime.GOOS {
if err1 != 0 { case "netbsd":
goto childerror _, _, err1 = RawSyscall(_SYS_DUP3, uintptr(pipe), uintptr(nextfd), O_CLOEXEC)
if err1 != 0 {
goto childerror
}
default:
_, _, err1 = RawSyscall(SYS_DUP2, uintptr(pipe), uintptr(nextfd), 0)
if err1 != 0 {
goto childerror
}
RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEXEC)
} }
RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEXEC)
pipe = nextfd pipe = nextfd
nextfd++ nextfd++
} }
@ -194,11 +203,19 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
if nextfd == pipe { // don't stomp on pipe if nextfd == pipe { // don't stomp on pipe
nextfd++ nextfd++
} }
_, _, err1 = RawSyscall(SYS_DUP2, uintptr(fd[i]), uintptr(nextfd), 0) switch runtime.GOOS {
if err1 != 0 { case "netbsd":
goto childerror _, _, err1 = RawSyscall(_SYS_DUP3, uintptr(fd[i]), uintptr(nextfd), O_CLOEXEC)
if err1 != 0 {
goto childerror
}
default:
_, _, err1 = RawSyscall(SYS_DUP2, uintptr(fd[i]), uintptr(nextfd), 0)
if err1 != 0 {
goto childerror
}
RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEXEC)
} }
RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEXEC)
fd[i] = nextfd fd[i] = nextfd
nextfd++ nextfd++
} }

View File

@ -17,6 +17,8 @@ import (
"unsafe" "unsafe"
) )
const _SYS_DUP3 = 0
// See version list in https://github.com/DragonFlyBSD/DragonFlyBSD/blob/master/sys/sys/param.h // See version list in https://github.com/DragonFlyBSD/DragonFlyBSD/blob/master/sys/sys/param.h
var ( var (
osreldateOnce sync.Once osreldateOnce sync.Once

View File

@ -14,6 +14,8 @@ package syscall
import "unsafe" import "unsafe"
const _SYS_DUP3 = SYS_DUP3
type SockaddrDatalink struct { type SockaddrDatalink struct {
Len uint8 Len uint8
Family uint8 Family uint8

View File

@ -4,6 +4,8 @@
package syscall package syscall
const _SYS_DUP3 = 0
func setTimespec(sec, nsec int64) Timespec { func setTimespec(sec, nsec int64) Timespec {
return Timespec{Sec: sec, Nsec: nsec} return Timespec{Sec: sec, Nsec: nsec}
} }