44//! filesystem. All methods in this module represent cross-platform filesystem
55//! operations. Extra platform-specific functionality can be found in the
66//! extension traits of `std::os::$platform`.
7+ //!
8+ //! # Time of Check to Time of Use (TOCTOU)
9+ //!
10+ //! Many filesystem operations are subject to a race condition known as "Time of Check to Time of Use"
11+ //! (TOCTOU). This occurs when a program checks a condition (like file existence or permissions)
12+ //! and then uses the result of that check to make a decision, but the condition may have changed
13+ //! between the check and the use.
14+ //!
15+ //! For example, checking if a file exists and then creating it if it doesn't is vulnerable to
16+ //! TOCTOU - another process could create the file between your check and creation attempt.
17+ //!
18+ //! Another example is with symbolic links: when removing a directory, if another process replaces
19+ //! the directory with a symbolic link between the check and the removal operation, the removal
20+ //! might affect the wrong location. This is why operations like [`remove_dir_all`] need to use
21+ //! atomic operations to prevent such race conditions.
22+ //!
23+ //! To avoid TOCTOU issues:
24+ //! - Be aware that metadata operations (like [`metadata`] or [`symlink_metadata`]) may be affected by
25+ //! changes made by other processes.
26+ //! - Use atomic operations when possible (like [`File::create_new`] instead of checking existence then creating).
27+ //! - Keep file open for the duration of operations.
728
829#![ stable( feature = "rust1" , since = "1.0.0" ) ]
930#![ deny( unsafe_op_in_unsafe_fn) ]
@@ -549,13 +570,14 @@ impl File {
549570 /// non-exhaustive list of likely errors.
550571 ///
551572 /// This option is useful because it is atomic. Otherwise between checking whether a file
552- /// exists and creating a new one, the file may have been created by another process (a TOCTOU
573+ /// exists and creating a new one, the file may have been created by another process (a [ TOCTOU]
553574 /// race condition / attack).
554575 ///
555576 /// This can also be written using
556577 /// `File::options().read(true).write(true).create_new(true).open(...)`.
557578 ///
558579 /// [`AlreadyExists`]: crate::io::ErrorKind::AlreadyExists
580+ /// [TOCTOU]: self#time-of-check-to-time-of-use-toctou
559581 ///
560582 /// # Examples
561583 ///
@@ -1580,7 +1602,7 @@ impl OpenOptions {
15801602 ///
15811603 /// This option is useful because it is atomic. Otherwise between checking
15821604 /// whether a file exists and creating a new one, the file may have been
1583- /// created by another process (a TOCTOU race condition / attack).
1605+ /// created by another process (a [ TOCTOU] race condition / attack).
15841606 ///
15851607 /// If `.create_new(true)` is set, [`.create()`] and [`.truncate()`] are
15861608 /// ignored.
@@ -1591,6 +1613,7 @@ impl OpenOptions {
15911613 /// [`.create()`]: OpenOptions::create
15921614 /// [`.truncate()`]: OpenOptions::truncate
15931615 /// [`AlreadyExists`]: io::ErrorKind::AlreadyExists
1616+ /// [TOCTOU]: self#time-of-check-to-time-of-use-toctou
15941617 ///
15951618 /// # Examples
15961619 ///
@@ -2924,17 +2947,17 @@ pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
29242947/// `GetFileInformationByHandleEx`, `SetFileInformationByHandle`, and `NtCreateFile`.
29252948///
29262949/// ## Time-of-check to time-of-use (TOCTOU) race conditions
2927- /// On a few platforms there is no way to remove a directory's contents without following symlinks
2928- /// unless you perform a check and then operate on paths based on that directory.
2929- /// This allows concurrently-running code to replace the directory with a symlink after the check,
2930- /// causing a removal to instead operate on a path based on the symlink. This is a TOCTOU race.
2931- /// By default, `fs::remove_dir_all` protects against a symlink TOCTOU race on all platforms
2932- /// except the following. It should not be used in security-sensitive contexts on these platforms:
2933- /// - Miri: Even when emulating targets where the underlying implementation will protect against
2934- /// TOCTOU races, Miri will not do so.
2935- /// - Redox OS: This function does not protect against TOCTOU races, as Redox does not implement
2936- /// the required platform support to do so.
2950+ /// See the [module-level TOCTOU explanation](self#time-of-check-to-time-of-use-toctou).
2951+ ///
2952+ /// On most platforms, `fs::remove_dir_all` protects against symlink TOCTOU races by default.
2953+ /// However, on the following platforms, this protection is not provided and the function should
2954+ /// not be used in security-sensitive contexts:
2955+ /// - **Miri**: Even when emulating targets where the underlying implementation will protect against
2956+ /// TOCTOU races, Miri will not do so.
2957+ /// - **Redox OS**: This function does not protect against TOCTOU races, as Redox does not implement
2958+ /// the required platform support to do so.
29372959///
2960+ /// [TOCTOU]: self#time-of-check-to-time-of-use-toctou
29382961/// [changes]: io#platform-specific-behavior
29392962///
29402963/// # Errors
@@ -3208,7 +3231,7 @@ impl AsInnerMut<fs_imp::DirBuilder> for DirBuilder {
32083231/// permission is denied on one of the parent directories.
32093232///
32103233/// Note that while this avoids some pitfalls of the `exists()` method, it still can not
3211- /// prevent time-of-check to time-of-use (TOCTOU) bugs. You should only use it in scenarios
3234+ /// prevent time-of-check to time-of-use ([ TOCTOU] ) bugs. You should only use it in scenarios
32123235/// where those bugs are not an issue.
32133236///
32143237/// # Examples
@@ -3221,6 +3244,7 @@ impl AsInnerMut<fs_imp::DirBuilder> for DirBuilder {
32213244/// ```
32223245///
32233246/// [`Path::exists`]: crate::path::Path::exists
3247+ /// [TOCTOU]: self#time-of-check-to-time-of-use-toctou
32243248#[ stable( feature = "fs_try_exists" , since = "1.81.0" ) ]
32253249#[ inline]
32263250pub fn exists < P : AsRef < Path > > ( path : P ) -> io:: Result < bool > {
0 commit comments