From e66992669172d1b5a10e553dc40a7c1853097d85 Mon Sep 17 00:00:00 2001 From: lfbzhm Date: Mon, 21 Oct 2024 06:36:56 +0000 Subject: [PATCH] fix an error caused by fd reuse race when starting runc init There is a race situation when we are opening a file, if there is a small fd was closed at that time, maybe it will be reused by safeExe. Because of Go stdlib fds shuffling bug, if the fd of safeExe is too small, go stdlib will dup3 it to another fd, or dup3 a other fd to this fd, then it will cause the fd type cmd.Path refers to a random path, and it can lead to an error "permission denied" when starting the process. Please see #4294 and . So we should not use the original fd of safeExe, but use the fd after shuffled by Go stdlib. Because Go stdlib will guarantee this fd refers to the correct file. Signed-off-by: lfbzhm --- libcontainer/container_linux.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go index 0b17168c2bb..838517c1c4d 100644 --- a/libcontainer/container_linux.go +++ b/libcontainer/container_linux.go @@ -618,6 +618,8 @@ func (c *Container) newParentProcess(p *Process) (parentProcess, error) { ) } + // TODO: After https://go-review.googlesource.com/c/go/+/515799 included + // in go versions supported by us, we can remove this logic. if safeExe != nil { // Due to a Go stdlib bug, we need to add safeExe to the set of // ExtraFiles otherwise it is possible for the stdlib to clobber the fd @@ -628,6 +630,18 @@ func (c *Container) newParentProcess(p *Process) (parentProcess, error) { // // See . cmd.ExtraFiles = append(cmd.ExtraFiles, safeExe) + + // There is a race situation when we are opening a file, if there is a + // small fd was closed at that time, maybe it will be reused by safeExe. + // Because of Go stdlib fds shuffling bug, if the fd of safeExe is too + // small, go stdlib will dup3 it to another fd, or dup3 a other fd to this + // fd, then it will cause the fd type cmd.Path refers to a random path, + // and it can lead to an error "permission denied" when starting the process. + // Please see #4294. + // So we should not use the original fd of safeExe, but use the fd after + // shuffled by Go stdlib. Because Go stdlib will guarantee this fd refers to + // the correct file. + cmd.Path = "/proc/self/fd/" + strconv.Itoa(stdioFdCount+len(cmd.ExtraFiles)-1) } // NOTE: when running a container with no PID namespace and the parent