-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
fix(install): prevent symlink race condition in install -D (fixes #10013) #10140
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
fix(install): prevent symlink race condition in install -D (fixes #10013) #10140
Conversation
|
GNU testsuite comparison: |
fc7eade to
0b91865
Compare
|
GNU testsuite comparison: |
Merging this PR will not alter performance
Comparing Footnotes
|
|
The 3.46% performance regression is an acceptable trade-off for fixing the symlink race condition vulnerability. The safe directory traversal using file descriptors adds unavoidable overhead, but prevents potential security exploits. |
|
GNU testsuite comparison: |
|
sorry but could you please rebase it ? thanks |
agreed |
fe7aec2 to
4fb0779
Compare
|
some conflicts, sorry |
4fb0779 to
f95bed7
Compare
|
There, that should resolve the conflicts :) |
|
GNU testsuite comparison: |
|
The sort regression is benchmark noise - this PR only touches |
|
This is a lot of added complexity and I think you could have a bit more polish before submitting for review :/ |
Yeah that was rough, won't happen again |
|
GNU testsuite comparison: |
b804df6 to
d138468
Compare
|
GNU testsuite comparison: |
|
GNU testsuite comparison: |
|
GNU testsuite comparison: |
| /// Copy a file using directory file descriptor for safe traversal. | ||
| /// This prevents symlink race conditions when creating target files. | ||
| #[cfg(unix)] | ||
| fn copy_file_safe(from: &Path, to_parent_fd: &DirFd, to_filename: &std::ffi::OsStr) -> UResult<()> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
some code duplication with copy_file it seems
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These can't be easily consolidated as they have different semantics:
copy_file_safe: fd-based (open_file_at), truncates existing files
copy_file: path-based (create_new), removes first, includes directory override check
Both are used: copy_file_safe at line 774 (safe -D path), copy_file at line 1148 (regular installs). Consolidating would require multiple match branches and obscure the distinct behaviors.
|
GNU testsuite comparison: |
b06f16f to
268e92d
Compare
|
Failures seem unrelated to my PR and it looks like theres a decision to make on upstream- cargo-deny: time v0.3.47 requires Rust 1.88.0 but the project's MSRV is 1.85.0. This will affect all PRs and main too. Upstream needs to either bump MSRV or add an ignore for it, definitely out of my bounds in this PR. |
|
GNU testsuite comparison: |
…ils#10013) This commit fixes a TOCTOU (Time-of-Check-Time-of-Use) race condition in the install -D command where an attacker could replace a directory component with a symlink between directory creation and file installation, redirecting writes to an arbitrary location. Changes: - Added mkdir_at() and open_file_at() methods to DirFd for safe operations - Added open_no_follow() to prevent following symlinks when opening directories - Added create_dir_all_safe() function that uses directory file descriptors - Modified install -D to use safe traversal functions instead of pathname-based ops - Added copy_file_safe() function for safe file copying using directory fds - Added tests to verify the fix prevents symlink race conditions The fix works by: 1. Using directory file descriptors (mkdirat/openat) instead of pathnames 2. Keeping directory fds open throughout the operation 3. Detecting and removing symlinks before directory creation 4. Anchoring all file operations to directory file descriptors This eliminates the race window by ensuring all critical operations use directory file descriptors that cannot be replaced by symlinks.
… and boolean simplifications
…x context setting to Linux platforms This commit updates the conditional compilation for SELinux context settings in the install module to only apply when the target OS is Linux. This change ensures that SELinux-related functionality is not erroneously included on non-Linux platforms, improving compatibility and preventing potential issues. Changes: - Modified `#[cfg(feature = "selinux")]` to `#[cfg(all(feature = "selinux", target_os = "linux"))]` in multiple locations to enforce the OS-specific behavior.
…s a file When -t is used with -D and the target exists as a file (not a directory), we should fail immediately without printing verbose directory creation messages. This matches GNU behavior and fixes the failing GNU test tests/install/basic-1.
- Replace std::io::copy() with copy_stream() for consistency and splice optimization - Consolidate DirFd::open() and open_subdir() to take follow_symlinks parameter - Extract finalize_installed_file() helper to reduce code duplication - Add documentation for security behavior (symlink removal) and mode handling - Clean up verbose comments
268e92d to
d694c9e
Compare
d694c9e to
a1ef268
Compare
|
GNU testsuite comparison: |
|
it looks great, i will wait for the ci to finish |
This PR fixes a TOCTOU (Time-of-Check-Time-of-Use) race condition in the install -D command where an attacker could replace a directory component with a symlink between directory creation and file installation, redirecting writes to an arbitrary location.
Changes
mkdir_at()andopen_file_at()methods toDirFdfor safe operationsopen_no_follow()to prevent following symlinks when opening directoriescreate_dir_all_safe()function that uses directory file descriptorscopy_file_safe()function for safe file copying using directory fdsHow the Fix Works
The fix prevents the race condition by:
mkdirat/openat) instead of pathnamesThis eliminates the race window by ensuring all critical operations use directory file descriptors that cannot be replaced by symlinks.
Testing
Fixes #10013