mirror of
https://github.com/opencontainers/runc.git
synced 2026-02-06 03:45:41 +01:00
Since [PR 4812], runc exec tries to use clone3 syscall with CLONE_INTO_CGROUP, falling back to the old method if it is not supported. One issue with that approach is, a > Cmd cannot be reused after calling its [Cmd.Start], [Cmd.Run], > [Cmd.Output], or [Cmd.CombinedOutput] methods. (from https://pkg.go.dev/os/exec#Cmd). This is enforced since Go 1.26, see [CL 728642], and so runc exec actually fails in specific scenarios (go1.26 and no CLONE_INTO_CGROUP support). The easiest workaround is to pre-copy the p.cmd structure (copy = *cmd). From the [CL 734200] it looks like it is an acceptable way, but it might break in the future as it also copies the private fields, so let's do a proper field-by-field copy. If the upstream will add cmd.Clone method, we will switch to it. Also, we can probably be fine with a post-copy (once the first Start has failed), but let's be conservative here and do a pre-copy. [PR 4812]: https://github.com/opencontainers/runc/pull/4812 [CL 728642]: https://go.dev/cl/728642 [CL 734200]: https://go.dev/cl/734200 Reported-by: Efim Verzakov <efimverzakov@gmail.com> Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
38 lines
1013 B
Go
38 lines
1013 B
Go
package libcontainer
|
|
|
|
import "os/exec"
|
|
|
|
// cloneCmd creates a copy of exec.Cmd. It is needed because cmd.Start
|
|
// must only be used once, and go1.26 actually enforces that (see
|
|
// https://go-review.googlesource.com/c/go/+/728642). The implementation
|
|
// is similar to
|
|
//
|
|
// cmd = *c
|
|
// return &cmd
|
|
//
|
|
// except it does not copy private fields, or fields populated
|
|
// after the call to cmd.Start.
|
|
//
|
|
// NOTE if Go will add exec.Cmd.Clone, we should switch to it.
|
|
func cloneCmd(c *exec.Cmd) *exec.Cmd {
|
|
cmd := &exec.Cmd{
|
|
Path: c.Path,
|
|
Args: c.Args,
|
|
Env: c.Env,
|
|
Dir: c.Dir,
|
|
Stdin: c.Stdin,
|
|
Stdout: c.Stdout,
|
|
Stderr: c.Stderr,
|
|
ExtraFiles: c.ExtraFiles,
|
|
SysProcAttr: c.SysProcAttr,
|
|
// Don't copy Process, ProcessState, Err since
|
|
// these fields are populated after the start.
|
|
|
|
// Technically, we do not use Cancel or WaitDelay,
|
|
// but they are here for the sake of completeness.
|
|
Cancel: c.Cancel,
|
|
WaitDelay: c.WaitDelay,
|
|
}
|
|
return cmd
|
|
}
|