Improve runc exec behavior with tight pids limit by kolyshkin · Pull Request #5531 · opencontainers/runc · GitHub
Skip to content

Improve runc exec behavior with tight pids limit - #5531

Open
kolyshkin wants to merge 2 commits into
opencontainers:mainfrom
kolyshkin:exec-pids-limit
Open

kolyshkin wants to merge 2 commits into
opencontainers:mainfrom
kolyshkin:exec-pids-limit

Conversation

@kolyshkin

@kolyshkin kolyshkin commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor
  1. Do not retry exec without CLONE_INTO_CGROUP on EAGAIN. Currently, with a tight pids limit, runc exec succeeds if there is no room at all (as the retry bypasses the limit), fails if there's room for a few pids, and succeeds if there's enough room for runc init (about 6 pids). With this change, the behavior is deterministic: exec fails unless there's enough room for runc init.

  2. When runc exec fails, check whether the pids limit was hit (by comparing the max counter from pids.events), and if so, add a (possibly hit pids limit) hint to the error.

Note that runc init needs a few pids since v1.4.0 (which started using CLONE_INTO_CGROUP for exec). Before that, runc exec worked with tight pids limits most of the time (since runc init was moved into the container cgroup late).

Fixes #1914.

kolyshkin and others added 2 commits October 8, 2026 14:50
Since runc exec started using CLONE_INTO_CGROUP, runc init is subject
to the container cgroup pids limit from the very beginning, and so
it needs a few pids (for nsexec stages and Go runtime threads) to
start.

When clone3 with CLONE_INTO_CGROUP fails, runc retries without it,
and then moves the process into the container cgroup. If the failure
is caused by the pids limit (clone3 returns EAGAIN), the retry
succeeds, since moving a process into a cgroup is not subject to the
pids limit. This makes the outcome of runc exec with a tight pids
limit dependent on how much room is left:

 - no room at all: exec succeeds (bypassing the limit);
 - room for a few pids (but not enough for runc init): exec fails;
 - enough room: exec succeeds.

Other possible reasons for EAGAIN (RLIMIT_NPROC, threads-max, pid_max)
do not depend on CLONE_INTO_CGROUP, so the retry won't help anyway.

Do not retry on EAGAIN, making the behavior deterministic: runc exec
fails unless there is enough room for runc init. Note that in case
there is no room at all, the exec'd process can't fork anyway.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
When a container cgroup pids limit is too tight, runc exec fails
because runc init (nsexec stages and Go runtime threads) needs a few
pids. The resulting error message is not very helpful, e.g.

	exec failed: unable to start container process: procReady not received

Similar to what we do for OOM kills, check whether the cgroup pids
limit was hit (by comparing the "max" counter from pids.events
before and after), and if yes, add a hint to the error, e.g.

	exec failed: unable to start container process: procReady not received (possibly hit pids limit)

Add an integration test.

Fixes opencontainers#1914.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
@kolyshkin kolyshkin changed the title libct: hint at pids limit on exec failure Improve runc exec behavior with tight pids limit Oct 8, 2026
@kolyshkin
kolyshkin marked this pull request as ready for review October 8, 2026 21:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tight container limits may cause "read init-p: connection reset by peer"

1 participant