Skip to content

Commit c59b45b

Browse files
committed
make exec.fifo can be safety read on readonly tmpfs
Signed-off-by: ningmingxiao <[email protected]>
1 parent 721d066 commit c59b45b

File tree

2 files changed

+39
-68
lines changed

2 files changed

+39
-68
lines changed

libcontainer/container_linux.go

Lines changed: 6 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"golang.org/x/sys/unix"
2121

2222
"github.com/opencontainers/cgroups"
23+
"github.com/opencontainers/runc/internal/linux"
2324
"github.com/opencontainers/runc/libcontainer/configs"
2425
"github.com/opencontainers/runc/libcontainer/exeseal"
2526
"github.com/opencontainers/runc/libcontainer/intelrdt"
@@ -231,76 +232,18 @@ func (c *Container) Exec() error {
231232
}
232233

233234
func (c *Container) exec() error {
234-
path := filepath.Join(c.stateDir, execFifoFilename)
235-
pid := c.initProcess.pid()
236-
blockingFifoOpenCh := awaitFifoOpen(path)
237-
for {
238-
select {
239-
case result := <-blockingFifoOpenCh:
240-
return handleFifoResult(result)
241-
242-
case <-time.After(time.Millisecond * 100):
243-
stat, err := system.Stat(pid)
244-
if err != nil || stat.State == system.Zombie {
245-
// could be because process started, ran, and completed between our 100ms timeout and our system.Stat() check.
246-
// see if the fifo exists and has data (with a non-blocking open, which will succeed if the writing process is complete).
247-
if err := handleFifoResult(fifoOpen(path, false)); err != nil {
248-
return errors.New("container process is already dead")
249-
}
250-
return nil
251-
}
252-
}
253-
}
254-
}
255-
256-
func readFromExecFifo(execFifo io.Reader) error {
257-
data, err := io.ReadAll(execFifo)
235+
fifoPath := filepath.Join(c.stateDir, execFifoFilename)
236+
fd, err := linux.Open(fifoPath, unix.O_WRONLY|unix.O_CLOEXEC, 0)
258237
if err != nil {
259238
return err
260239
}
261-
if len(data) <= 0 {
262-
return errors.New("cannot start an already running container")
240+
defer unix.Close(fd)
241+
if _, err := unix.Write(fd, []byte("0")); err != nil {
242+
return &os.PathError{Op: "write exec fifo", Path: fifoPath, Err: err}
263243
}
264244
return nil
265245
}
266246

267-
func awaitFifoOpen(path string) <-chan openResult {
268-
fifoOpened := make(chan openResult)
269-
go func() {
270-
result := fifoOpen(path, true)
271-
fifoOpened <- result
272-
}()
273-
return fifoOpened
274-
}
275-
276-
func fifoOpen(path string, block bool) openResult {
277-
flags := os.O_RDONLY
278-
if !block {
279-
flags |= unix.O_NONBLOCK
280-
}
281-
f, err := os.OpenFile(path, flags, 0)
282-
if err != nil {
283-
return openResult{err: fmt.Errorf("exec fifo: %w", err)}
284-
}
285-
return openResult{file: f}
286-
}
287-
288-
func handleFifoResult(result openResult) error {
289-
if result.err != nil {
290-
return result.err
291-
}
292-
f := result.file
293-
defer f.Close()
294-
if err := readFromExecFifo(f); err != nil {
295-
return err
296-
}
297-
err := os.Remove(f.Name())
298-
if err == nil || os.IsNotExist(err) {
299-
return nil
300-
}
301-
return err
302-
}
303-
304247
type openResult struct {
305248
file *os.File
306249
err error

libcontainer/standard_init_linux.go

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package libcontainer
33
import (
44
"errors"
55
"fmt"
6+
"io"
67
"os"
78
"os/exec"
89

@@ -266,14 +267,18 @@ func (l *linuxStandardInit) Init() error {
266267
// user process. We open it through /proc/self/fd/$fd, because the fd that
267268
// was given to us was an O_PATH fd to the fifo itself. Linux allows us to
268269
// re-open an O_PATH fd through /proc.
269-
fd, err := linux.Open(fifoPath, unix.O_WRONLY|unix.O_CLOEXEC, 0)
270-
if err != nil {
270+
271+
result := fifoOpen(fifoPath, true)
272+
if result.err != nil {
271273
return err
272274
}
273-
if _, err := unix.Write(fd, []byte("0")); err != nil {
274-
return &os.PathError{Op: "write exec fifo", Path: fifoPath, Err: err}
275+
if err := readFromExecFifo(result.file); err != nil {
276+
return err
277+
}
278+
result.file.Close()
279+
if err := os.Remove(fifoPath); os.IsNotExist(err) {
280+
return err
275281
}
276-
277282
// Close the O_PATH fifofd fd before exec because the kernel resets
278283
// dumpable in the wrong order. This has been fixed in newer kernels, but
279284
// we keep this to ensure CVE-2016-9962 doesn't re-emerge on older kernels.
@@ -305,3 +310,26 @@ func (l *linuxStandardInit) Init() error {
305310
}
306311
return linux.Exec(name, l.config.Args, l.config.Env)
307312
}
313+
314+
func fifoOpen(path string, block bool) openResult {
315+
flags := os.O_RDONLY
316+
if !block {
317+
flags |= unix.O_NONBLOCK
318+
}
319+
f, err := os.OpenFile(path, flags, 0)
320+
if err != nil {
321+
return openResult{err: fmt.Errorf("exec fifo: %w", err)}
322+
}
323+
return openResult{file: f}
324+
}
325+
326+
func readFromExecFifo(execFifo io.Reader) error {
327+
data, err := io.ReadAll(execFifo)
328+
if err != nil {
329+
return err
330+
}
331+
if len(data) <= 0 {
332+
return errors.New("cannot start an already running container")
333+
}
334+
return nil
335+
}

0 commit comments

Comments
 (0)