Mostly Typed

For Hackers and Other Heretics

The ALLOW System Call

It is common for drivers to share data with application via shared memory. For example, an application might need to pass a buffer to a network driver in order to read a packet.

The obvious way to do this is to essentially give drivers complete access to the app’s memory. The application passes a pointer and size of the buffer via a system, the kernel interprets these as generic arguments, and the driver directly indexes into the app’s memory to use the buffer:

fn subscribe(..., buf_ptr: usize, buf_len: usize) -> isize {
    let buffer = app.get_mem_slice(buf_ptr, buf_len);

However, providing drivers with full access to application memory forces a trust model in which drivers can completely control application memory. In Tock, we do not expect drivers to be bug-free, and in fact assume that drivers are mutually-distrustful. Ideally, an application should be able to mitigate the impact of any single driver by relying on the OS to enforce that:

  • Drivers can only interact with applications if the application has opted-in (e.g. implicitly by subscribing to a notification from the driver

  • Drivers can only access application memory they have explicitly been given access to. This, at least, allows applications to rely on the integrity of memory they have not shared with drivers, and to trust drivers differentially.

I’m currently experimenting with a new system call, ALLOW, that manages this interaction:

fn allow(driver_num: usize, allow_num: usize,
         buf_ptr: *mut u8, buf_len: usize) -> isize;

ALLOW takes a pointer and length from the application and, assuming the corresponding buffer lies completely within the application’s exposed memory (i.e. it’s memory the application is actually allowed to pass around), passes that buffer to the driver:

trait Driver {
    fn allow(&mut self, allow_num: usize, AppSlice<u8>) -> isize;

However, it’s not clear that this is the right interface. On the one hand, with this interface driver must somehow figure out how to associate an AppSlice with a call to SUBSCRIBE (especially in the case of multiple applications). Instead, we could extend SUBSCRIBE to include the ALLOW functionality, but then we would completely run out of CPU registers for arguments (maybe that’s just OK?). Furthurmore, in both options, applications have no way of specifying that a driver should reuse a buffer (other than passing in the same buffer again to ALLOW, which would result in multiple copies of identical AppSlice values).