3 ms·
We're working on it: https://github.com/fishinabarrel/linux-kernel-module-rust https://github.com/fishinabarrel/linux-kernel-module-rust Check out the demo in
by geofft 7y ago
We're working on it: https://github.com/fishinabarrel/linux-kernel-module-rust https://github.com/fishinabarrel/linux-kernel-module-rust
Check out the demo in PR #122, which lets you create three boolean sysctls and a character device that prints the state of those sysctls in JSON (using serde).
We gave a talk about it last week at Linux Security Summit, I'll submit it once the recording is up :) Slides are at https://ldpreload.com/p/kernel-modules-in-rust-lssna2019.pdf https://ldpreload.com/p/kernel-modules-in-rust-lssna2019.pdf .
- raverbashing 7y agoLooks interesting and definitely promising Though it would probably make sense to make the API more "Rust like" and avoid things like the multiple cstr!() Some things are definitely trickier than others, for example how to deal with the different options of kmalloc if it's rust that's allocating memory
- geofft 7y agoFeedback is definitely welcome! Re cstr see https://github.com/fishinabarrel/linux-kernel-module-rust/issues/16 https://github.com/fishinabarrel/linux-kernel-module-rust/is... and https://github.com/fishinabarrel/linux-kernel-module-rust/pull/133 https://github.com/fishinabarrel/linux-kernel-module-rust/pu... . What we have now is definitely better than b"foo\0" but not the best possible thing. I think there's work upstream on custom / multiple allocators; we'll plug the various kmalloc(GFP_FOO) flags into that once it exists. It is super beneficial to use the standard library's collections and third-party crates that use them.
- zaphirplane 7y agoFor those like I was, wondering why a framework is required to write out of tree Linux modules in rust It’s to auto create rust bindings. Link between rust crates and kernel build system
- geofft 7y agoHalf that, and half to create safe interfaces that feel like native Rust ("ergonomic") and not like you're writing C in Rust. For instance, the kernel wants you to define a character device by passing a struct with a bunch of C function pointers for how to read, write, seek, ioctl, etc. on the device. Rust has a trait / interface system that's a good match for this use case, so in src/chrdev.rs we define a Rust trait with all these methods, and we have a helper function to create the C struct with FFI-safe function pointers that call the various methods on the Rust trait. The broad goal is that you don't need to use the "unsafe" keyword to write kernel modules that don't access memory directly themselves (filesystems, network protocols, etc.: device drivers might still need unsafe code where actually talking to the device, but it should be as little as possible). That means the interface used by kernel modules can't involve any unwrapped C functions or raw C pointers.
- pjmlp 7y agoThanks for the heads up about this year's Summit.
- steelframe 7y agoI attended LSS this year and enjoyed your talk. I also attended KP Singh's talk on eBPF LSMs, and I couldn't help but compare the two mechanisms for making code in the kernel more safe. eBPF's approach is to generate code that's verified to be safe and that's limited in the operations it's allowed to do in the kernel, using trusted helper functions to access kernel data structures and functions. I couldn't help but draw an analogy to unsafe wrappers for Rust. In its current form I might not want to write core logic of a device driver in eBPF, as it started out as something suited for mandatory access control policy, packet filtering, and auditing. That's changing though, and people seem to be demanding more and more functionality in eBPF. I'm admittedly bad at predicting the future, but one thing I can say with some confidence is that eBPF's capabilities are going to increase with time. I would also be hesitant to attempt to write a device driver in Rust because of the degree to which I'd have to interact with other subsystems and structures of the kernel that are still written in unsafe C. I wouldn't have an intuition for the incremental benefit of using Rust for some of the core logic of the driver while still having to use unsafe wrappers to muck with all the other parts of the kernel where, if I get it wrong, my driver can still oops/hang/etc. Would the complexity of mixing two languages with unsafe wrappers plus increased code size "pay for" any incremental benefit, or would I have to expect future dividends from eventually having "enough" of the kernel written in Rust for it to be a worthwhile investment? One advantage of eBPF, I suppose, is that you can write your code in old familiar C. With forthcoming support for bounded loops, I expect people are going to be proposing more and more use cases for it. I can imagine scenarios where one camp will say, "This is a job for Rust," and the other camp will retort, "Actually, this job can currently be done in eBPF." eBPF having the other distinct advantage of already being a supported feature of the upstream kernel. This is all pretty new to me, and so all I have are my impressions and intuitions. I'd appreciate hearing more perspectives on this.