6 ms·
I'm gonna go ahead and say it: Perhaps in retrospect C is an inappropriate choice of language for these kinds of applications. This "Performance at all costs,
by bunderbunder 12y ago
I'm gonna go ahead and say it: Perhaps in retrospect C is an inappropriate choice of language for these kinds of applications.
This "Performance at all costs, including safety and predictability" thing may be appropriate in video games, but for security-critical applications that philosophy is downright negligent.
- tedunangst 12y agoI'm not aware of any language that would be better. Most languages don't even let you touch memory to try to zero it.
- swift 12y agoMany languages zero every allocation unless they can prove that you immediately write over that memory without reading it.
- deleted 12y ago[deleted]
- tedunangst 12y agoWhich does nothing for memory which has been freed but not reallocated.
- swift 12y agoThat's a great point; should've thought through that post a little better. Thanks.
- marvy 12y agoYes, but that's going the wrong direction. The situation here is that you've already written over it, and now wish to erase what you wrote.
- bunderbunder 12y agoA language that wouldn't give you a way to zero out data wouldn't be appropriate for security-critical tasks either. Just like how a language that doesn't do array bounds checking and permits pointer math (read: a language where buffer overflows are a damn feature) isn't appropriate for security critical tasks. Just like how a language that must be actively fought using clever hacks in order to prevent it from undermining your attempts to guard against common exploit vectors isn't appropriate for security critical tasks.
- ufo 12y agoZeroing out an array or struct field is not a C-specific feature.
- tedunangst 12y agoDead store elision is not a C specific optimization.
- jacksingleton 12y agoThis is what Mozilla is trying to create with Rust http://www.rust-lang.org/ http://www.rust-lang.org/
- userbinator 12y agoThere's basically only one (or a family of) languages that have no optimisation at all, and enable complete control over what the machine does - Asm. The code you get is exactly the code you write, no matter how efficient or inefficient it is. This also enables much better the prevention of other attacks like timing/power analysis, since you can effectively insert dummy instructions as needed to keep the timing and power well-behaved. The biggest downside I see is that it's non-portable, but the reality is that there's not all that many architectures out there to port to anyway (x86, ARM, MIPS probably covers 90%+) and for truly security-critical code having that level of control could be worth it. (This also avoids the "trusting the compiler" problem - an assembler is far easier to verify correctness of than even the simplest C compiler...)
- dllthomas 12y ago"There's basically only one (or a family of) languages that have no optimisation at all" ... sort of. Chips themselves perform some optimizations.
- schoen 12y agoI think I heard of a timing attack that was introduced by CPU optimizations, not in the underlying code at all! But I can't remember what research that was and maybe I'm confusing two different issues.
- dllthomas 12y agoCertainly plausible. If the CPU optimizes one path but not another, in principle that's some information. In practice, gathering enough data to get that above the noise floor and turning it into something useful besides would certainly be difficult but maybe not too difficult.
- schoen 12y agoI might be thinking of some of the cache timing issues about sharing physical hardware with other guest VMs. There were papers in the last two years showing circumstances in which another VM on the same device can learn about secrets in caches via timing experiments. But that's a cache issue rather than a general pipeline issue. So I still can't remember if there's something else that I'm thinking of or if I'm just confusing it with the cache stuff. http://blog.cryptographyengineering.com/2012/10/attack-of-week-cross-vm-timing-attacks.html http://blog.cryptographyengineering.com/2012/10/attack-of-we... More recent stuff in this vein: https://eprint.iacr.org/2014/435.pdf https://eprint.iacr.org/2014/435.pdf (Yikes!)
- pcwalton 12y agoDead store elimination is a really important optimization, and it comes out of bog-standard compiler optimizations like SROA on SSA form IR. You really want your compiler to perform it for acceptable performance.
- bunderbunder 12y agoYes. But dead store elimination combined with being allowed to dereference arbitrary pointers and leaving newly allocated blocks of memory uninitialized is problematic. Contrary to what the C standard would like us to believe, those other features do mean that dead store elimination alters the semantics of a program. It doesn't impact the semantics of the procedure whose dead stores are being eliminated, but it alters the semantics of arbitrary operations elsewhere in the program because it could influence the result I get when I dereference a pointer dereference or examine the contents of a newly-allocated block of memory. In most cases that distinction is nit-picky. It can be perfectly reasonable for the language to throw up its hands, shout "undefined behavior", and just assume that whatever random uncontrolled thing happens won't be too terrible, assuming whatever your program does isn't too important. But for security-critical applications it's a really stinking important distinction, because the range of possible behaviors found in the "undefined" category includes things like Heartbleed.
- pcwalton 12y agoIf your compiler couldn't perform dead store elimination on memory (remember, memory includes allocas), then you'd lose most of the benefits of performing standard SSA form optimizations after SROA has happened. Essentially you'd kill scalar replacement of aggregates, which is a critical optimization. It's very important for performance that it allowed to happen.
- bunderbunder 12y agoNote that I'm not saying that dead store elimination is the problem. I'm saying that dead store elimination in combination with other language features is a problem. Dead store elimination is not unique to C. But those other language features are. Since I'm complaining about C in particular, I submit that the bit that I'm most worried about isn't the stuff that every language does. That said, I realize that allowing data that's hypothetically disappeared forever into the free() black hole to come back into the universe through white holes such as malloc() and buf[buf_length] aren't the only reasons why you'd want to make for sure that you can clear out unused memory. Which is why it would be nice if the C spec also included some way to securely clear up memory that the compiler isn't allowed to defeat. No, an optional feature in a spec that's only 3 years old and mostly not supported isn't good enough. If it isn't ubiquitous it's not a whole lot more useful than any of the platform- and architecture-specific fixes that already exist.
- maxlybbert 12y agoC may have pitfalls for "these kinds of applications," but it has some strengths that other languages don't. Since C gives the programmer significant control over memory allocation, it's possible to avoid various kinds of timing attacks related to cache misses (possible is not the same as easy). Many languages don't give the programmer the necessary tools to do that.
- dllthomas 12y agoThere are two different things you can mean when you say "C is not suitable to these kinds of applications". One is the more extreme, "You should not be using C, you should be using <other existing language> because it is more suitable." That's a bit of a hard sell; though specific alternatives should be evaluated on their merits. There is also, "there are design choices that have been made in C that make it worse for these applications than C would have been were it not for those choices", which seems an easy case to make.
- maxlybbert 12y agoThe funny thing to me is that the standard crypto packages for other languages nearly always end up calling C code.
- dllthomas 12y agoThat's not at all incompatible with "C is the best option of existing languages, but still bad in some obvious ways where it could be better (for this purpose)."
- maxlybbert 12y agoTrue.
- PhasmaFelis 12y agoC/C++ are like Formula 1 racing cars: indispensable if you need to go really, really fast; wildly impractical in all other situations.
- exDM69 12y ago> C/C++ are like Formula 1 racing cars ... I can't agree with this comparison at all. It may be true if speed is what you want but that's not the only reason. C (and to a lesser extent, C++) are indispensable in lots of situations where you're working close to the metal. There are very few viable alternatives when working with kernel space code, micro controllers or embedded applications as well as crypto primitives. Rust is perhaps the only language that can be used instead of C and C++ in these applications. I'd liken C more to a heavy duty vehicle, something that most people never need but there's no replacement for the tasks it is intended for.
- ygra 12y agoI'm not sure how this depends on the language, per se. Basically you want very special behaviour here: Allocate a piece of memory, preferrably so that it doesn't end up accidentally in permanent storage and later clear it and deallocate it again. C gives you no such facilities to do so, but so do very few other languages (if any). The correct course here would rather be to ask the OS to do that for you. You can tell the memory allocator to never page out the block you get. Every OS has a syscall to zero memory that isn't subject to compiler optimisations. Honestly, in my eyes, this is a place where the language is specified in a way that it cannot ever guarantee what you're trying to achieve and in that case you're best off not relying on the language, but on other things that can make such guarantees.