Do not transition shim to stopped state from a state query

createdState.State and runningState.State transitioned the shim's init
process to stoppedState whenever a single `runsc state` call answered
"stopped". That transition bypasses SetExited: waitBlock is never
closed, no TaskExit event is published, and handleStoppedKill silently
swallows all subsequent kills, so containerd waits forever and the
container can never be torn down.

This behaviour comes from commit 0b39816a3, which tried to fix the
opposite problem of containerd never seeing that a container died due
to query errors. However, this part was never essential, because the
real fixes had to do with state queries on dead or deleted containers
erroring out. In light of https://github.com/google/gvisor/pull/14645,
there is now a concrete example of a buggy runsc not being an
authoritative and irreversible source for the stopped state, so kills
can be accepted but dropped, and the pod was stuck terminating forever.
This commit is contained in:
Konstantin Bogomolov
2026-09-08 16:12:35 -07:00
parent e11d0a7b1c
commit f152fe247e
+2 -10
View File
@@ -127,11 +127,7 @@ func (s *createdState) Exec(ctx context.Context, path string, r *ExecConfig) (ex
}
func (s *createdState) State(ctx context.Context) (string, error) {
state, err := s.p.state(ctx)
if err == nil && state == statusStopped {
s.transition(stopped)
}
return state, err
return s.p.state(ctx)
}
func (s *createdState) Stats(ctx context.Context, id string) (*runc.Stats, error) {
@@ -181,11 +177,7 @@ func (s *runningState) Exec(_ context.Context, path string, r *ExecConfig) (exte
}
func (s *runningState) State(ctx context.Context) (string, error) {
state, err := s.p.state(ctx)
if err == nil && state == "stopped" {
s.transition(stopped)
}
return state, err
return s.p.state(ctx)
}
func (s *runningState) Stats(ctx context.Context, id string) (*runc.Stats, error) {