Skip to content

fix: eliminate TOCTOU races in ln and tac by deferring is_dir() checks#10991

Merged
sylvestre merged 4 commits intouutils:mainfrom
abendrothj:fix/is_dir_TOCTOU_and_err_msgs
Feb 26, 2026
Merged

fix: eliminate TOCTOU races in ln and tac by deferring is_dir() checks#10991
sylvestre merged 4 commits intouutils:mainfrom
abendrothj:fix/is_dir_TOCTOU_and_err_msgs

Conversation

@abendrothj
Copy link
Contributor

@abendrothj abendrothj commented Feb 17, 2026

ln: call hard_link() first, check is_dir() only on failure for diagnostics
tac: remove is_dir()/metadata() pre-checks, open file directly and let OS report errors (EISDIR, ENOENT)

Matches GNU coreutils behavior: operate first, diagnose after.

"it's better to ask for forgiveness, rather than for permission"

Closes #9450

@abendrothj abendrothj force-pushed the fix/is_dir_TOCTOU_and_err_msgs branch 2 times, most recently from bcf8fdc to e177167 Compare February 17, 2026 08:40
@github-actions
Copy link

GNU testsuite comparison:

GNU test failed: tests/misc/io-errors. tests/misc/io-errors is passing on 'main'. Maybe you have to rebase?
Skipping an intermittent issue tests/pr/bounded-memory (passes in this run but fails in the 'main' branch)
Congrats! The gnu test tests/dd/no-allocate is now passing!
Congrats! The gnu test tests/seq/seq-epipe is now passing!

@abendrothj abendrothj force-pushed the fix/is_dir_TOCTOU_and_err_msgs branch from dffafc3 to 9cf958c Compare February 17, 2026 09:31
@codspeed-hq
Copy link

codspeed-hq bot commented Feb 17, 2026

Merging this PR will not alter performance

✅ 294 untouched benchmarks
⏩ 42 skipped benchmarks1


Comparing abendrothj:fix/is_dir_TOCTOU_and_err_msgs (e8b98bc) with main (9ac174b)

Open in CodSpeed

Footnotes

  1. 42 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@github-actions
Copy link

GNU testsuite comparison:

GNU test failed: tests/date/date-locale-hour. tests/date/date-locale-hour is passing on 'main'. Maybe you have to rebase?
Congrats! The gnu test tests/dd/no-allocate is now passing!

@abendrothj abendrothj force-pushed the fix/is_dir_TOCTOU_and_err_msgs branch from 8af5b77 to ac10014 Compare February 17, 2026 09:49
@github-actions
Copy link

GNU testsuite comparison:

GNU test failed: tests/date/date-locale-hour. tests/date/date-locale-hour is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/tail/pipe-f2. tests/tail/pipe-f2 is passing on 'main'. Maybe you have to rebase?
Skipping an intermittent issue tests/pr/bounded-memory (passes in this run but fails in the 'main' branch)
Note: The gnu test tests/tail/tail-n0f is now being skipped but was previously passing.
Congrats! The gnu test tests/dd/no-allocate is now passing!
Congrats! The gnu test tests/seq/seq-epipe is now passing!

@github-actions
Copy link

GNU testsuite comparison:

Skipping an intermittent issue tests/pr/bounded-memory (passes in this run but fails in the 'main' branch)
Congrats! The gnu test tests/dd/no-allocate is now passing!

ln: call hard_link() first, check is_dir() only on failure for diagnostics
tac: remove is_dir()/metadata() pre-checks, open file directly and let OS report errors (EISDIR, ENOENT)

Closes uutils#9450
- Remove `(os error 28)` from test_failed_write_is_reported expectation
  to match the intentional strip_errno() behavior
@abendrothj abendrothj force-pushed the fix/is_dir_TOCTOU_and_err_msgs branch from a3a28ef to e8b98bc Compare February 23, 2026 08:24
@github-actions
Copy link

GNU testsuite comparison:

Note: The gnu test tests/env/env-signal-handler was skipped on 'main' but is now failing.

@github-actions
Copy link

GNU testsuite comparison:

GNU test failed: tests/date/resolution. tests/date/resolution is passing on 'main'. Maybe you have to rebase?
Note: The gnu test tests/unexpand/bounded-memory is now being skipped but was previously passing.

@abendrothj abendrothj force-pushed the fix/is_dir_TOCTOU_and_err_msgs branch 2 times, most recently from 6e26c55 to e8b98bc Compare February 23, 2026 10:09
@github-actions
Copy link

GNU testsuite comparison:

Note: The gnu test tests/env/env-signal-handler was skipped on 'main' but is now failing.

@abendrothj abendrothj force-pushed the fix/is_dir_TOCTOU_and_err_msgs branch 2 times, most recently from 06621c4 to e8b98bc Compare February 25, 2026 11:03
@sylvestre sylvestre merged commit b08532a into uutils:main Feb 26, 2026
418 of 468 checks passed
@abendrothj abendrothj deleted the fix/is_dir_TOCTOU_and_err_msgs branch February 27, 2026 02:55
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.

Using Path::is_dir() leads to many TOCTOU races.

2 participants