1
0
mirror of https://github.com/opencontainers/runc.git synced 2026-02-05 09:46:08 +01:00

Merge pull request #5091 from kolyshkin/go126

Fix runc exec vs go1.26 + older kernel
This commit is contained in:
Akihiro Suda
2026-02-04 19:43:32 +09:00
committed by GitHub
4 changed files with 53 additions and 3 deletions

View File

@@ -25,7 +25,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-24.04, ubuntu-24.04-arm]
go-version: [1.24.x, 1.25.x]
go-version: [1.24.x, 1.25.x, 1.26.0-rc.2]
rootless: ["rootless", ""]
race: ["-race", ""]
criu: ["", "criu-dev"]
@@ -34,11 +34,15 @@ jobs:
# (need to compile criu) and don't add much value/coverage.
- criu: criu-dev
go-version: 1.24.x
- criu: criu-dev
go-version: 1.26.0-rc.2
- criu: criu-dev
rootless: rootless
# Do race detection only on latest Go.
# Do race detection only with latest stable Go version.
- race: -race
go-version: 1.24.x
- race: -race
go-version: 1.26.0-rc.2
runs-on: ${{ matrix.os }}

37
libcontainer/cmd_clone.go Normal file
View File

@@ -0,0 +1,37 @@
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
}

View File

@@ -528,6 +528,12 @@ func (c *Container) newParentProcess(p *Process) (parentProcess, error) {
}
cmd := exec.Command(exePath, "init")
// Theoretically, exec.Command can set cmd.Err. Practically, this
// should never happen (Linux, Go <= 1.26, exePath is absolute),
// but in the unlikely case it just did, let's fail early.
if cmd.Err != nil {
return nil, fmt.Errorf("exec.Command: %w", cmd.Err)
}
cmd.Args[0] = os.Args[0]
cmd.Stdin = p.Stdin
cmd.Stdout = p.Stdout

View File

@@ -380,11 +380,14 @@ func (p *setnsProcess) startWithCgroupFD() error {
defer fd.Close()
}
cmdCopy := cloneCmd(p.cmd)
err = p.startWithCPUAffinity()
if err != nil && p.cmd.SysProcAttr.UseCgroupFD {
logrus.Debugf("exec with CLONE_INTO_CGROUP failed: %v; retrying without", err)
// SysProcAttr.CgroupFD is never used when UseCgroupFD is unset.
p.cmd.SysProcAttr.UseCgroupFD = false
cmdCopy.SysProcAttr.UseCgroupFD = false
// Must not reuse exec.Cmd.
p.cmd = cmdCopy
err = p.startWithCPUAffinity()
}