From f3e4f8ece99af983a97924989c2107ec2b3369c6 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 8 Apr 2026 15:21:06 -0700 Subject: [PATCH] libct/int: show stderr if command failed When running a process inside a container, make sure its stderr is not nil (except for some trivial cases like cat). Modify waitProcess to show failed command's stderr, if possible. Signed-off-by: Kir Kolyshkin (cherry picked from commit bf4fcc300267f5eff5a89a7213aa62ffaa1a02a0) Signed-off-by: Kir Kolyshkin --- libcontainer/integration/exec_test.go | 24 ++++++++++++++++++------ libcontainer/integration/execin_test.go | 3 ++- libcontainer/integration/utils_test.go | 5 ++++- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/libcontainer/integration/exec_test.go b/libcontainer/integration/exec_test.go index 9133b6801..7d931bd21 100644 --- a/libcontainer/integration/exec_test.go +++ b/libcontainer/integration/exec_test.go @@ -171,6 +171,7 @@ func TestEnter(t *testing.T) { Env: standardEnvironment, Stdin: stdinR, Stdout: &stdout, + Stderr: new(strings.Builder), Init: true, } err = container.Run(&pconfig) @@ -184,13 +185,13 @@ func TestEnter(t *testing.T) { stdinR2, stdinW2, err := os.Pipe() ok(t, err) pconfig2 := libcontainer.Process{ - Cwd: "/", - Env: standardEnvironment, + Cwd: "/", + Args: []string{"sh", "-c", "cat && readlink /proc/self/ns/pid"}, + Env: standardEnvironment, + Stdin: stdinR2, + Stdout: &stdout2, + Stderr: new(strings.Builder), } - pconfig2.Args = []string{"sh", "-c", "cat && readlink /proc/self/ns/pid"} - pconfig2.Stdin = stdinR2 - pconfig2.Stdout = &stdout2 - err = container.Run(&pconfig2) _ = stdinR2.Close() defer stdinW2.Close() @@ -253,6 +254,7 @@ func TestProcessEnv(t *testing.T) { }, Stdin: nil, Stdout: &stdout, + Stderr: new(strings.Builder), Init: true, } err = container.Run(&pconfig) @@ -293,6 +295,7 @@ func TestProcessEmptyCaps(t *testing.T) { Env: standardEnvironment, Stdin: nil, Stdout: &stdout, + Stderr: new(strings.Builder), Init: true, } err = container.Run(&pconfig) @@ -336,6 +339,7 @@ func TestProcessCaps(t *testing.T) { Env: standardEnvironment, Stdin: nil, Stdout: &stdout, + Stderr: new(strings.Builder), Capabilities: &configs.Capabilities{}, Init: true, } @@ -396,6 +400,7 @@ func TestAdditionalGroups(t *testing.T) { Env: standardEnvironment, Stdin: nil, Stdout: &stdout, + Stderr: new(strings.Builder), AdditionalGroups: []int{3333, 99999}, Init: true, } @@ -833,6 +838,7 @@ func TestSysctl(t *testing.T) { Env: standardEnvironment, Stdin: nil, Stdout: &stdout, + Stderr: new(strings.Builder), Init: true, } err = container.Run(&pconfig) @@ -942,6 +948,7 @@ func TestOomScoreAdj(t *testing.T) { Env: standardEnvironment, Stdin: nil, Stdout: &stdout, + Stderr: new(strings.Builder), Init: true, } err = container.Run(&pconfig) @@ -1081,6 +1088,7 @@ func TestHook(t *testing.T) { Env: standardEnvironment, Stdin: nil, Stdout: &stdout, + Stderr: new(strings.Builder), Init: true, } err = container.Run(&pconfig) @@ -1196,6 +1204,7 @@ func TestRootfsPropagationSlaveMount(t *testing.T) { Env: standardEnvironment, Stdin: stdinR2, Stdout: &stdout2, + Stderr: new(strings.Builder), } err = container.Run(pconfig2) @@ -1307,6 +1316,7 @@ func TestRootfsPropagationSharedMount(t *testing.T) { Env: standardEnvironment, Stdin: stdinR2, Stdout: &stdout2, + Stderr: new(strings.Builder), Capabilities: &configs.Capabilities{}, } @@ -1490,6 +1500,7 @@ func TestInitJoinPID(t *testing.T) { Args: []string{"ps"}, Env: standardEnvironment, Stdout: buffers.Stdout, + Stderr: new(strings.Builder), } err = container1.Run(ps) ok(t, err) @@ -1622,6 +1633,7 @@ func TestTmpfsCopyUp(t *testing.T) { Env: standardEnvironment, Stdin: nil, Stdout: &stdout, + Stderr: new(strings.Builder), Init: true, } err = container.Run(&pconfig) diff --git a/libcontainer/integration/execin_test.go b/libcontainer/integration/execin_test.go index 2cd1f1375..32cdb1985 100644 --- a/libcontainer/integration/execin_test.go +++ b/libcontainer/integration/execin_test.go @@ -160,6 +160,7 @@ func TestExecInAdditionalGroups(t *testing.T) { Env: standardEnvironment, Stdin: nil, Stdout: &stdout, + Stderr: new(strings.Builder), AdditionalGroups: []int{4444, 87654}, } err = container.Run(&pconfig) @@ -538,7 +539,7 @@ func TestExecInUserns(t *testing.T) { "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", }, Stdout: buffers.Stdout, - Stderr: os.Stderr, + Stderr: new(strings.Builder), } err = container.Run(process2) ok(t, err) diff --git a/libcontainer/integration/utils_test.go b/libcontainer/integration/utils_test.go index e30630953..b9407d2a4 100644 --- a/libcontainer/integration/utils_test.go +++ b/libcontainer/integration/utils_test.go @@ -90,7 +90,10 @@ func waitProcess(p *libcontainer.Process, t testing.TB) { t.Helper() _, err := p.Wait() if err != nil { - t.Fatalf("unexpected error: %v", err) + if stderr, ok := p.Stderr.(fmt.Stringer); ok { + err = fmt.Errorf("%w; stderr:\n%s", err, stderr) + } + t.Fatalf("command failed: %v", err) } }