Skip to content

linux: fix pidfd_open ENOENT errno support - #2399

Closed
usiegj00 wants to merge 1 commit into
containers:mainfrom
usiegj00:pidfd-open-enoent
Closed

usiegj00 wants to merge 1 commit into
containers:mainfrom
usiegj00:pidfd-open-enoent

Conversation

@usiegj00

@usiegj00 usiegj00 commented Oct 21, 2026 •

Copy link
Copy Markdown

Supersedes #2394, which was closed. @usiegl00 opened that PR with these same
commits; @giuseppe asked that the commit author and DCO match the submitting
account, so I am resubmitting under my own. @kolyshkin's review note on the
comment wording is already folded in, and the test has since been dropped per
@giuseppe's review below.

In commit 8cf4b738f6d8, "pidfd: improve uapi when task isn't found",
pidfd_open() returns ENOENT instead of EINVAL when the pid exists but is not
the leader of a thread-group. ENOENT is returned from Linux 6.16 onwards.

This happens when the pid space wraps under significant pid churn.
libcrun_kill_linux() only called libcrun_check_pid_valid() for EINVAL, so on
newer kernels crun delete --force failed with "open pidfd: No such file or
directory" and the stopped container could never be removed. On a busy node
these accumulate.

The fix treats ENOENT the same as EINVAL: check that the pid still belongs to
the container, and report ESRCH when it does not.

Verified in production on kernel 7.0 with a 1.25.1 backport: a delete that had
been failing succeeded, and pidfd_open errors went from roughly 4/min to 0.

Since Linux 6.16 (commit 8cf4b738f6d8, "pidfd: improve uapi when task
isn't found"), pidfd_open() returns ENOENT instead of EINVAL when the
pid exists but is not a thread-group leader.

libcrun_kill_linux() only checked the pid with libcrun_check_pid_valid()
for EINVAL, so on newer kernels it returned "open pidfd: No such file or
directory" when the container's recorded pid had been reused by a thread
of another process.  "crun delete --force" then failed for that stopped
container, and it could never be deleted.  On a busy node, where the pid
space wraps quickly, stopped containers accumulate.

Handle ENOENT the same way as EINVAL: check that the pid still belongs to
the container, and report ESRCH when it does not.  Accept ENOENT in the
same place in container_delete_internal().

Signed-off-by: Jonathan Siegel <jonathan@xenon.io>
@packit-as-a-service

Copy link
Copy Markdown

Ephemeral COPR build failed. @containers/packit-build please check.

@giuseppe

Copy link
Copy Markdown
Member

the patch LGTM but I am not sure we need the new test, we don't need to test the kernel

@usiegj00

Copy link
Copy Markdown
Author

Dropped the test. It was illustrative, and it made the pid reuse deterministic
so the ENOENT path could be reproduced, but you are right that it tests kernel
behaviour rather than crun. It is removed.

The PR is now the fix alone.

Comment thread src/libcrun/linux.c
Comment on lines +8073 to +8077
/* Check if the PID is valid before reporting an error. pidfd_open
fails for a pid that is not a thread-group leader, for example when
the container's pid was reused by a thread: with EINVAL before
Linux 6.16, with ENOENT since (commit 8cf4b738f6d8, "pidfd: improve
uapi when task isn't found"). */

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is way too long, enough to have something like

       /* pidfd_open returns EINVAL (ENOENT since Linux 6.16) if the pid is
         not a thread-group leader.  Check if the PID is valid before
         reporting an error.  */

@kolyshkin

Copy link
Copy Markdown
Collaborator

closing in favor of #2402

@kolyshkin kolyshkin closed this Oct 21, 2026
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.

3 participants