9 ms·
- 2x double-free Yes, it would be very weird to manage to do this in rust. It would require screwing up badly in unsafe code. I guess the most likely way to fu
by gpm 6y ago
- 2x double-free
Yes, it would be very weird to manage to do this in rust. It would require screwing up badly in unsafe code. I guess the most likely way to fuck up unsafe code in this way would be to screw up a custom datastructure like a custom reference counted pointer (but the obvious solution is to just use the standard ones).
- 8x NULL pointer dereference
Yes, rust tells you when pointers might be Null (which is represented by saying the pointer is Option<PointerType> instead of just PointerType), and doesn't let you use the pointer in a way that implicitly assumes it isn't null.
- 6x general protection
These are generally memory errors, and are certainly undefined behavior, so yes.
- 6x slab-out-of-bounds access
"Yes" with a small caveat, depending on how you are using the slab it is likely that Rust doesn't force you to explicitly think about the out of bounds case and turns just silently turns the security vulnerability into a runtime error, which might be handled farther up the stack or might cause the kernel to halt.
- 14x use-after-free access
Yes, like double frees. The range of possible fuckups in unsafe code that cause this is probably slightly larger than the equivalent range for double frees.
- _pmf_ 6y ago> These are generally memory errors, and are certainly undefined behavior, so yes. USB registers might be in DMA buffers or another memory location that might get mapped/unmapped at any point. Not everything fits a simplistic linear memory model.
- asveikau 6y agoThis is an interesting point. Rust's borrow checker or bounds checks probably also can't know about a page table change happening underneath it. Anyone want to correct me on that?
- monocasa 6y agoIt's pretty easy to wrap those constructs in RAII wrappers to replace or augment the normal reference counting that C code would be using to keep those buffers mapped, along with associating the lifetime of the relevant buffers with that refcnt. So it won't be perfect, but you can add safety versus what you get in C. You can even add safety versus what you'd get in C++ because of the lifetimes you can associate.
- asveikau 6y agoI know it's possible to reference count a page table mapping, in any language. My question is has anybody really attempted it in a rust kernel to make the sort of automatic safety measures we know rust for mean anything at all. It seems like if you really want correctness, every allocation must bump such a recount, which is very expensive.
- gpm 6y agoSo the general trick with reference counted pointers in rust, is that you don't have to touch the allocation count when creating a new pointer as long as you already have a pointer that you know lives for longer than your new pointer, and the rust type system will check that you didn't make a mistake when you thought you did. I.e. say I have a `x: Rc<[u8]>`, that is a ref counted pointer to some memory, and a length of that memory. I can do `let y: &[u8] = &x;`. `y` is now a not-ref counted pointer to the same memory (with the same length), that's guaranteed to be dropped before `x` is so the memory won't be freed from under it. I can also do `let z: &u8 = &x[5]`. `z` is now a pointer to a byte in `x`. Like `y` it's not ref counted and the compiler will force us to drop it before we drop `x`. You can make a whole allocator in this fashion (people have, even in the standard library I believe). If you get really clever you can probably even make an allocator in this fashion where the allocator doesn't use any unsafe code, you can easily make one where the users of the allocator don't need any unsafe code.
- gpm 6y agoThere's no fundamental reason why you couldn't write an abstraction around the page table that the rust borrow checker understands. The rust borrow checker works on the principle of ensuring that if you have a unique pointer (&mut) to something, nothing else can access it. If you have a shared pointer (&) to something, nothing else is mutating it except where internal mutability is explicitly marked (UnsafeCell, and abstractions using UnsafeCell such as Cell, RefCell, Mutex, RwLock, and so on). To mutate a page table entry you would need an &mut reference to it, to access a page you would need an & reference to the page table entry (from the &PageTableEntry you would get a &[u8] pointing to the data which the borrow checker would guarantee you drop before you drop the &PageTableEntry before anything mutates the PageTableEntry).
- steveklabnik 6y agoThis isn't exactly what you're asking about, but I really really love https://os.phil-opp.com/paging-implementation/ https://os.phil-opp.com/paging-implementation/ Shows you how you might implement paging, and how much unsafe you need to do so.
- pml1 6y agoSo the same argument that is made against the "mythical C programmer that never makes memory corruption mistakes" is also valid for the mythical Rust developer that never makes mistakes in unsafe code... It's two sides of the same coin.
- monocasa 6y agoExcept unsafe blocks are rare and heavily marked as "this is where the unsafeness is".
- pml1 6y agoIt won't be rare in driver code.
- monocasa 6y agoIt absolutely will, particularly in USB code. USB devices other than host controllers don't have memory mapped registers for instance, it's basically a network protocol.
- ComputerGuru 6y agoI’ve written bare metal code for rust that does networking and had only a handful of `unsafe` usages, and none after startup/init was completed. It’s actually really incredible how far “simple” shared-read-vs-exclusive-write bound checking and a very strict (but capable/likely Turing complete) type system can take you.
- samsari 6y agoExcept in rust unsafe code is very much not the norm, and much easier keep an eye on. Anyone writing rust worth their salt should be paying 5 times as close attention to every line of unsafe code for exactly this reason.
- spieglt 6y agoBut overall the two situations aren't nearly equivalent. Writing C, you're constantly at risk of making these mistakes. Writing Rust, you can keep the vast majority of your code safe and more closely examine the smaller unsafe area for memory errors. (In driver development, you may have to use more "unsafe" than for application development, but this doesn't negate the benefits. Also the compiler output is much more helpful.)
- josephcsible 6y agoI don't think Rust really makes NULL dereferences any better. In practice, a NULL dereference in C is almost always "just" a crash that can't be turned into something worse (unlike the rest of these kinds of bugs), and Rust makes it really easy to call "unwrap", which if your Option is None... crashes.
- gpm 6y agoExplicit `unwrap` (rust) is really orders of magnitude better than implicit `unwrap` (c dereference if you're lucky and the compiler hasn't optimized based on the assumption that the pointer is non-null). There aren't actually many explicit unwrap's in practical code, and they're something you notice when auditing or reviewing the code. The change in type means both the caller and the callee almost always agree on whether or not the contract is that "this pointer can be null" or "this pointer isn't null".
- cesarb 6y ago> In practice, a NULL dereference in C is almost always "just" a crash that can't be turned into something worse No, in C a NULL pointer dereference is not a crash, it's undefined behavior (which yes, can manifest as a crash), which is much more unpredictable.
- Tobu 6y agoIndeed. For anyone still believing a NULL dereference (or any of the other UB that is in the C spec) is just a segfault, "What Every C Programmer Should Know About Undefined Behavior" is still required reading: http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html http://blog.llvm.org/2011/05/what-every-c-programmer-should-... Here's how triggering UB ends up as a vulnerability: https://lwn.net/Articles/342330/ https://lwn.net/Articles/342330/
- suyjuris 6y ago> Here's how triggering UB ends up as a vulnerability To be fair, dereferencing NULL ended up as a vulnerability due to 1. the optimiser removing the subsequent NULL check, and 2. the zero page being mapped. While 1. may happen, depending on how sophisticated the compiler is, 2. was already a security issue and is 'almost always' not the case.