mirror of
https://github.com/opencontainers/runc.git
synced 2026-07-11 06:03:57 +08:00
685bbe04e1
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>
(cherry picked from commit cb31d62f1c)
Signed-off-by: lifubang <lifubang@acmcoder.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
|
|
}
|