Tracking trust with Rust in the kernel
Ready to give LWN a try? With a subscription to LWN, you can stay current with what is happening in the Linux and free-software community and take advantage of subscriber-only site features. We are pleased to offer you a free trial subscription, no credit card required, so that you can see for yourself. Please, join us!
The Linux kernel has to handle many different sources of data that should not be trusted: user space, network connections, and removable storage, to name a few. The kernel has to remain secure even if one of these sends garbled (or malicious) data. Benno Lossin has been working on an API for kernel Rust code that makes it harder to accidentally make decisions based on data from user space. That work is now on its fourth revision, and Lossin has asked kernel developers to experiment with it and see where problems remain, making this a good time to look at the proposed API.
The core approach, as with so many things in Rust, centers on the type system. Lossin's patch set introduces a new type, Untrusted , that marks data as originating from an untrusted source, and therefore requiring special caution. Trying to access a value wrapped by Untrusted is forbidden by Rust. The type is a "transparent" structure, meaning that it will be laid out in memory exactly like the type that it wraps. An Untrusted
The bulk of Lossin's patch set is documentation for Untrusted , and some utility functions to manipulate untrusted values. There is also special support for common data structures, specifically slices (arrays with a run-time-known length) and vectors (growable arrays on the heap) of untrusted values. When dealing with an existing buffer that should be filled with untrusted data, the documentation recommends writing the interface like this:
pub fn read_from_userspace(buf: &mut [Untrusted
That function takes a mutable reference to a slice of untrusted bytes, and will fill it with user-space data. That data can later be copied back to user space without having to unwrap it. Trying to actually use the value of an untrusted object within the kernel, however, will cause a compiler error. Lossin recommends that form of API because converting an &mut Untrusted<[u8]> (a mutable reference to an untrusted slice of bytes) into an &mut [Untrusted
Sometimes, the kernel does need to read user-space data, not merely copy it around. The third patch of the set contains functions to help with that. It introduces a new trait called Validate that encapsulates the logic for validating user-space data before use. For a custom type T , an implementation of Validate contains the logic needed to turn an Untrusted into a plain T . Lossin isn't totally happy with that API, though, and wants to find time to improve it.
Greg Kroah-Hartman, who has been enthusiastic about the idea of marking input from user space in the past, asked for Lossin to add an example of a driver using Untrusted .
ioctl() is the callback that is taking untrusted data from userspace. That's one place we have had more kernel buffer overflows then I can count and ALWAYS needs to be properly verified before anything can be done with the data there.
... continue reading