Skip to content

Exit code for failed exec start is inconsistent #45795

@corhere

Description

@corhere

When an exec fails to start, the daemon sets the exec's exit code according to the error from containerd

moby/daemon/exec.go

Lines 286 to 293 in eb76c93

ec.Process, err = tsk.Exec(ctx, ec.ID, p, cStdin != nil, ec.InitializeStdio)
// the exec context should be ready, or error happened.
// close the chan to notify readiness
close(ec.Started)
if err != nil {
defer ec.Unlock()
return setExitCodeFromError(ec.SetExitCode, err)
}

but then clobbers it, overwriting with the value 126, in a deferred block.

moby/daemon/exec.go

Lines 183 to 195 in eb76c93

defer func() {
if err != nil {
ec.Lock()
ec.Container.ExecCommands.Delete(ec.ID)
ec.Running = false
exitCode := 126
ec.ExitCode = &exitCode
if err := ec.CloseStreams(); err != nil {
logrus.Errorf("failed to cleanup exec %s streams: %s", ec.Container.ID, err)
}
ec.Unlock()
}
}()

If it fails in such a way that containerd also publishes an exit event, daemon.ProcessEvent also races to handle the situation. Because the mutex on the exec config is repeatedly unlocked and relocked, daemon.ContainerExecStart races daemon.ProcessEvent to delete the exec from the container's ExecStore and set the exec's exit code. Depending on whether ContainerExecStart deletes the exec from the container's ExecStore before or after ProcessEvent handles the exit event, an "exec_die" container event is logged with the "exitCode" attribute set to either 127 or the actual exit code reported by containerd, while the exec's exit code is set to 126.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions