@@ -5,8 +5,10 @@ package utils
55
66import (
77 "fmt"
8+ "math"
89 "os"
910 "strconv"
11+ "sync"
1012
1113 "golang.org/x/sys/unix"
1214)
@@ -23,9 +25,38 @@ func EnsureProcHandle(fh *os.File) error {
2325 return nil
2426}
2527
28+ var (
29+ haveCloseRangeCloexecBool bool
30+ haveCloseRangeCloexecOnce sync.Once
31+ )
32+
33+ func haveCloseRangeCloexec () bool {
34+ haveCloseRangeCloexecOnce .Do (func () {
35+ // Make sure we're not closing a random file descriptor.
36+ tmpFd , err := unix .FcntlInt (0 , unix .F_DUPFD_CLOEXEC , 0 )
37+ if err != nil {
38+ return
39+ }
40+ defer unix .Close (tmpFd )
41+
42+ err = unix .CloseRange (uint (tmpFd ), uint (tmpFd ), unix .CLOSE_RANGE_CLOEXEC )
43+ // Any error means we cannot use close_range(CLOSE_RANGE_CLOEXEC).
44+ // -ENOSYS and -EINVAL ultimately mean we don't have support, but any
45+ // other potential error would imply that even the most basic close
46+ // operation wouldn't work.
47+ haveCloseRangeCloexecBool = err == nil
48+ })
49+ return haveCloseRangeCloexecBool
50+ }
51+
2652// CloseExecFrom applies O_CLOEXEC to all file descriptors currently open for
2753// the process (except for those below the given fd value).
2854func CloseExecFrom (minFd int ) error {
55+ if haveCloseRangeCloexec () {
56+ err := unix .CloseRange (uint (minFd ), math .MaxUint , unix .CLOSE_RANGE_CLOEXEC )
57+ return os .NewSyscallError ("close_range" , err )
58+ }
59+
2960 fdDir , err := os .Open ("/proc/self/fd" )
3061 if err != nil {
3162 return err
0 commit comments