I encountered a bug during development of my distributed workflow engine, and I learned that:
A TOCTOU (Time-of-Check to Time-of-Use) vulnerability is a software security issue that occurs when an attacker can alter a condition or variable between the moment a program checks its status (time-of-check) and the moment it uses that status (time-of-use). This is essentially a race condition.
How it works:
- Time-of-Check (TOC): A program checks a resource's state or a condition to ensure it is safe to proceed. For example, it checks if a file exists or if the user has permission to access it.
- Attacker Action: An attacker exploits the small window of time after the check but before the use to change the resource's state. For example, they might quickly replace the legitimate file with a malicious one or alter a symlink.
- Time-of-Use (TOU): The program proceeds with the operation based on the (now outdated or manipulated) information it gathered during the check.
Real-world example:
A common example involves file system operations, particularly in Unix-like systems:
- TOC: A program checks if a user is permitted to open a specific file (e.g.,
/tmp/safe_file). - Attacker Action: An attacker, in the brief moment after the check but before the file is opened, deletes
/tmp/safe_fileand creates a symbolic link (symlink) with the same name that points to a sensitive file (e.g.,/etc/shadow). - TOU: The program opens the file with elevated privileges, but it is now unknowingly accessing the sensitive
/etc/shadowfile through the symlink, potentially allowing the attacker to read or modify its contents.
Mitigation:
Mitigating TOCTOU vulnerabilities requires careful design:
- Locking: The most reliable way is to lock the resource immediately after the check and keep it locked until the use is complete.
- Atomic Operations: Using atomic system calls that perform the check and the use as a single, uninterrupted operation can prevent the race condition.
- Minimize Privileges: Running processes with the minimum necessary privileges reduces the potential impact if an exploit is successful.
- Careful Handling of Symlinks: Programs, especially those with high privileges, should be extremely cautious when interacting with user-controlled files or directories to avoid symlink vulnerabilities.
After noticing this, it took me days to fix the issue as these kind of problems are very hard to detect, specially in complex code. There are also other similar defects that you need to be aware of:
Database-Specific Concurrency Issues
These are classic concurrency problems that can become security vulnerabilities if not handled correctly:
- Lost Update Problem: When two transactions read the same data, both modify it, but the second transaction's update overwrites the first's, making the first update "lost".
- Dirty Read Problem (Uncommitted Dependency): A transaction reads data that has been written by another ongoing, but uncommitted, transaction. If the first transaction rolls back, the data read by the second becomes invalid.
- Non-Repeatable Read Problem: A transaction reads the same data twice but gets different values because another committed transaction modified the data in between the two reads.
- Phantom Read Problem: A transaction executes a query twice, but the second time, it sees a different set of rows (phantoms) due to another transaction inserting or deleting rows that match the query's criteria.
I hope it helps a bit, Cheers.