@@ -618,6 +618,8 @@ func (c *Container) newParentProcess(p *Process) (parentProcess, error) {
618618 )
619619 }
620620
621+ // TODO: After https://go-review.googlesource.com/c/go/+/515799 included
622+ // in go versions supported by us, we can remove this logic.
621623 if safeExe != nil {
622624 // Due to a Go stdlib bug, we need to add safeExe to the set of
623625 // ExtraFiles otherwise it is possible for the stdlib to clobber the fd
@@ -628,6 +630,18 @@ func (c *Container) newParentProcess(p *Process) (parentProcess, error) {
628630 //
629631 // See <https://github.com/golang/go/issues/61751>.
630632 cmd .ExtraFiles = append (cmd .ExtraFiles , safeExe )
633+
634+ // There is a race situation when we are opening a file, if there is a
635+ // small fd was closed at that time, maybe it will be reused by safeExe.
636+ // Because of Go stdlib fds shuffling bug, if the fd of safeExe is too
637+ // small, go stdlib will dup3 it to another fd, or dup3 a other fd to this
638+ // fd, then it will cause the fd type cmd.Path refers to a random path,
639+ // and it can lead to an error "permission denied" when starting the process.
640+ // Please see #4294.
641+ // So we should not use the original fd of safeExe, but use the fd after
642+ // shuffled by Go stdlib. Because Go stdlib will guarantee this fd refers to
643+ // the correct file.
644+ cmd .Path = "/proc/self/fd/" + strconv .Itoa (stdioFdCount + len (cmd .ExtraFiles )- 1 )
631645 }
632646
633647 // NOTE: when running a container with no PID namespace and the parent
0 commit comments