Skip to content

Commit 7094efb

Browse files
committed
init: use *os.File for passed file descriptors
While it doesn't make much of a practical difference, it seems far more reasonable to use os.NewFile to wrap all of our passed file descriptors to make sure they're tracked by the Go runtime and that we don't double-close them. Signed-off-by: Aleksa Sarai <[email protected]>
1 parent 10754b3 commit 7094efb

File tree

5 files changed

+33
-24
lines changed

5 files changed

+33
-24
lines changed

libcontainer/init_linux.go

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -137,24 +137,26 @@ func startInitialization() (retErr error) {
137137
logrus.SetLevel(logrus.Level(logLevel))
138138
}
139139

140-
logFD, err := strconv.Atoi(os.Getenv("_LIBCONTAINER_LOGPIPE"))
140+
logFd, err := strconv.Atoi(os.Getenv("_LIBCONTAINER_LOGPIPE"))
141141
if err != nil {
142142
return fmt.Errorf("unable to convert _LIBCONTAINER_LOGPIPE: %w", err)
143143
}
144+
logPipe := os.NewFile(uintptr(logFd), "logpipe")
144145

145-
logrus.SetOutput(os.NewFile(uintptr(logFD), "logpipe"))
146+
logrus.SetOutput(logPipe)
146147
logrus.SetFormatter(new(logrus.JSONFormatter))
147148
logrus.Debug("child process in init()")
148149

149150
// Only init processes have FIFOFD.
150-
fifofd := -1
151+
var fifoFile *os.File
151152
envInitType := os.Getenv("_LIBCONTAINER_INITTYPE")
152153
it := initType(envInitType)
153154
if it == initStandard {
154-
envFifoFd := os.Getenv("_LIBCONTAINER_FIFOFD")
155-
if fifofd, err = strconv.Atoi(envFifoFd); err != nil {
155+
fifoFd, err := strconv.Atoi(os.Getenv("_LIBCONTAINER_FIFOFD"))
156+
if err != nil {
156157
return fmt.Errorf("unable to convert _LIBCONTAINER_FIFOFD: %w", err)
157158
}
159+
fifoFile = os.NewFile(uintptr(fifoFd), "initfifo")
158160
}
159161

160162
var consoleSocket *os.File
@@ -208,10 +210,10 @@ func startInitialization() (retErr error) {
208210
}
209211

210212
// If init succeeds, it will not return, hence none of the defers will be called.
211-
return containerInit(it, &config, syncPipe, consoleSocket, pidfdSocket, fifofd, logFD, dmzExe)
213+
return containerInit(it, &config, syncPipe, consoleSocket, pidfdSocket, fifoFile, logPipe, dmzExe)
212214
}
213215

214-
func containerInit(t initType, config *initConfig, pipe *syncSocket, consoleSocket, pidfdSocket *os.File, fifoFd, logFd int, dmzExe *os.File) error {
216+
func containerInit(t initType, config *initConfig, pipe *syncSocket, consoleSocket, pidfdSocket, fifoFile, logPipe, dmzExe *os.File) error {
215217
if err := populateProcessEnvironment(config.Env); err != nil {
216218
return err
217219
}
@@ -223,7 +225,7 @@ func containerInit(t initType, config *initConfig, pipe *syncSocket, consoleSock
223225
consoleSocket: consoleSocket,
224226
pidfdSocket: pidfdSocket,
225227
config: config,
226-
logFd: logFd,
228+
logPipe: logPipe,
227229
dmzExe: dmzExe,
228230
}
229231
return i.Init()
@@ -234,8 +236,8 @@ func containerInit(t initType, config *initConfig, pipe *syncSocket, consoleSock
234236
pidfdSocket: pidfdSocket,
235237
parentPid: unix.Getppid(),
236238
config: config,
237-
fifoFd: fifoFd,
238-
logFd: logFd,
239+
fifoFile: fifoFile,
240+
logPipe: logPipe,
239241
dmzExe: dmzExe,
240242
}
241243
return i.Init()

libcontainer/mount_linux.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,12 @@ func mountViaFds(source string, srcFile *mountSource, target, dstFd, fstype stri
113113
// mount(2), we need to get a safe handle to /proc/thread-self. This
114114
// isn't needed for move_mount(2) because in that case the path is just
115115
// a dummy string used for error info.
116-
fdStr := strconv.Itoa(int(srcFile.file.Fd()))
116+
srcFileFd := srcFile.file.Fd()
117117
if isMoveMount {
118-
src = "/proc/self/fd/" + fdStr
118+
src = "/proc/self/fd/" + strconv.Itoa(int(srcFileFd))
119119
} else {
120120
var closer utils.ProcThreadSelfCloser
121-
src, closer = utils.ProcThreadSelf("fd/" + fdStr)
121+
src, closer = utils.ProcThreadSelfFd(srcFileFd)
122122
defer closer()
123123
}
124124
}

libcontainer/setns_init_linux.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"fmt"
66
"os"
77
"os/exec"
8-
"strconv"
98

109
"github.com/opencontainers/selinux/go-selinux"
1110
"github.com/sirupsen/logrus"
@@ -24,7 +23,7 @@ type linuxSetnsInit struct {
2423
consoleSocket *os.File
2524
pidfdSocket *os.File
2625
config *initConfig
27-
logFd int
26+
logPipe *os.File
2827
dmzExe *os.File
2928
}
3029

@@ -131,8 +130,8 @@ func (l *linuxSetnsInit) Init() error {
131130

132131
// Close the log pipe fd so the parent's ForwardLogs can exit.
133132
logrus.Debugf("setns_init: about to exec")
134-
if err := unix.Close(l.logFd); err != nil {
135-
return &os.PathError{Op: "close log pipe", Path: "fd " + strconv.Itoa(l.logFd), Err: err}
133+
if err := l.logPipe.Close(); err != nil {
134+
return fmt.Errorf("close log pipe: %w", err)
136135
}
137136

138137
if l.dmzExe != nil {

libcontainer/standard_init_linux.go

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"fmt"
66
"os"
77
"os/exec"
8-
"strconv"
98

109
"github.com/opencontainers/runtime-spec/specs-go"
1110
"github.com/opencontainers/selinux/go-selinux"
@@ -25,8 +24,8 @@ type linuxStandardInit struct {
2524
consoleSocket *os.File
2625
pidfdSocket *os.File
2726
parentPid int
28-
fifoFd int
29-
logFd int
27+
fifoFile *os.File
28+
logPipe *os.File
3029
dmzExe *os.File
3130
config *initConfig
3231
}
@@ -244,11 +243,11 @@ func (l *linuxStandardInit) Init() error {
244243

245244
// Close the log pipe fd so the parent's ForwardLogs can exit.
246245
logrus.Debugf("init: about to wait on exec fifo")
247-
if err := unix.Close(l.logFd); err != nil {
248-
return &os.PathError{Op: "close log pipe", Path: "fd " + strconv.Itoa(l.logFd), Err: err}
246+
if err := l.logPipe.Close(); err != nil {
247+
return fmt.Errorf("close log pipe: %w", err)
249248
}
250249

251-
fifoPath, closer := utils.ProcThreadSelf("fd/" + strconv.Itoa(l.fifoFd))
250+
fifoPath, closer := utils.ProcThreadSelfFd(l.fifoFile.Fd())
252251
defer closer()
253252

254253
// Wait for the FIFO to be opened on the other side before exec-ing the
@@ -269,7 +268,7 @@ func (l *linuxStandardInit) Init() error {
269268
// N.B. the core issue itself (passing dirfds to the host filesystem) has
270269
// since been resolved.
271270
// https://github.com/torvalds/linux/blob/v4.9/fs/exec.c#L1290-L1318
272-
_ = unix.Close(l.fifoFd)
271+
_ = l.fifoFile.Close()
273272

274273
s := l.config.SpecState
275274
s.Pid = unix.Getpid()

libcontainer/utils/utils_unix.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,3 +202,12 @@ func ProcThreadSelf(subpath string) (string, ProcThreadSelfCloser) {
202202
}
203203
return threadSelf + subpath, runtime.UnlockOSThread
204204
}
205+
206+
// ProcThreadSelfFd is small wrapper around ProcThreadSelf to make it easier to
207+
// create a /proc/thread-self handle for given file descriptor.
208+
//
209+
// It is basically equivalent to ProcThreadSelf(fmt.Sprintf("fd/%d", fd)), but
210+
// without using fmt.Sprintf to avoid unneeded overhead.
211+
func ProcThreadSelfFd(fd uintptr) (string, ProcThreadSelfCloser) {
212+
return ProcThreadSelf("fd/" + strconv.FormatUint(uint64(fd), 10))
213+
}

0 commit comments

Comments
 (0)