# Reading external memory * Reading a MMIO register * Reading memory mapped from user space * Reading kernel memory initialized outside the Rust AM By external memory, we mean memory that is manipulated outside the Rust abstract machine. The issue has come up at least a few times in the list: * [iov_iter](https://lore.kernel.org/all/87ecuplgqy.fsf@kernel.org) * [dma](https://lore.kernel.org/all/25e7e425-ae72-4370-ae95-958882a07df9@ralfj.de) * [block io](https://lore.kernel.org/all/ab8fd525-9a63-46e2-a443-b9d94eed6004@ralfj.de) ## The problem There are two problems: 1) We might not be able to control writes to the external memory. Memory accesses may race, which is UB. 2) The Rust AM might assume the memory is uninit. Creating a reference to uninit memory is UB. Even though the compiler may produce working code in the face of this UB: "The generated program is a random sequence of bytes that just happens to take the shape of a seemingly working program by accident. Such is the joy of code that causes UB. You cannot deduce anything from what happens when you execute a program with UB, since that act is by itself meaningless. You need to establish that your program has no UB before making any inference based on what you see the program do after it came out of the compiler." [2] ## Solutions To solve 1, we can: * Use atomic volatile loads or atomic volatile memcpy. The latter is not available yet [3] * Do the read in assembly [1] According to [4], as long as we *only* read from external memory with [volatile reads](https://doc.rust-lang.org/core/ptr/fn.read_volatile.html), the Rust AM will not consider the memory written by this function uninitialized, and problem 2 goes away. Regarding using inline assembly: "For now (until our atomic APIs have caught up), inline asm or volatile remains the recommended way to interact with untrusted code, with the understanding that it is the "least bad" solution." [1] ### Assembly (`asm!`) From [here](https://doc.rust-lang.org/reference/inline-assembly.html#r-asm.rules.mem-same-as-ffi): The set of memory locations that assembly code is allowed to read and write are the same as those allowed for an FFI function. - If the readonly option is set, then only memory reads are allowed. - If the nomem option is set then no reads or writes to memory are allowed. - These rules do not apply to memory which is private to the assembly code, such as stack space allocated within it. ## References * ["What The Hardware Does" is not What Your Program Does: Uninitialized Memory](https://www.ralfj.de/blog/2019/07/14/uninit.html) * [I must read what Rust considers uninitialized memory. How to do it without undefined behavior?](https://users.rust-lang.org/t/i-must-read-what-rust-considers-uninitialized-memory-how-to-do-it-without-undefined-behavior/90513/22) * [Is read_volatile on uninitialized memory really undefined behavior?](https://github.com/rust-lang/miri/issues/2807) [2] * [What about: volatile, concurrency, and interaction with untrusted threads](https://github.com/rust-lang/unsafe-code-guidelines/issues/152) [1] * [Specification of inline assembly](https://github.com/rust-lang/unsafe-code-guidelines/issues/422) * [Support for Linux kernel memory model](https://github.com/rust-lang/unsafe-code-guidelines/issues/348) * [[RFC] AtomicPerByte (aka "atomic memcpy")](https://github.com/rust-lang/rfcs/pull/3301) [3] * [Pre-Pre-RFC: core::arch::{load, store} and stricter volatile semantics ](https://github.com/rust-lang/unsafe-code-guidelines/issues/321) * [Should Rust assume that there are unknown threads of execution?](https://github.com/rust-lang/unsafe-code-guidelines/issues/215) * [RfL Zulip discussion](https://rust-for-linux.zulipchat.com/#narrow/channel/288090-core-team/topic/Reading.20external.20memory/with/528032600) [4] * [UB caused by races on `{read,write}_volatile`](https://rust-lang.zulipchat.com/#narrow/channel/136281-t-opsem/topic/UB.20caused.20by.20races.20on.20.60.7Bread.2Cwrite.7D_volatile.60/near/399343771) * [Rust inline assembly reference](https://doc.rust-lang.org/reference/inline-assembly.html#rules-for-inline-assembly)