Skip to content

fix(realpath): reject non-directory path components and forcing them to ENOTDIR - #16153

Open
Martell0x1 wants to merge 3 commits into
uutils:mainfrom
Martell0x1:fix/realpath-parent-dir-not-directory
Open

Martell0x1 wants to merge 3 commits into
uutils:mainfrom
Martell0x1:fix/realpath-parent-dir-not-directory

Conversation

@Martell0x1

@Martell0x1 Martell0x1 commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Problem

uutils realpath incorrectly accepts paths containing a regular file followed by ...

For example, /tmp/example/file/.. succeeds in uutils, whereas GNU realpath fails with ENOTDIR (Not a directory).

The implementation removes the preceding component when encountering ParentDir without verifying that the component is a directory.

Root Cause

In src/uucore/src/lib/features/fs.rs, the ParentDir branch performs:

OwningComponent::ParentDir => {
    result.pop();
}

This removes the preceding component without validating whether it can be traversed as a directory.

Fix

Validate path components before resolving ParentDir, rejecting non-directory and nonexistent intermediate components where required by the selected resolution mode.

Tests

  • Added regression tests covering invalid file/parent-directory traversal and valid directory/parent-directory traversal.
  • Tested against the realpath feature:
cargo test --no-default-features --features realpath
  • Manually verified behavior using regular files, directories, and symlinks.

Requires #16161
Closes #16117

Copilot AI balanced review requested due to automatic review settings November 3, 2026 01:46

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing. Review the Copilot code review billing settings.

@codspeed

codspeed Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Merging this PR will not alter performance

1 warning, 1 note

⚠️ 123 benchmarks are dominated by system calls

System calls cannot be simulated consistently and are left out of the measure. The reported value understates the real cost. Switch to the Walltime instrument to measure them.

Learn more about system calls

See affected benchmarks

ℹ️ 1 benchmark has no flamegraph

The flamegraph wasn't generated: most of the time was spent in runtime internals, which would leave nothing useful to analyze.

See affected benchmarks

✅ 401 untouched benchmarks
⏩ 70 skipped benchmarks1


Comparing Martell0x1:fix/realpath-parent-dir-not-directory (3cc5e18) with main (f1ae8f1)

Open in CodSpeed

Footnotes

  1. 70 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. ↩

@Martell0x1
Martell0x1 force-pushed the fix/realpath-parent-dir-not-directory branch from 2f1fa3d to 3cc5e18 Compare November 3, 2026 09:12
Copilot AI balanced review requested due to automatic review settings November 3, 2026 09:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing. Review the Copilot code review billing settings.

@Martell0x1

Copy link
Copy Markdown
Contributor Author

@codspeedbot explain why performance improved

Comment thread src/uucore/src/lib/features/fs.rs Outdated
OwningComponent::CurDir => {}
OwningComponent::ParentDir => {
// checking for current component
if !result.as_os_str().is_empty() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this also runs with MissingHandling::Missing, so realpath -m missing/.. and -m file/.. fail now, GNU accepts both
please skip the check in that mode and add a -m test

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

ignored the check for MissingHandler::Missing

Comment thread src/uucore/src/lib/features/fs.rs Outdated
Ok(meta) if meta.is_dir() => {}
Ok(_) => {
return Err(Error::new(ErrorKind::NotADirectory, "Not a directory"));
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

why rebuild a NotFound error? Err(e) => return Err(e) is enough

Comment thread src/uucore/src/lib/features/fs.rs Outdated
OwningComponent::CurDir => {}
OwningComponent::ParentDir => {
// checking for current component
if !result.as_os_str().is_empty() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

could you please reuse ensure_is_directory(&result)? here? it already gives ENOTDIR, without the hardcoded strings

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

Comment thread tests/by-util/test_realpath.rs Outdated

// spell-checker:ignore nusr

use uucore::util_name;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

util_name is already imported from uutests, does this compile?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

actually it did , i guess as rust allows importing the same macro's name but from different paths

.ucmd()
.arg("regular_file/..")
.fails()
.code_is(1)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

the issue also mentions -L, -e and readlink -f, please add tests for them
-L still goes through normalize_path, so it isn't fixed yet

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yes i totaly forgot to add Logical path support .

Comment thread tests/by-util/test_realpath.rs Outdated

at.mkdir("directory");

scene.ucmd().arg("directory/..").succeeds();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

please check the stdout too, not only the exit code

Copilot AI balanced review requested due to automatic review settings November 3, 2026 14:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing. Review the Copilot code review billing settings.

@Martell0x1
Martell0x1 requested a review from sylvestre November 3, 2026 14:31
@Martell0x1
Martell0x1 force-pushed the fix/realpath-parent-dir-not-directory branch from e7c8a6b to 8fbaeb1 Compare November 3, 2026 14:39
Copilot AI balanced review requested due to automatic review settings November 3, 2026 14:39

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing. Review the Copilot code review billing settings.

This branch has not been deployed

No deployments
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.

realpath: "file/.." resolves lexically instead of failing with ENOTDIR

3 participants