Skip to content

Conversation

sami-daniel
Copy link

@sami-daniel sami-daniel commented Jun 1, 2025

Fixes #518

Create function check_path_integrity which checks
the integrity of the path, with the following criteria:

  • Only absolute paths
  • Only non-empty paths
  • Only directories in path

If the PATH env var does not pass the criteria, an error is returned warning about the specific path part that caused that error.

It was not possible to write tests for the changes, only to check if there were regressions. To test the changes, it would be necessary to change the PATH at test runtime. The only way to do this is through the operating system API wrapper provided in std::env::set_var. In order to use this API, you must ensure that no other thread is reading or writing from any place other than a single place, thus avoiding data races and concurrency.
Unfortunately, the command engine that findutils currently use to execute other commands together with find comes from std::process::Command, and it uses the PATH to find the command to be executed. lazy_static would not work in this case either. A possible solution would be to change the CI's to run only cargo test -- test-threads=1, but I think the tradeoff would not be worth it for such a simple change. Besides the fact that other tests are reading variables that we just changed, then probably many executables would not be found

Copy link

codecov bot commented Jun 1, 2025

Codecov Report

❌ Patch coverage is 87.77293% with 28 lines in your changes missing coverage. Please review.
✅ Project coverage is 87.18%. Comparing base (d55e2f9) to head (38f994c).
⚠️ Report is 20 commits behind head on main.

Files with missing lines Patch % Lines
src/find/matchers/exec.rs 87.77% 26 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #553      +/-   ##
==========================================
+ Coverage   87.15%   87.18%   +0.02%     
==========================================
  Files          31       31              
  Lines        6300     6529     +229     
  Branches      324      328       +4     
==========================================
+ Hits         5491     5692     +201     
- Misses        578      604      +26     
- Partials      231      233       +2     

☔ View full report in Codecov by Sentry.
📢 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.

@sylvestre
Copy link
Contributor

could you also please add tests (with error mgmt)? thanks

@sami-daniel
Copy link
Author

could you also please add tests (with error mgmt)? thanks

done

@sami-daniel
Copy link
Author

could you also please add tests (with error mgmt)? thanks

done

Ok, I will fix these errors that are occurring on Windows before sending another push.

Fixes uutils#518

Create function check_path_integrity which checks
the integrity of the path, with the following criteria:

- Only absolute paths
- Only non-empty paths
- Only directories in path

If the PATH env var does not pass the criteria,
an error is returned warning about the specific
path part that caused that error.

Tests:

- Added tests for both SingleExecMatcher and MultiExecMatcher
- Covered all PATH validation scenarios:
  * Valid absolute directories
  * Empty path segments
  * Relative path segments
  * File paths instead of directories
- Ensured safe environment variable handling with unsafe blocks
- Maintained consistent test patterns with existing serial tests
- Verified correct error handling for invalid PATH configurations

To avoid making the function that performs the check public,
tests were also added that verify that there is no error
with a valid PATH.
@sami-daniel
Copy link
Author

Since we cannot test in the exec.rs file, I couldn't test (directly) the check_path_integrity function. So, the codecov will probably point out an error at this point. However, tests have been added to validate the correct behavior of the Matchers creation to work around this issue.

@sami-daniel sami-daniel requested a review from tavianator June 10, 2025 18:00
@sami-daniel sami-daniel force-pushed the main branch 5 times, most recently from 5f16fc5 to 744e55c Compare June 11, 2025 13:00
}
}
} else {
return Err("PATH environment variable is not defined.".into());
Copy link
Contributor

Choose a reason for hiding this comment

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

This shouldn't be an error. If PATH is unset, there is a default value to use, which in C is confstr(_CS_PATH). Not sure what it should be on Windows.

Copy link
Author

Choose a reason for hiding this comment

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

I didn't find any wrapper or high level API around this. I guess we should use the libc crate for it

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah I wouldn't block this PR over that, it might be a bit of work to wrap libc nicely.

Copy link
Author

Choose a reason for hiding this comment

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

The problem is _CS_PATH may not be available on non-posix compliant system. I guess we should use libc::confstr(...) on Unix and on Windows we can use C:\Windows\system32;C\Windows as a PATH fallback.

Copy link
Author

Choose a reason for hiding this comment

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

Haha, we don't need to use libc::confstr or do any further validation just remove the else branch

Copy link
Contributor

Choose a reason for hiding this comment

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

Good point! Generally the default $PATH is only absolute paths, nothing to worry about. On Windows I think by default the current directory is searched.

Copy link
Author

Choose a reason for hiding this comment

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

I guess there are two possibilities.
First: PATH = None, it will not validate anything. There is no risk, because without PATH, there is no way to have something invalid.

Second: Windows, even without PATH, creates a "fake" PATH and runs the process. If there is an invalid path, it will fail the check. I think the point here is: What is the behavior of Command when it gets to it and the PATH is empty? Will it use confstr in Posix compliant and in Windows on will use current directory or will it not search because it does not have the PATH?

I think we can explore the internals of Command, but I did not find any documentation on this.

Copy link
Author

Choose a reason for hiding this comment

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

Hello again. Doing a little more research, I found this thread on Quora.

Basically, it says that everything depends on the shell and the OS. There's no way to predict it because it depends on several uncontrollable factors: the variable inheritance process, whether the path uses a fallback, etc. It might be safer to simply fail if the PATH isn't present. If Windows sets the PATH as the current directory, we'll find out by iterating through the PATH and checking it. This way, there's no way for it to run insecurely and we guarantee integrity.

renamed: check_path_integrity -> check_path_entries_absolute

The function check_path_entries_absolute now only looks for paths that are not absolute or that are empty.
In addition, if possible, if there is any error related to the PATH, show the exact segment where the error occurred.

tests:

The tests that used to reside in exec_unit_tests.rs are now in exec.rs, directly handling a fake of the PATH for testing,
eliminating the need to mark tests with #[serial] or use unsafe { env::set_var(...) }.

Co-authored-by: Tavian <tavianator@tavianator.com>
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.

find: -execdir should ensure secure PATH variable
3 participants