Merge pull request from GHSA-xr7r-f8xq-vfvv · opencontainers/runc@0212048 (original) (raw)
`@@ -11,6 +11,7 @@ import (
`
11
11
`"runtime"
`
12
12
`"strconv"
`
13
13
`"sync"
`
``
14
`+
_ "unsafe" // for go:linkname
`
14
15
``
15
16
` securejoin "github.com/cyphar/filepath-securejoin"
`
16
17
`"github.com/sirupsen/logrus"
`
`@@ -53,14 +54,11 @@ func haveCloseRangeCloexec() bool {
`
53
54
`return haveCloseRangeCloexecBool
`
54
55
`}
`
55
56
``
56
``
`-
// CloseExecFrom applies O_CLOEXEC to all file descriptors currently open for
`
57
``
`-
// the process (except for those below the given fd value).
`
58
``
`-
func CloseExecFrom(minFd int) error {
`
59
``
`-
if haveCloseRangeCloexec() {
`
60
``
`-
err := unix.CloseRange(uint(minFd), math.MaxUint, unix.CLOSE_RANGE_CLOEXEC)
`
61
``
`-
return os.NewSyscallError("close_range", err)
`
62
``
`-
}
`
``
57
`+
type fdFunc func(fd int)
`
63
58
``
``
59
`+
// fdRangeFrom calls the passed fdFunc for each file descriptor that is open in
`
``
60
`+
// the current process.
`
``
61
`+
func fdRangeFrom(minFd int, fn fdFunc) error {
`
64
62
`procSelfFd, closer := ProcThreadSelf("fd")
`
65
63
`defer closer()
`
66
64
``
`@@ -88,15 +86,67 @@ func CloseExecFrom(minFd int) error {
`
88
86
`if fd < minFd {
`
89
87
`continue
`
90
88
` }
`
91
``
`-
// Intentionally ignore errors from unix.CloseOnExec -- the cases where
`
92
``
`-
// this might fail are basically file descriptors that have already
`
93
``
`-
// been closed (including and especially the one that was created when
`
94
``
`-
// os.ReadDir did the "opendir" syscall).
`
95
``
`-
unix.CloseOnExec(fd)
`
``
89
`+
// Ignore the file descriptor we used for readdir, as it will be closed
`
``
90
`+
// when we return.
`
``
91
`+
if uintptr(fd) == fdDir.Fd() {
`
``
92
`+
continue
`
``
93
`+
}
`
``
94
`+
// Run the closure.
`
``
95
`+
fn(fd)
`
96
96
` }
`
97
97
`return nil
`
98
98
`}
`
99
99
``
``
100
`+
// CloseExecFrom sets the O_CLOEXEC flag on all file descriptors greater or
`
``
101
`+
// equal to minFd in the current process.
`
``
102
`+
func CloseExecFrom(minFd int) error {
`
``
103
`+
// Use close_range(CLOSE_RANGE_CLOEXEC) if possible.
`
``
104
`+
if haveCloseRangeCloexec() {
`
``
105
`+
err := unix.CloseRange(uint(minFd), math.MaxUint, unix.CLOSE_RANGE_CLOEXEC)
`
``
106
`+
return os.NewSyscallError("close_range", err)
`
``
107
`+
}
`
``
108
`+
// Otherwise, fall back to the standard loop.
`
``
109
`+
return fdRangeFrom(minFd, unix.CloseOnExec)
`
``
110
`+
}
`
``
111
+
``
112
`+
//go:linkname runtime_IsPollDescriptor internal/poll.IsPollDescriptor
`
``
113
+
``
114
`+
// In order to make sure we do not close the internal epoll descriptors the Go
`
``
115
`+
// runtime uses, we need to ensure that we skip descriptors that match
`
``
116
`+
// "internal/poll".IsPollDescriptor. Yes, this is a Go runtime internal thing,
`
``
117
`+
// unfortunately there's no other way to be sure we're only keeping the file
`
``
118
`+
// descriptors the Go runtime needs. Hopefully nothing blows up doing this...
`
``
119
`+
func runtime_IsPollDescriptor(fd uintptr) bool //nolint:revive
`
``
120
+
``
121
`+
// UnsafeCloseFrom closes all file descriptors greater or equal to minFd in the
`
``
122
`+
// current process, except for those critical to Go's runtime (such as the
`
``
123
`+
// netpoll management descriptors).
`
``
124
`+
//
`
``
125
`+
// NOTE: That this function is incredibly dangerous to use in most Go code, as
`
``
126
`+
// closing file descriptors from underneath *os.File handles can lead to very
`
``
127
`+
// bad behaviour (the closed file descriptor can be re-used and then any
`
``
128
`+
// *os.File operations would apply to the wrong file). This function is only
`
``
129
`+
// intended to be called from the last stage of runc init.
`
``
130
`+
func UnsafeCloseFrom(minFd int) error {
`
``
131
`+
// We cannot use close_range(2) even if it is available, because we must
`
``
132
`+
// not close some file descriptors.
`
``
133
`+
return fdRangeFrom(minFd, func(fd int) {
`
``
134
`+
if runtime_IsPollDescriptor(uintptr(fd)) {
`
``
135
`+
// These are the Go runtimes internal netpoll file descriptors.
`
``
136
`+
// These file descriptors are operated on deep in the Go scheduler,
`
``
137
`+
// and closing those files from underneath Go can result in panics.
`
``
138
`+
// There is no issue with keeping them because they are not
`
``
139
`+
// executable and are not useful to an attacker anyway. Also we
`
``
140
`+
// don't have any choice.
`
``
141
`+
return
`
``
142
`+
}
`
``
143
`+
// There's nothing we can do about errors from close(2), and the
`
``
144
`+
// only likely error to be seen is EBADF which indicates the fd was
`
``
145
`+
// already closed (in which case, we got what we wanted).
`
``
146
`+
_ = unix.Close(fd)
`
``
147
`+
})
`
``
148
`+
}
`
``
149
+
100
150
`// NewSockPair returns a new SOCK_STREAM unix socket pair.
`
101
151
`func NewSockPair(name string) (parent, child *os.File, err error) {
`
102
152
`fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM|unix.SOCK_CLOEXEC, 0)
`