24 ms·
> Our work highlights that current defensive programming techniques are more akin to anecdotal workarounds to compilers’ behavior rather than a systematic solut
by kibwen 2y ago
> Our work highlights that current defensive programming
techniques are more akin to anecdotal workarounds to
compilers’ behavior rather than a systematic solution.
Our results point out that high-level constant-time code is prone to dangerous transformations and optimizations from compilers and calls for cooperation between developers of
security-critical libraries and general-purpose compilers.
All optimizing compilers perform optimizations based on the notion of an abstract machine, which determines what semantics of the original program must be conserved. And the abstract machine for a given language is usually provided by the language that is being implemented (except for e.g. languages that just give up and say "give me C's abstract machine").
You definitely don't want compiler backends trying to "guess" when some defensive programming technique is being used, so that they can compile it conservatively. That's a dead-end pathway to madness. You need languages to give you the power to explicitly say "this operation is constant time, don't mess with it". And in practice they do give you this power, via inline assembly. Of course inline assembly is suboptimal for a lot of reasons, and we can certainly try to do better, but this is a language design problem, not an optimizing compiler problem.
- the8472 2y agoNot just the abstract machines. CPUs don't guarantee constant-time execution for most instructions. And if you target wasm or some other intermediate compilation target then the first compiler can't do much about the 2nd compiler applying additional optimizations. And then there are post-link optimizations where any hypothetical "please don't optimize this" annotations would be gone.
- pclmulqdq 2y agoIn a theoretical sense only, that is true on x86 when a flag (that is always set) is not set. The vast majority of useful instructions are constant-time (in the value of the data).
- nullc 2y agoIndeed, but the manufacturer doesn't promise anything-- for all you know the next processor generation or even microcode revision could change that. It would be nice for processor makers to explicitly specify that the common arithmetic instructions will take time which is constant in terms of their argument data.
- pclmulqdq 2y agoThey are explicitly specified by all major CPU vendors. https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/best-practices/data-operand-independent-timing-isa-guidance.html https://www.intel.com/content/www/us/en/developer/articles/t...
- nullc 2y agoTIL -- wasn't the case a number of years ago.
- adrian_b 2y agoNowadays the manufacturer must promise that at least a well-defined subset of the instructions have an execution time independent of the operands. See the comment above by "cokernel_hacker", which provides links to the Intel and Arm documentation of this feature.
- GTP 2y agoA thing that I've been wondering is, would it be enough in this specific case to turn off compiler optimizations, e.g. by using GCC's -O0 flag?
- photochemsyn 2y agoLibsodium does this compiler-specific pragmas and attributes (like __attribute__((optimize("O0")))). It's also the cryptographic library mentioned in this study with the smallest number of discovered issues, but: > "However, we want to note that libsodium is the smallest library that we test with the most limited support for cryptographic primitives. For example, libsodium does not support the elliptic curve secp256; instead,they do all of their elliptic curve operations on curve25519. Therefore, it may be unfair to compare to larger libraries with support for more cryptographic primitives."
- GTP 2y agoThanks, the fact that they still found issues answers my question.
- badmintonbaseba 2y ago"The optimize attribute should be used for debugging purposes only. It is not suitable in production code." https://gcc.gnu.org/onlinedocs/gcc-14.2.0/gcc/Common-Function-Attributes.html https://gcc.gnu.org/onlinedocs/gcc-14.2.0/gcc/Common-Functio...
- jedisct1 2y ago> Libsodium does this compiler-specific pragmas and attributes (like __attribute__((optimize("O0")))) It doesn't do anything like that.
- SAI_Peregrinus 2y agoIn general, no. Optimizations from a compiler can't do anything regular code gen isn't allowed to do. It's just they're more likely to do some things. So in practice disabling optimization (especially using pragmas or attributes for certain critical functions) can help, but it can't be considered truly reliable.
- secondcoming 2y agomemset isn’t part of any abstract machine, yet compilers feel free to optimise that out, so we needed to add new functions that compilers wouldn’t touch.
- gavinsyancey 2y agoThe C language specification describes what memset does. If a program calls memset, compilers must make it behave as if an actual call to the memset function (as described in the standard) was made, for all observable effects that matter to the abstract machine.
- pjc50 2y ago.. unless the compiler spots UB anywhere near the function call, in which case all bets are off.
- amluto 2y agoI think a good solution involves more than operations. Consider: int a = read_a_value(); a = constant_time_add(a+1); do_something_with(a); In many languages, the compiler is free to insert entirely new operations between these statements so long as the output isn’t affected. Or the compiler could reuse a register that contained a to do something else and do something awful like zeroing that register in non-constant time. I think that new types are a better solution. A type could be specified such that the compiler must not use its value in a non-constant time operation, nor may the compiler leak it into an initialized value.
- pjmlp 2y agoThe problem is the programming language culture, in some circles, if guessing is going too far, the compiler writers will rather opt for safety, while other language communities will stop at nothing for the ultimate performance, nitromethan powered optimising compiler.
- pjc50 2y agoC has enough security questions hanging around it; for things like constant time operation, which has AFAIK never been promised anywhere in the C standards (and probably can't be!), I think the only reasonable solution is a new language specifically designed for the purpose. Not for writing whole programs in, but for writing fairly small amounts of code that performs arithmetic and compiles to libraries with C linkage. No VM, not even any memory allocation (make the caller do that in advance with fixed-size areas). Basically the "portable assembler" that people keep using C for despite its explicit promises in the standard to not be that.
- PaulDavisThe1st 2y ago> the only reasonable solution is a new language specifically designed for the purpose. actual assembler is just such a language, as is being discussed here.
- pjc50 2y agoSure - but that's not a portable language at all! Nor is it an especially good target for any kind of formal verification or even type-checking.
- saagarjha 2y agoNeither is C, to be fair.
- PaulDavisThe1st 2y agoGiven that to meet constant-time requirements, the language will need to guarantee more or less 1-for-1 (or more generally, M-for-N) translation to assembler, I don't think you're going to improve on the verification or type checking situation by changing the syntax to something else.
- fuhsnn 2y agoConstant-time programming itself isn't quite portable, RISC-V for example requires the Zkt extension to mandate it.