Race Conditions & TOCTOU
Last updated: 2026-04-10
Related: Use After Free, Architecture
Tags:race-condition,user-mode,kernel-mode
Summary
Race condition vulnerabilities arise when a security-critical operation assumes exclusive access to shared state but can be interrupted between a check and an action. In Windows, the most exploitable patterns are TOCTOU (Time-Of-Check-Time-Of-Use) in file/object operations, double-fetch bugs between user-mode and kernel-mode, and concurrent access to kernel objects. These bugs can yield arbitrary write primitives, privilege escalation, or sandbox escapes.
TOCTOU (Time-Of-Check-Time-Of-Use)
Pattern
1. CHECK: kernel validates user-supplied buffer/path/handle
2. ← RACE WINDOW: attacker modifies the checked resource
3. USE: kernel uses the now-modified resource assuming validation holds
Classic: File Path TOCTOU
1. Kernel: check if path "C:\User\file.txt" is safe
2. Attacker: rename symlink/directory → path now points to "C:\Windows\System32\file.txt"
3. Kernel: opens/writes to privileged path assuming prior check was valid
CVE Examples
- CVE-2015-1701 (TOCTOU in Client/Server Runtime): CreateSymbolicLink race → arbitrary file operation as SYSTEM
- CVE-2018-0743 (WSL TOCTOU): Windows Subsystem for Linux path race
- Stuxnet used a 0-day print spooler TOCTOU
- PrintNightmare variants (2021) — spooler TOCTOU on driver path validation
Double-Fetch Bugs
A kernel reads a user-mode value twice without re-validation — attacker modifies it between reads.
// Vulnerable kernel code:
ULONG size = *(ULONG*)UserBuffer; // FETCH 1: read size
if (size > MAX_SIZE) return ERROR; // check using size
// ...
ULONG size2 = *(ULONG*)UserBuffer; // FETCH 2: attacker changed UserBuffer[0] here!
memcpy(kernel_buf, src, size2); // use size2 → heap overflow
Why this happens:
- Performance optimization: reading from user memory is “cheap”
- Incorrect assumption that user memory is stable
- Missing
ProbeForRead+ copy-to-kernel-buffer pattern
Exploitation
- Thread 1: call vulnerable syscall with
size = VALID - Thread 2: spin loop writing
size = HUGEto buffer address - Race: kernel reads valid size, checks pass, re-reads huge size, copies too much
Tools: write racing thread that continuously modifies the value; usercallback fuzzing
CVE Examples
- CVE-2016-7255 (win32k double-fetch) — used in-the-wild by APT28
- CVE-2013-3660 (win32k, BITMAP double-fetch) — used in targeted attacks
Kernel UAF via Concurrent Object Manipulation
When two threads operate on the same kernel object concurrently:
Thread A: begin_operation(obj) ← increments refcount or takes lock
Thread B: destroy(obj) ← if refcount check has race, frees obj
Thread A: use(obj) ← obj already freed → UAF
win32k Callback Races
Win32k’s callback mechanism (calling user-mode during kernel operations) creates race windows:
Thread 1: win32k starts operation, calls user-mode callback
Thread 2: during callback, destroys shared win32k object
Thread 1: returns from callback, accesses freed object → UAF
This is the root cause of many win32k UAF CVEs (see Use After Free).
File System Races
Opportunistic Lock (OpLock) Races
- Request an OpLock on a file before a privileged process opens it
- When privileged process opens → OpLock callback to user-mode
- During callback: rename file, replace with symlink to privileged location
- Release OpLock → privileged process now operates on attacker-chosen file
CVE-2019-0841: Windows AppX installer TOCTOU via OpLock → DACL manipulation on privileged file → SYSTEM
Directory Junction / Symlink Abuse
NtCreateFilewithFILE_FLAG_OPEN_REPARSE_POINT+ directory junction- Windows supports object manager symlinks (
\??\C:\...) - Mount points + junctions can redirect file operations
- Combined with privileged process writing to “safe” path → redirect to system path
Tools:
CreateMountPoint.exe(Tyranid/James Forshaw)- NtApiDotNet symbolic link primitives
symboliclink-testing-tools— James Forshaw’s PoC tools
Semaphore / Lock Order Inversions
Deadlocks that degrade into races when locks are bypassed or ordered incorrectly:
- Lock A → Lock B (correct order)
- Thread 2: Lock B → Lock A (inverted)
- Result: race window between partial lock acquisition
In kernel: lock order violations in IRP handling, I/O completion paths, and DPC routines.
Exploitation Techniques
Winning the Race: Timing Strategies
- CPU core pinning: pin racing threads to specific cores for reproducible scheduling
- Priority manipulation: boost racing thread to just above vulnerable thread
- Pause sliding: use RDTSC-based spinning to align execution windows
- Event synchronization: use kernel events to synchronize entry into race window
- Large race window: prefer bugs where window spans a syscall (much larger window)
Kernel-Specific Race Amplification
- Use
NtSetInformationThread(ThreadPriority)to control scheduling - Spray system calls from multiple threads to create contention
- Use NPU timers (
NtSetTimerResolution) to increase scheduling granularity
Reliably Exploiting Races
- Target races with large windows (e.g., file operation with network involved)
- Use OpLock to pause execution at precise moment
- Practice: aim for >90% reliability before considering exploitable
Fuzzing for Race Conditions
- KAFL / WTF: can fuzz kernel paths with concurrent threads
- krace (research): kernel race fuzzer using coverage + thread interleaving
- Concurrence: record/replay-based race detection
- Manual: instrument suspected race paths with ETW events, observe ordering
Exploit Relevance
Race conditions / TOCTOU are especially valuable because:
- They often affect high-privilege components (installers, system services, kernel)
- They don’t require memory corruption — logic bugs
- They survive memory safety mitigations entirely (no ASLR/DEP relevance)
- File system races (OpLock + junction) are a repeating pattern with new instances every year
James Forshaw (Project Zero) has documented the most systematic Windows TOCTOU toolkit — study his work extensively.
References
- “Windows TOCTOU Exploitation” — James Forshaw (Project Zero)
- “symboliclink-testing-tools” — James Forshaw, GitHub
- “CVE-2019-0841” — SandboxEscaper analysis
- “OpLock-based races” — James Forshaw blog
- “Double-Fetch vulnerabilities in the Linux kernel” (cross-reference for methodology) — Wang et al.
- “Race Condition Exploitation on Windows” — Alex Ionescu
