← Back to context

Comment by johncolanduoni

2 months ago

Drivers are interesting from a safety perspective, because on systems without an IOMMU sending the wrong command to devices can potentially overwrite most of RAM. For example, if the safe wrappers let you write arbitrary data to a PCIe network card’s registers you could retarget a receive queue to the middle of a kernel memory page.

> if the safe wrappers let you write arbitrary data to a PCIe network card’s registers

Functions like that can and should be marked unsafe in rust. The unsafe keyword in rust is used both to say “I want this block to have access to unsafe rust’s power” and to mark a function as being only callable from an unsafe context. This sounds like a perfect use for the latter.

  • > Functions like that can and should be marked unsafe in rust.

    That's not how it works. You don't mark them unsafe unless it's actually required for some reason. And even then, you can limit that scope to a line or two in majority of cases. You mark blocks unsafe if you have to access raw memory and there's no way around it.

    • It is how it's supposed to work. `unsafe` is intended to be used on functions where the caller must uphold some precondition(s) in order to not invoke UB, even if the keyword is not strictly required to get the code to compile.

      The general rule of thumb is that safe code must not be able to invoke UB.

      3 replies →

  • So if you're writing a device driver in rust...

    - Hardware access is unsafe - Kernel interface is unsafe

    How much remains in the layer in-between that's actually safe?

    • All logic, all state management, all per-device state machines, all command parsing and translation, all data queues, etc. Look at the examples people posted in other comments.

      1 reply →

In normal user-mode rust, not running inside the kernel at all, you can open /dev/mem and write whatever you want to any process's memory (assuming you are root). This does not require "unsafe" at all.

Another thing you can do from rust without "unsafe": output some buggy source code that invokes UB in a language like C to a file, then shell out to the compiler to compile that file and run it.

  • Sure, but those are non-central to what the program is doing. Writing to the wrong register offset and hosing main memory is a thing that happens when developing drivers (though usually it breaks obviously during testing).

    • Right, you're not wrong that this is a possible failure mode which Rust's guarantees don't prevent.

      I'm just pointing out that "your program manipulates the external system in such a way that UB is caused" is outside the scope of Rust's guarantees, and kernel development doesn't fundamentally change that (even though it might make it easier to trigger). Rust's guarantees are only about what the Rust code does; anything else would be hard or impossible to guarantee and Rust doesn't try to do so.