4 ms·
For kernel-level programming, I think Rust is basically the same as C or C++ in this regard. I haven't seen a kernel written in Rust where I am convinced there
by cwzwarich 9y ago
For kernel-level programming, I think Rust is basically the same as C or C++ in this regard. I haven't seen a kernel written in Rust where I am convinced there is a submodule that can be treated as if its correctness doesn't impact the safety of the entire kernel.
- Rusky 9y ago> a submodule that can be treated as if its correctness doesn't impact the safety of the entire kernel. You don't have to go all that way to be better than C or C++. Rust can give you a submodule A whose correctness doesn't impact the safety of any uses of submodule B.
- cwzwarich 9y agoIf the correctness of submodule A impacts the safety of the entire kernel, then it impacts the safety of the uses of any other submodule, because you can't really contain the consequences of the unsafe behavior.
- Rusky 9y ago> you can't really contain the consequences of the unsafe behavior. That's true, but the property I described can still help you track down the root cause and limit the number of places that interact with it.
- TheDong 9y agoI don't understand this argument at all. "Rust is not perfect, so it's basically the same as C" The fact that "american fuzzy lop" and "syzkaller" have gone through the kernel and found dozens of use-after-free's (see https://github.com/google/syzkaller/blob/4bd70f/docs/linux/found_bugs.md https://github.com/google/syzkaller/blob/4bd70f/docs/linux/f...), shows that even incredibly carefully programmed C messes up in totally rote ways. The basic cleanup code which is able to be exploited here would not be in an unsafe block if this were rust. In fact, because rust abstracts memory management out better, most of the cleanup code wouldn't exist at all. Rust also allows better abstractions. For example, Rc<T> in rust is much easier to use without screwing up than the manually handled reference counters littered throughout the kernel. It seems obvious to me that numerous deadlocks in the kernel could be avoided by not hand-rolling refcounting everywhere. You're right that there's still the potential with rust for some code to compromise the safety of the entire kernel. But with rust that's a subset of code, not practically every single line of the whole thing. It seems to me like memory corruption/use-after-free/etc only being able to happen in a small fraction of code is better than it being able to happen anywhere.
- zaarn 9y ago> Rc<T> Rc requires memory allocation. When you boot a kernel you don't have that. Until you set it up, you can't use anything that requires a heap, only stack values. The best solution I found is to use C code to allocate raw memory and then go through the elaborate process of setting up kernel address space, after which you setup a frame allocator, after which you can setup interrupts and finally use pagefaults to normally use kernel heap. But wait there is more! During a pagefault interrupt you can't use the kernel heap in a writeful manner that is not inplace. Since a page fault during a page fault is a double fault and thusly your only option is to crash the kernel. You can only read from the kernel heap, modify in place in the heap and write to pagetables. Same goes for some other interrupts. Which btw, violate a lot of ways Rust code likes to work. An interrupt is like a coroutine but you don't have a nice runtime that abstracts it for you, instead the IRQ just smashes into the active execution and let's hope you haven't held any locks to important kernel stuff at that moment because you will have to crack that lock open.
- TheDong 9y agoMy point is really that rust allows you to build those abstractions, regardless of that specific one. Sure, the kernel has reusable things like its embedded linked list etc, but they're not type-safe, and they can't represent ownership. With rust's type-system, a generic rc-like thing could be created which is suitable for the world of the kernel, even if it's not the stdlib Rc.
- zaarn 9y agoYou can't have RC until you have setup a heap. The stack is not a safe place to put these things. Without any memory management, things get hard fast, especially considering you still need to parse the memory layout to find out which parts of memory are even usable.
- Dylan16807 9y agoThe original comment was "Rc<T> in rust is much easier to use without screwing up than the manually handled reference counters littered throughout the kernel." That's heap vs. heap. It comes after the very brief stage you're mentioning.
- pcwalton 9y agoWhy is kernel programming any different from user-level programming here? I tend to think that the driver and network level, which is where most problems in the real world tend to lie, is similar to userland in how often unsafe code gets used and the impact of unsafe code on the correctness of the kernel. In fact, the fact that you can write some drivers in userland on certain OS's--and they can crash without bringing down the whole OS--is strong evidence of this.
- zaarn 9y agox86 is unsafe. Period. A lot of devices are unsafe. Period. You can write some device drivers in userspace. But you can't handle page faults in userspace. Those need to be handled by the kernel and will be 100% unsafe because any mistake will lead to a certain and quick double or triple fault. Kernel Level Programming is very very different to normal user-level programming. There is no malloc. There is no segmentation. Nothing prevents you from dereferencing a null pointer. In fact, in kernel-land a null pointer is valid memory. You don't have any of the forgiving properties of Ring3 assembly code in kernel-land.
- rcxdude 9y agoWhat you are describing is <10% of, say, the linux kernel. The rest of it reads very much like user-land code (and dereferencing a null pointer will often earn you a nice warning message if not a panic).
- zaarn 9y agoThose are usually the important 10% of a kernel that build the foundation of everything else. Once you have VMM and Paging setup, preventing a null pointer deref is not hard (simply unpage 0x0)