7 ms·
The author focuses on rewriting low-level media decoders in Rust. I have bit of experience in this area. I've been slowly working on an MPEG2 binary subtitle de
by ekidd 9y ago
The author focuses on rewriting low-level media decoders in Rust. I have bit of experience in this area. I've been slowly working on an MPEG2 binary subtitle decoder in Rust: https://github.com/emk/subtitles-rs https://github.com/emk/subtitles-rs
A while back, I ran my subtitle decoder through "cargo fuzz", and I was pleasantly surprised at the results: Close to half a billion fuzz runs found 5 runtime panics, all of which were detected by Rust before they could compromise security. If I'd written this code in C, several of those errors would have been exploitable. I like to think I'm a lot more paranoid than the average programmer. But the MPEG2 format is gnarly and, sooner or later, I'll miss a potential overflow when bit shifting, or get confused following internal "pointers" in a subtitle packet.
Rust has a few advantages for this work:
1. Rust does not require a garbage collector or other specialized runtime. This makes it far easier to pretend to be boring C code. This is a significant advantage over some other excellent languages like Haskell, etc., which require non-trivial runtimes.
2. Rust is very fast by default. For low-level programming, this matters.
3. The Rust infrastructure for testing and fuzzing is surprisingly good and easy to use, which makes it easier to produce bullet-proof libraries.
The downside is that even if you're already familiar with C++, it's probably going to take a couple of weeks to become comfortable with Rust. And if you don't really understand stacks, heaps, memory layout and references, it may take even longer.
I do agree with the underlying thesis: In 15 years, I'll be heartbroken if we're still facing an endless stream of security updates and remote root compromises. But it's going to require literally billions of dollars of programmer time to put a dent in this problem.
- yjftsjthsd-h 9y ago> Close to half a billion fuzz runs found 5 runtime panics, all of which were detected by Rust before they could compromise security. If I'd written this code in C, several of those errors would have been exploitable. Wouldn't the apples-apples comparison be fuzzing a C program? If AFL would catch the same bugs, Rust isn't better than C in this case.
- Jweb_Guru 9y agoThe difference is not in what was caught by AFL, but what wasn't (and also, what would have happened in C had AFL not been run).
- ekidd 9y ago> If AFL would catch the same bugs, Rust isn't better than C in this case. You can find a list of my vobsub bugs in the Rust Fuzz Trophy Case: https://github.com/rust-fuzz/trophy-case https://github.com/rust-fuzz/trophy-case They are: 1. The shift overflow: This was harmless in both C and Rust, I believe. 2. The arithmetic overflow: This was a runtime panic in Rust, resulting in a clean crash. In C, this might have been exploitable with a complex enough attack. 3. The three "invalid slice" errors. All of these were clean runtime panics in Rust, and I'm pretty sure that at least two of them would have been exploitable in C with enough work. So Rust has a couple of advantages here. Out of 5 errors found by the fuzzer, the worst thing that could happen in Rust would have been crashing the program in a controlled fashion. In C, we would have been looking at memory corruption and quite possibly escalation. Secondly, Rust's runtime checks actually make fuzzers work better. Even simple checks like "is the end index of this slice great >= to the beginning index?" tend to catch problems almost as soon as they occur.
- bandook_raja 9y agoI think you aren't understanding what parent comment is trying to say. No one is saying rust isn't better than C in some respects, instead, you were comparing Rust + Fuzzing with C and he implied that you should at least use C + AFL if you want to compare properly otherwise it's just BS.
- eridius 9y agoIt's a pointless comparison. Fuzzers don't catch everything. What's important is the type of issue that the fuzzers do reveal, because that gives a hint as to how severe the uncaught issues may be.
- jcelerier 9y agoYou would get 2. and 3. as runtime panic in C if you used sanitizers.
- the_why_of_y 9y agoYou would also get additional attack surface if you used sanitizers, because they were designed as debugging tools, not for production deployment. http://seclists.org/oss-sec/2016/q1/363 http://seclists.org/oss-sec/2016/q1/363
- Shoop 9y agoOne implication is that C would have had more errors, but that's a hard judgement to make. It's probably true. The thing that really matters is that these errors which the fuzzer found aren't exploitable -- memory errors in rust are guaranteed to panic (unsafe aside) instead of susceptible to overflows, etc. Since fuzzing is very much more of an art than a science, this guarantee is important.
- vertex-four 9y agoThe point here is that a runtime panic is not an exploitable event - at the very worst, it's a DoS as it usually results in the program exiting. AFL isn't even nearly guaranteed to catch everything, but what it's shown here is that the program contained bugs which would've resulted in an exploitable event in C. The program probably contains more bugs, but following this pattern, it's more likely that they result in panics in most of the worst cases, not exploitable events.
- hsivonen 9y agoWith Rust, a panic occurs right away when the fuzzer develops input that performs e.g. out of bounds access. With C, it's possible to go wrong a little but not enough to segfault or to go wrong enough that by accident the access looks valid (for an unintended valid memory address) to a sanitizer. In that sense, fuzzing Rust is more certain to make the bad things actually be caught than with C where there's a chance that the fuzzer developed input that caused UB but the UB didn't happen to be caught by the mechanisms that are supposed to discover bad events during fuzzing.
- deleted 9y ago[deleted]
- rurban 9y agoI don't agree with the underlying thesis: In 15 years, I'll be heartbroken if we're still facing an endless stream of security updates and remote root compromises when all these projects were rewritten in a popular but unsafe language: Rust. There do exist fast and SAFE language out there. With guaranteed memory safety, null pointer safety, concurrency safety, dead-lock freedom, race freedom, and even with normal syntax. Rust is not one of them. When will all these rust fanboys finally see the light?
- dikaiosune 9y agoCan you be specific about which languages you include in the category of "fast and SAFE"?
- bandook_raja 9y agoD? GC is optional so don't even :D
- dikaiosune 9y agoHow much of the standard library works without GC enabled? How many community libraries do? D has a lot of great things (I am incredibly jealous of their metaprogramming facilities sometimes), but it doesn't seem like many people are successfully using it in the "fast and SAFE" sense as GP defined it.
- bandook_raja 9y ago> How much of the standard library works without GC enabled? How many community libraries do? Enough to be usable on virtually all platforms that rust is going to target in next 2 years. I hope I'll get proven wrong but that's it for now. And maybe along the time we'll see some decoupling of stdlib from GC too. OTOH some people like GC too :)
- qznc 9y ago
- danenania 9y agoIs there any way to lessen the burden by automating conversion of straightforward portions of a C codebase to Rust? They seem similar enough conceptually and semantically, if not syntactically, that a lot of boring C code might be fairly easy to translate?
- steveklabnik 9y agohttps://github.com/jameysharp/corrode/ https://github.com/jameysharp/corrode/
- Animats 9y agoThat doesn't convert C to Rust. It compiles C into Rust as a target language, bugs and all. Raw pointers in C become raw pointers in Rust.
- danenania 9y agoYeah, I suppose the larger challenge is how to convert unsafe C to safe Rust.
- Animats 9y agoMost of the problems revolve around "how big is it". (The three big problems in C are "how big is it", "who owns it", and "who locks it". C has no language constructs for any of those, while Rust does.) If a C program works at all, there has to be some computable expression for the length of a C array. Code that uses an array passed as a pointer has to know how big the array is, even though C lacks a language construct for this. The problem is finding that expression. For many cases, it can be automatically inferred, especially if you have cross-module analysis and can see where the original array came from. I once proposed an extension to C to allow expressing array size information.[1] Discussions indicated it was technically sound but politically too much trouble. It gives a hint, though, of how to approach size information in C. Instead of int read(int fd, char buf[], size_t len); one would write int read(int fd, char& buf[len], size_t len); Same generated code for the call, but now the source code contains size information, which could be used for subscript checking by the caller and callee. A serious C to Rust converter needs to be able to detect relationships like that. It doesn't have to be 100% automatic. If the converter could knock off most of the easy cases (especially those involving strings), and accept hints on the hard ones, it could be usable. [1] http://www.animats.com/papers/languages/safearraysforc43.pdf http://www.animats.com/papers/languages/safearraysforc43.pdf