Skip to content

pipes: close pipe descriptors on open_pipe() error paths - #3134

Open
Utkal059 wants to merge 1 commit into
checkpoint-restore:criu-devfrom
Utkal059:fix/pipes-fd-leak
Open

pipes: close pipe descriptors on open_pipe() error paths#3134
Utkal059 wants to merge 1 commit into
checkpoint-restore:criu-devfrom
Utkal059:fix/pipes-fd-leak

Conversation

@Utkal059

@Utkal059 Utkal059 commented Sep 2, 2026

Copy link
Copy Markdown
Member

Fixes #3133

open_pipe() creates a pipe pair and returns -1 from four places without closing the descriptors: when cr_fchown() fails, when restore_pipe_data() fails, when send_desc_to_peer() fails, and when rst_file_params() fails after one end has already been closed.

This adds a common err_close label that closes both ends, and closes tmp when rst_file_params() fails.

Closing tmp is safe because reopen_pipe() always closes the descriptor it is given and returns a new one, and the inherited-fd path sets pi->reopen before jumping to the reopen label, so every path reaching rst_file_params() owns tmp.

The tmp < 0 test is moved ahead of rst_file_params(), which makes the trailing tmp >= 0 guard redundant. Behaviour is otherwise unchanged.

Testing

  • make -j8 builds clean with no new warnings.
  • Found with gcc -fanalyzer. Note that the analyzer still reports a leak at the function exit after this change: it cannot resolve the computed index in pfd[!(pi->pe->flags & O_WRONLY)] and so cannot tell that the success path transfers the descriptor to the caller. That report is a false positive and is present both before and after this patch, so the analyzer does not confirm the fix; the error paths above were verified by inspection.

I was not able to exercise the failing paths end to end locally, as they need a restore to fail at exactly these points. Happy to add a test or take a different approach if you prefer.

open_pipe() creates a pipe pair with pipe(2) and then returns -1 from
three places without closing either end:

  - cr_fchown() fails while restoring pipe ownership
  - restore_pipe_data() fails
  - send_desc_to_peer() fails while handing a descriptor to a peer

A fourth descriptor is leaked after the reopen step.  Once one end has
been closed and tmp holds the surviving descriptor, a failing
rst_file_params() returns without closing it.

Closing tmp there is safe.  reopen_pipe() always closes the descriptor it
is given and returns a new one, and the inherited-fd path sets pi->reopen
before jumping to the reopen label, so every path that reaches
rst_file_params() owns tmp.

Add a common err_close label that closes both ends of the pipe, and close
tmp when rst_file_params() fails.  Test tmp for failure before using it,
which makes the trailing tmp >= 0 guard redundant.

Signed-off-by: Utkal Singh <singhutkal015@gmail.com>
Copilot AI lite review requested due to automatic review settings September 2, 2026 18:04

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟢 Approval recommended

The change is small, localized, and correctly closes all identified leaked descriptors without altering the success path behavior.

Pull request overview

This PR fixes a file-descriptor leak in CRIU’s pipe restore path by ensuring both ends of a newly created pipe are closed on early error returns in open_pipe(), and by closing the remaining end when rst_file_params() fails.

Changes:

  • Replace three return -1 error exits after pipe(pfd) with a shared err_close label that closes pfd[0] and pfd[1].
  • Reorder the tmp < 0 check ahead of rst_file_params() and remove the now-redundant tmp >= 0 guard.
  • Close tmp when rst_file_params() fails to prevent leaking the surviving pipe end.
File summaries
File Description
criu/pipes.c Adds a common error-cleanup path to close pipe FDs and plugs a leak when rst_file_params() fails.
Review details
  • Files reviewed: 1/1 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@codecov-commenter

codecov-commenter commented Sep 2, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 57.70%. Comparing base (90dd8ae) to head (4f444f2).
⚠️ Report is 3 commits behind head on criu-dev.

Files with missing lines Patch % Lines
criu/pipes.c 0.00% 10 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##           criu-dev    #3134      +/-   ##
============================================
- Coverage     57.72%   57.70%   -0.02%     
============================================
  Files           161      161              
  Lines         43920    43930      +10     
  Branches       9637     9635       -2     
============================================
- Hits          25351    25350       -1     
- Misses        18330    18341      +11     
  Partials        239      239              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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.

pipes: open_pipe() leaks pipe descriptors on error paths

3 participants