-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Explain TOCTOU
on the top of std::fs
, and reference it in functions
#141847
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
Open
xizheyin
wants to merge
1
commit into
rust-lang:master
Choose a base branch
from
xizheyin:141837
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,27 @@ | |
//! filesystem. All methods in this module represent cross-platform filesystem | ||
//! operations. Extra platform-specific functionality can be found in the | ||
//! extension traits of `std::os::$platform`. | ||
//! | ||
//! # Time of Check to Time of Use (TOCTOU) | ||
//! | ||
//! Many filesystem operations are subject to a race condition known as "Time of Check to Time of Use" | ||
//! (TOCTOU). This occurs when a program checks a condition (like file existence or permissions) | ||
//! and then uses the result of that check to make a decision, but the condition may have changed | ||
//! between the check and the use. | ||
//! | ||
//! For example, checking if a file exists and then creating it if it doesn't is vulnerable to | ||
//! TOCTOU - another process could create the file between your check and creation attempt. | ||
//! | ||
//! Another example is with symbolic links: when removing a directory, if another process replaces | ||
//! the directory with a symbolic link between the check and the removal operation, the removal | ||
//! might affect the wrong location. This is why operations like [`remove_dir_all`] need to use | ||
//! atomic operations to prevent such race conditions. | ||
//! | ||
//! To avoid TOCTOU issues: | ||
//! - Be aware that metadata operations (like [`metadata`] or [`symlink_metadata`]) may be affected by | ||
//! changes made by other processes. | ||
//! - Use atomic operations when possible (like [`File::create_new`] instead of checking existence then creating). | ||
//! - Keep file open for the duration of operations. | ||
|
||
#![stable(feature = "rust1", since = "1.0.0")] | ||
#![deny(unsafe_op_in_unsafe_fn)] | ||
|
@@ -549,13 +570,14 @@ impl File { | |
/// non-exhaustive list of likely errors. | ||
/// | ||
/// This option is useful because it is atomic. Otherwise between checking whether a file | ||
/// exists and creating a new one, the file may have been created by another process (a TOCTOU | ||
/// exists and creating a new one, the file may have been created by another process (a [TOCTOU] | ||
/// race condition / attack). | ||
/// | ||
/// This can also be written using | ||
/// `File::options().read(true).write(true).create_new(true).open(...)`. | ||
/// | ||
/// [`AlreadyExists`]: crate::io::ErrorKind::AlreadyExists | ||
/// [TOCTOU]: self#time-of-check-to-time-of-use-toctou | ||
/// | ||
/// # Examples | ||
/// | ||
|
@@ -1580,7 +1602,7 @@ impl OpenOptions { | |
/// | ||
/// This option is useful because it is atomic. Otherwise between checking | ||
/// whether a file exists and creating a new one, the file may have been | ||
/// created by another process (a TOCTOU race condition / attack). | ||
/// created by another process (a [TOCTOU] race condition / attack). | ||
/// | ||
/// If `.create_new(true)` is set, [`.create()`] and [`.truncate()`] are | ||
/// ignored. | ||
|
@@ -1591,6 +1613,7 @@ impl OpenOptions { | |
/// [`.create()`]: OpenOptions::create | ||
/// [`.truncate()`]: OpenOptions::truncate | ||
/// [`AlreadyExists`]: io::ErrorKind::AlreadyExists | ||
/// [TOCTOU]: self#time-of-check-to-time-of-use-toctou | ||
/// | ||
/// # Examples | ||
/// | ||
|
@@ -2924,17 +2947,17 @@ pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> { | |
/// `GetFileInformationByHandleEx`, `SetFileInformationByHandle`, and `NtCreateFile`. | ||
/// | ||
/// ## Time-of-check to time-of-use (TOCTOU) race conditions | ||
/// On a few platforms there is no way to remove a directory's contents without following symlinks | ||
/// unless you perform a check and then operate on paths based on that directory. | ||
/// This allows concurrently-running code to replace the directory with a symlink after the check, | ||
/// causing a removal to instead operate on a path based on the symlink. This is a TOCTOU race. | ||
/// By default, `fs::remove_dir_all` protects against a symlink TOCTOU race on all platforms | ||
/// except the following. It should not be used in security-sensitive contexts on these platforms: | ||
/// - Miri: Even when emulating targets where the underlying implementation will protect against | ||
/// TOCTOU races, Miri will not do so. | ||
/// - Redox OS: This function does not protect against TOCTOU races, as Redox does not implement | ||
/// the required platform support to do so. | ||
/// See the [module-level TOCTOU explanation](self#time-of-check-to-time-of-use-toctou). | ||
/// | ||
/// On most platforms, `fs::remove_dir_all` protects against symlink TOCTOU races by default. | ||
/// However, on the following platforms, this protection is not provided and the function should | ||
/// not be used in security-sensitive contexts: | ||
/// - **Miri**: Even when emulating targets where the underlying implementation will protect against | ||
/// TOCTOU races, Miri will not do so. | ||
/// - **Redox OS**: This function does not protect against TOCTOU races, as Redox does not implement | ||
/// the required platform support to do so. | ||
Comment on lines
+2950
to
+2958
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I refactored the contents in #141832. I moved the synbolic TOCTOU race example to the top of |
||
/// | ||
/// [TOCTOU]: self#time-of-check-to-time-of-use-toctou | ||
/// [changes]: io#platform-specific-behavior | ||
/// | ||
/// # Errors | ||
|
@@ -3208,7 +3231,7 @@ impl AsInnerMut<fs_imp::DirBuilder> for DirBuilder { | |
/// permission is denied on one of the parent directories. | ||
/// | ||
/// Note that while this avoids some pitfalls of the `exists()` method, it still can not | ||
/// prevent time-of-check to time-of-use (TOCTOU) bugs. You should only use it in scenarios | ||
/// prevent time-of-check to time-of-use ([TOCTOU]) bugs. You should only use it in scenarios | ||
/// where those bugs are not an issue. | ||
/// | ||
/// # Examples | ||
|
@@ -3221,6 +3244,7 @@ impl AsInnerMut<fs_imp::DirBuilder> for DirBuilder { | |
/// ``` | ||
/// | ||
/// [`Path::exists`]: crate::path::Path::exists | ||
/// [TOCTOU]: self#time-of-check-to-time-of-use-toctou | ||
#[stable(feature = "fs_try_exists", since = "1.81.0")] | ||
#[inline] | ||
pub fn exists<P: AsRef<Path>>(path: P) -> io::Result<bool> { | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Here,
TOCTOU
create
andremove_dir_all
, from simple to complex.TOCTOU
.