Skip to content

Best practices for sharing memory with untrusted parties #607

@RalfJung

Description

@RalfJung

This was the starting point for #152. That got closed saying "volatile is for MMIO", which is further discussed in #321. However, since then we got "also volatile can access memory outside the AM" (rust-lang/rust#141260) which changes the picture again IMO. The question also recently came up in rust-lang/rust#154321.

I would say the safest (least AM/model-breaking) way to share memory with an untrusted party is to never make that memory part of the AM. This avoids any trouble related to memory models or compiler assumptions. If this isn't actual "memory" in the first place, there can't be any assumptions. And now that volatile accesses are allowed to access such "non-memory", this is actually a viable option. I think this also explains why people are naturally drawn towards using volatile for this kind of interaction. If LLVM changes volatile loads to no longer be willreturn (which @nikic says is on the table), this model even allows reads and writes on memory that might get unmapped at any time. (Alternatively, #606 discusses ways for such segfaults to be valid everywhere, that'd also implicitly cover volatile accesses.)

For a Rust program this means only using raw pointers, never creating a reference, and only using read_volatile and write_volatile. Those don't even have to be atomic; all concurrency behavior is hidden behind the opaqueness of volatile accesses. (Atomic volatile accesses are useful if the party those accesses are communicating with also has access to actual Rust memory. That's not the case for this discussion.) It currently also means never using offset or field projections but we could fix that (#350) -- the LLVM IR we generate is already okay here, we "just" have to update our Rust-level model.


The other model we have discussed in the past is to have that shared memory be actual Rust memory and model whatever the untrusted code does as atomic accesses. This means the Rust code must also use atomic accesses. This seems to work fine in practice but the model actually has a gaping hole -- mixed-size accesses are UB, so the untrusted code can still cause UB in the Rust code. The advantage of this model is that the Rust code is allowed to use shared references (as long as all bytes of the pointee type are inside an UnsafeCell).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions