Security devs forced to hide Boolean logic from overeager optimizer [theregister.com]:
The creators of security software have encountered an unlikely foe in their attempts to protect us: modern compilers.
Today's compilers boil down code into its most efficient form, but in doing so they can undo safety precautions.
"Modern software compilers are breaking our code," said René Meusel [linkedin.com], sharing his concerns in a FOSDEM talk [fosdem.org] on February 1.
Meusel manages the Botan cryptography library and is also a senior software engineer at Rohde & Schwarz Cybersecurity.
As the maintainer of Botan, Meusel is cognizant of all the different ways encryption can be foiled. It's not enough to get the math right. Your software also needs to encrypt and decrypt safely.
Writing code to execute this task can be trickier than some might imagine. And the compilers aren't helping.
Meusel offered an example of the kind of problem he deals with implementing a simple login system.
The user types in a password, which gets checked against a database, character by character. Once the first character doesn't match, an error message is returned.
For a close observer trying to break in, the time it takes the system to return that error indicates how many letters of the guessed password the user has already entered correctly. A longer response time indicates more of the password has been guessed.
This side-channel leak has been used in the past to facilitate brute-force break-ins. It just requires a high-resolution clock that can tell the minuscule differences in response times.
Good thing cryptographers are a congenitally paranoid sort. They have already created preventive functions to equalize these response times to the user so they are not so revealing. These constant-time implementations "make the run time independent of the password," Meusel said.
The GNU C compiler is excellent with reasoning about Boolean values. It may be too clever. Like Microsoft Clippy-level clever.
Meusel ran a constant-time implementation through GCC 15.2 (with -std=c++23 -O3).
The loop to check the character exits early when the character is correct, so GCC assumed the rest of the function wasn't needed. But the rest of the code that actually fixed the timing was jettisoned, and the side-channel vulnerability was exposed once again. Thanks, GCC.
Meusel didn't get into why C optimizers have it in for Boolean comparisons, but good C programmers know to fear the aggressive optimization of Boolean logic, which can be hazardous [anandtech.com] to their finished products.
Boolean decisions mean branching, which is expensive for the hardware, so the compiler would just rather turn your branchful code [algorithmica.org] into branchless control-flow logic anyway, and that's cool, right?
The trick is to hide the semantics of this little program from the compiler, Meusel advised.
The first step is to replace the Boolean value that the loop is given with a two-bit integer, and use some bit shift or bitwise operations to mask the input (Meusel supplies the requisite code in his talk, so check out the slides [fosdem.org] for all the geeky goodness).
You would think this would do the job.
But GCC is smarter than that. It can see when you are trying to make a sneaky Boolean comparison.
So you need to apply an obfuscation function to both the input and the output. But not for any benefit to the program itself, but just because these are other values that the compiler could use "to screw us over," Meusel said.
And, finally, you need to throw the value through some inline assembly code that does absolutely nothing but return the same value. In effect it warns the compiler, which doesn't understand assembly, to not mess with these values however Boolean they may appear.
[...] There are a number of takeaways from Meusel's talk, the chief one being: maybe just switch off the optimization button [gnu.org] on GCC?
Nonetheless, compiler builders may want to consider factors other than code efficiency.
"They want to make your code fast, and they're really good at it, but they don't put any other qualitative requirements of your implementation into this consideration," Meusel said.