12 ms·
Cve-rs: Fast memory vulnerabilities, written in safe Rust
- WirelessGigabit 3y agoIt's weird to see lifetime correlations expressed as &'a &'b and not with where 'a: 'b I suppose I don't understand enough of how the first is different from the second one, and how it impacts this issue.
- dannymi 3y agoIt's just a reference to a reference. It has nothing to do with lifetime correlations. Also, it's a lot less weird if you don't stop in the middle of the type. The entire type is for example &'a &'b u8 or &'a &'b () So the outer reference has lifetime 'a and the inner reference has lifetime 'b.
- Georgelemental 3y ago> It has nothing to do with lifetime correlations Yes it does; there's an implied `'b: 'a` outlives relationship that's required for the type to be well-formed.
- kbknapp 3y agoIn fact, I believe that's exactly where this bug lies. You're effectively able to trigger a case in which passing `&'a &'b` without providing any correlation (`where 'a: 'b`) that one would normally be required to provide makes the compiler behave as if those correlations were passed, albeit inferred incorrectly.
- LegionMammal978 3y agoThe first one creates an implied bound, while the second is an explicit bound. The important thing about implied bounds is that they allow late binding of lifetimes to function pointers (or closures): that is, you can have a single function pointer type like "for<'a> fn(&'a str)" that can be called with any lifetime 'a. Here, the lifetime 'a is called "late-bound", since it can be different with each call. In contrast, if a lifetime is subject to an explicit where bound, it must be "early-bound": each function pointer can must choose one particular value for that lifetime, that must be upheld for every call. For a practical example, you might have tried to declare a closure with a &T parameter, only to get lifetime errors when you call it twice. This is because the lifetime in the closure type is early-bound and must be the same for every call. (Sometimes the compiler figures out that a late-bound lifetime is desired, but the rules are very subtle. This is also why it's difficult to write a function that accepts a generic async closure.) Late binding is necessary for certain kinds of variance, which is a big part of this issue. Function pointers are contravariant in their parameters, which means if you have a type like "fn(&'short str)", you can cast it to "fn(&'static str)", since a 'static reference will always be valid for 'short. They're also covariant in their return type, so that "fn() -> &'static str" can be cast into "fn() -> &'short str". But when performing these variance transformations with late-bound lifetimes, the compiler doesn't always take into account the implied bounds in the source type properly, which allows you to perform casts that aren't actually sound.
- WirelessGigabit 3y agoEdit (since I cannot edit my comment after 2 hours): for the code to properly verify the lifetimes one needs to write where 'b: 'a meaning 'b is at least as useful as 'a. So 'b can live the same time, or longer, but not less.
- robinsonrc 3y agoIt’s good to see that at least Miri catches the issues. Hopefully the compiler can catch up with that!
- vlovich123 3y agoDoes polonius catch the issue?
- throwawaymaths 3y agoIf you need a compiler sidecar anyways, why not just have a simpler language where all the borrow checking is done in a sidecar?
- dralley 3y agoYou don't "need" a compiler sidecar unless you're specifically writing code to exploit obscure bugs. This is a 0.0001% case
- throwawaymaths 3y agoyeah or if you're using someone else's code that you're trusting doesn't have "obscure bugs" put there to smuggle in a vuln.
- dralley 3y agoNonetheless, it's far less of an issue than in any other language. You don't need 20 lines of crazy code to slip a serious security vulnerability into C, you can add one with a single character changed half of the time.
- pcwalton 3y agoThis is exaggerated re. C, but it is true that the important thing for practical security is whether memory safety is violated in practice, and obscure compiler bugs you have to go out of your way to try to exploit don't affect that. That being said, this bug is pretty bad, and it should be fixed. I should point out that the reason the bug is difficult seems to mainly be because of backwards compatibility concerns. If compatibility weren't an issue, Rust could just ban function contravariance and nobody would care.
- dralley 3y agoSeems to rely on at least one known compiler bug (admittedly one open since 2015) https://github.com/rust-lang/rust/issues/25860 https://github.com/rust-lang/rust/issues/25860
- dgfitz 3y agoLooking at the syntax in that bug report makes me think I could never learn rust.
- faitswulff 3y agoYou could also think of it as "look at all the weird syntax olympics you need to do in order to trigger a compiler edge case!"
- jrockway 3y agoThe crazier the reproduction, the more interesting the bug. A trivial bug isn't an interesting. A bug where two edge cases interact to do something more than the sum of parts is quite interesting. You learn something about the edge where there's an interaction, and the underlying system as a whole. (Have you ever looked at a fuzzer-generated failing piece of data and not though "oh whoa good point". That's interesting!)
- the_mitsuhiko 3y agoThat is not syntax you would ever see.
- wredue 3y agoI wrote pretty basic rust stuff and had to use lifetime syntax quite a bit. If you are just forcing deep copies all the time, you might not see it often, but if you're just going to deep copy everything always, you’re probably going to be better off with another language to be honest as you’re tossing away much of the benefit of using a language like rust anyway.
- Karellen 3y ago> GLWTS(Good Luck With That Shit) Public License > The author has absolutely no fucking clue what the code in this project does. It might just fucking work or not, there is no third option. lol
- omoikane 3y agoSounds like an updated version of WTFPL https://en.wikipedia.org/wiki/WTFPL https://en.wikipedia.org/wiki/WTFPL
- infamouscow 3y ago[flagged]
- steveklabnik 3y agoI don't know what you mean. This is a compiler bug? Nobody claims that other compilers must also have the exact same bugs.
- adastra22 3y agoIt is a compiler bug, yes.
- steveklabnik 3y agoSorry, I was typing the way I talk again, this doesn't always come across well in text. Yes, thanks for making sure that's known.
- nicklecompte 3y agoIt's really a bug in the design of Rust itself, not in the implementation of rustc: https://counterexamples.org/nearly-universal.html?highlight=Rust#nearly-universal-quantification https://counterexamples.org/nearly-universal.html?highlight=... The fix needs to happen at the level of type-theoretic computer science, not clever Rust programming. And in particular, an alternate implementation of Rust which fixes this bug would have a different type system than rustc, and arguably should be considered a separate dialect of Rust (at least unless rustc is updated accordingly).
- steveklabnik 3y agoI think in the same way that you are frustrated because people say "it's a compiler bug" too often, this feels like going in the other direction too much. The higher order bit, to me, is the "segfault in safe code means a bug" stance that the overall project takes. Soundness holes happen. Sometimes they take a while to transition away from. Arguing that the compiler faithfully implements an algorithm that causes bugs still means, from a higher perspective, that the compiler has a bug: they have chosen an inappropriate algorithm here. There is no specification of the specific implementation here. Rust could in fact (at least in theory, I am not an expert on this specific problem) transition to a different path here where the bug does not manifest. RFC 1214 is an example of the Rust Project successfully doing this, and hilariously enough, that situation is one of the things that led to this one!
- adastra22 3y agoWhat’s your shell prompt config that you screenshotted in the README?
- xal 3y agolooks like https://starship.rs/ https://starship.rs/
- hpb42 3y agoOh, cool. They implemented a `download_more_ram()` function![0] Does it crash safely as well? I did not test it, I more than 640 KB of ram. - [0] https://github.com/Speykious/cve-rs/blob/d51f52dd64f148a086e0b2ac4059c9c99a212c68/src/lib.rs#L92-L116 https://github.com/Speykious/cve-rs/blob/d51f52dd64f148a086e...
- foolswisdom 3y agoWhat a wonderful license! https://github.com/Speykious/cve-rs/blob/main/LICENSE https://github.com/Speykious/cve-rs/blob/main/LICENSE
- poly_morphis 3y agoI could get behind that type of short, clear legalese.
- deleted 3y ago[deleted]
- yjftsjthsd-h 3y ago> 0. You just DO WHATEVER THE FUCK YOU WANT TO as long as you NEVER LEAVE A FUCKING TRACE TO TRACK THE AUTHOR of the original product to blame for or held responsible. A thing of beauty^_^ I've seen a lot of licenses that require attribution[0], so a license that explicitly demands that you not credit the author is a lovely twist:) [0] Read: Nearly all of them; even permissive BSD-like licenses usually(?) require that much.
- saagarjha 3y agoAre you the safest because you're Rust? Or are you Rust because you are the safest?
- datadeft 3y agoThe real question is: what is the chance that somebody runs into this while implementing something common.
- vacuity 3y agoIt's not about frequency; it's about the possibility that just one of these unsoundness bugs gets through to production and screws things up. The whole point of memory safety languages is that, unless you (or a dependency author) dives into the dark arts of whatever language you're working in, you are guaranteed to not encounter use-after-free or null-pointer-dereference. Practically, maybe such a bug gets patched quickly, and no one exploits it as a vulnerability. In hindsight, then, it wasn't so bad. But you don't want to be the one who is called at 2 AM because an impossible segfault happened and wrecked the database.
- fweimer 3y agoWithout compiler bugs, on stock Linux, you can achieve the same thing via /proc/self/mem. Rust makes this very easy because you can get the raw address from safe code, so no guessing is required which memory location to patch. For the compiler bug, as someone who never strayed into those regions of Rust programming, it's not clear to me how likely it is that someone would write such code by accident and introduce a memory safety issue into their program. I browsed the Github issues, but couldn't find an indicator how people encountered this in the first place.
- jcmoyer 3y ago>Without compiler bugs, on stock Linux, you can achieve the same thing via /proc/self/mem. The documentation addresses this case specifically: https://doc.rust-lang.org/stable/std/os/unix/io/index.html#procselfmem-and-similar-os-features https://doc.rust-lang.org/stable/std/os/unix/io/index.html#p... "Rust’s safety guarantees only cover what the program itself can do, and not what entities outside the program can do to it. /proc/self/mem is considered to be such an external entity..."
- fweimer 3y agoThe /proc/self/mem thing shouldn't be a problem because you won't run into it accidentally. What I'm wondering if this compiler bug is in the same category, or if a Rust programmer is somewhat likely to run into this bug by accident (or other I-unsound compiler bugs) if their approach is more or less “tweak things until they typecheck and pass the borrow checker”.
- steveklabnik 3y agoI have been programming in Rust since late 2012. I don’t think I have ever run into a soundness bug like this in the wild. That doesn’t mean that it never happens, but it is a very rare occurrence, not something that Rust programmers deal with regularly.