Skip to content

Mentorship Session: Writing Linux Kernel Modules in Rust

WedsonCandiceShuahMiguel

Blue TeamThe Linux Foundation1 hr 31 minAdvancedOpen on YouTube ↗

Evaluates mentorship Session: Writing Linux Kernel Modules in Rust and evaluates key implications for security practitioners.

Summary

# Mentorship Session: Writing Linux Kernel Modules in Rust

### Overview In this Linux Foundation mentorship session, Wedson Almeida Filho, a software engineer at Google and maintainer of the Rust for Linux project, presents an interactive walkthrough on developing Linux kernel modules in Rust. The primary motivation for adopting Rust in the Linux kernel is achieving memory safety to eliminate classes of vulnerabilities (such as use-after-free bugs) while preserving C-like performance without requiring a runtime garbage collector. Wedson walks attendees through kernel vs. user-space concepts, module lifecycles, and a live coding demonstration developing a simple virtual character device module named `scull`.

### Key Topics - **Rust for Linux Goals**: Making Rust a first-class language for Linux kernel development. Rust provides compile-time memory safety, formal verification properties, and a rich type system that eliminates common kernel memory bugs. - **Error Handling and Ergonomics**: How Rust simplifies kernel code compared to C. The `?` error-propagation operator replaces manual return-code checking and nested `goto` cleanup labels, while RAII and the `Drop` trait manage resource cleanups automatically. - **Kernel Execution Model vs. User Space**: The distinction between distinct user-space address spaces and shared kernel space, as well as the module lifecycle (`init` registration, event callbacks, and `exit` unregistration). - **Development Workflow**: Using a custom VM with BusyBox, building minimal Linux kernel configurations via `make allnoconfig`, running and testing using QEMU, and debugging with GDB. - **Rust Types and Safety Abstractions**: Utilizing `Pin`, `Box`, and `Ref` (kernel equivalent of `Arc`) to handle self-referential structures, memory locations, and shared lifetimes safely.

### Technical Details During the live demonstration, Wedson begins implementing a Rust version of the classic `scull` (Simple Character Utility for Loading Localities) driver from the Linux Device Drivers book: 1. **Build System Integration**: Added a new Kconfig entry (`SAMPLE_RUST_SCULL`) and updated `samples/rust/Makefile` to conditionally build `rust_scull.o`. Enabled the module via `make menuconfig`. 2. **Kernel Module Skeleton**: Created an empty Rust module defining a struct `Scull` and implementing the `KernelModule` trait with an `init()` function returning an `Ok(Scull)`. 3. **Logging**: Used the `pr_info!` macro for type-safe kernel log printing without the formatting security pitfalls of C's `printk`. 4. **File Operations and Misc Device Registration**: Implemented the `FileOperations` trait with `open`, `read`, and `write` callbacks. Registered the module as a miscellaneous device using `misc::Registration::new_pinned()`. 5. **Resource Pinning**: Wedson explained that Rust types are movable by default (via bitwise copies). Because C kernel structures often contain self-referential pointers (such as `list_head`), kernel registrations must be pinned (`Pin<Box<...>>`) to prevent memory relocation after initialization. 6. **Handling Use-After-Free at Compile Time**: When attempting to share state between device registration and open file descriptors, Rust's borrow checker rejected returning a borrowed reference where ownership was expected. Wedson demonstrated that a naive box cannot be copied or outlive unregistration safely; instead, reference counting via kernel `Ref` pointers is required to prevent use-after-free conditions that plague C implementations when devices unregister while file handles remain open.

### Takeaways Rust's compiler catches subtle kernel bugs—such as resource leaks, missing struct initializations, and complex lifetime/use-after-free mismatches—strictly at compile time. Although developing low-level abstractions can be complex and currently relies on specific compiler toolchains due to unstable language features, the resulting consumer code is cleaner, more concise, and significantly safer than equivalent C implementations. Future sessions will cover development environment setup and asynchronous kernel programming.

Related talks