Winning the race against TOCTOU vulnerabilities in C & C++
Security is an eternal race between the techniques and technologies of attackers and those of the defenders. Today, I'm proud to announce a step forward for defenders with a new rule to detect a literal race condition: TOCTOU (or TOCTTOU) vulnerabilities, known in long-form as Time Of Check (to) Time Of Use.
With TOCTOU, the idea is that there's a window of opportunity between when a privileged program checks a file (Does the file exist? Are permissions okay for what we're about to do? …) and when it operates on that file (Create the file. Write to the file. …). In that window, an attacker could replace the file with e.g. a symlink to `/etc/passwd`, and the operation you meant to perform on `/home/ann/tmp` happens to an important system file instead.
Now, you may think that window, and thus the opportunity, is vanishingly small. To be honest, I did when I first encountered this. But researchers have shown that it's still exploitable when the OS interjects a system interrupt between the check and the use. In fact, those researchers were somewhat surprised to see their attack succeed 85% of the time even when the critical operations were "separated only by a few milliseconds." And other researchers have shown that it's possible to crank the exploitation window wide open with an attack called a "filesystem maze".
So this is serious stuff, and not just in a theoretical way. For instance, there was the Docker TOCTOU reported in 2018 that allowed root access to the host filesystem. And then there was the TOCTOU in the Pulse Secure VPN client for Windows reported earlier this year that allowed an attacker to gain administrative rights on the machine. Both of those now-fixed vulnerabilities are registered as entries in the Common Vulnerabilities and Exposures (CVE) list. At this writing, there are 96 TOCTOU CVEs. And those are only the ones that the white hats have found and reported!
That's why we've introduced rule S5847, Accessing files should not introduce TOCTOU vulnerabilities, for C, C++, and Objective-C (more languages "soon"!) to detect TOCTOU vulnerabilities in your code. Here's an example from an internal test project:
I've said this already, but it's worth pointing out again that even though the `fopen` is written right after the access check, it may not run right after in a multi-tasking environment, i.e. any modern OS.
So okay, you're convinced! S5847 is available today on SonarCloud and in SonarQube 8.5+, and you're going to activate it immediately in your Quality Profile and reanalyze. And then what? If even back-to-back commands are still vulnerable, what's a poor programmer to do? Well, the first choice is using an atomic operation if one is available. When it's not, grab a file descriptor in the check - it will be mapped to the file itself - and use it instead of the file name in subsequent operations. That way, your target file can't be swapped out from under you. Your sysadmin and your users will thank you.