Skip to content

Commit ccb55d4

Browse files
committed
Explain TOCTOU on the top of std::fs, and ref it in functions
Signed-off-by: xizheyin <xizheyin@smail.nju.edu.cn>
1 parent 337c11e commit ccb55d4

File tree

1 file changed

+28
-4
lines changed

1 file changed

+28
-4
lines changed

library/std/src/fs.rs

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,26 @@
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+
//! Be aware that metadata operations (like [`metadata`] or [`symlink_metadata`]) may be affected by
19+
//! changes made by other processes.
20+
//!
21+
//! To avoid TOCTOU issues:
22+
//! - Use atomic operations when possible (like [`File::create_new`] instead of checking existence then creating)
23+
//! - Keep file handles open for the duration of operations
24+
//! - Use file locking when appropriate
25+
//!
26+
//! Individual functions in this module document their specific TOCTOU considerations.
727
828
#![stable(feature = "rust1", since = "1.0.0")]
929
#![deny(unsafe_op_in_unsafe_fn)]
@@ -549,13 +569,14 @@ impl File {
549569
/// non-exhaustive list of likely errors.
550570
///
551571
/// 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
572+
/// exists and creating a new one, the file may have been created by another process (a [TOCTOU]
553573
/// race condition / attack).
554574
///
555575
/// This can also be written using
556576
/// `File::options().read(true).write(true).create_new(true).open(...)`.
557577
///
558578
/// [`AlreadyExists`]: crate::io::ErrorKind::AlreadyExists
579+
/// [TOCTOU]: self#time-of-check-to-time-of-use-toctou
559580
///
560581
/// # Examples
561582
///
@@ -1580,7 +1601,7 @@ impl OpenOptions {
15801601
///
15811602
/// This option is useful because it is atomic. Otherwise between checking
15821603
/// whether a file exists and creating a new one, the file may have been
1583-
/// created by another process (a TOCTOU race condition / attack).
1604+
/// created by another process (a [TOCTOU] race condition / attack).
15841605
///
15851606
/// If `.create_new(true)` is set, [`.create()`] and [`.truncate()`] are
15861607
/// ignored.
@@ -1591,6 +1612,7 @@ impl OpenOptions {
15911612
/// [`.create()`]: OpenOptions::create
15921613
/// [`.truncate()`]: OpenOptions::truncate
15931614
/// [`AlreadyExists`]: io::ErrorKind::AlreadyExists
1615+
/// [TOCTOU]: self#time-of-check-to-time-of-use-toctou
15941616
///
15951617
/// # Examples
15961618
///
@@ -2923,7 +2945,7 @@ pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
29232945
/// - "Windows": This function currently corresponds to `CreateFileW`,
29242946
/// `GetFileInformationByHandleEx`, `SetFileInformationByHandle`, and `NtCreateFile`.
29252947
///
2926-
/// ## Time-of-check to time-of-use (TOCTOU) race conditions
2948+
/// ## Time-of-check to time-of-use ([TOCTOU]) race conditions
29272949
/// On a few platforms there is no way to remove a directory's contents without following symlinks
29282950
/// unless you perform a check and then operate on paths based on that directory.
29292951
/// This allows concurrently-running code to replace the directory with a symlink after the check,
@@ -2935,6 +2957,7 @@ pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
29352957
/// - Redox OS: This function does not protect against TOCTOU races, as Redox does not implement
29362958
/// 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]
32263250
pub fn exists<P: AsRef<Path>>(path: P) -> io::Result<bool> {

0 commit comments

Comments
 (0)