Re: Allow data races on some read/write operations
Andreas Hindborg <[email protected]>
| Newsgroups | dev.linux.lists.lkmm,dev.linux.lists.iommu,org.kernel.vger.linux-kernel,org.kernel.vger.rust-for-linux |
|---|---|
| Message-ID | <[email protected]> |
"Ralf Jung" <[email protected]> writes: > Hi all, > >>>> For some kinds of hardware, we might not want to trust the hardware. >>>> I.e., there is no race under normal operation, but the hardware could >>>> have a bug or be malicious and we might not want that to result in UB. >>>> This is pretty similar to syscalls that take a pointer into userspace >>>> memory and read it - userspace shouldn't modify that memory during the >>>> syscall, but it can and if it does, that should be well-defined. >>>> (Though in the case of userspace, the copy happens in asm since it >>>> also needs to deal with virtual memory and so on.) >>> >>> Wow you are really doing your best to combine all the hard problems at the same >>> time. ;) >>> Sharing memory with untrusted parties is another tricky issue, and even leaving >>> aside all the theoretical trouble, practically speaking you'll want to >>> exclusively use atomic accesses to interact with such memory. So doing this >>> properly requires atomic memcpy. I don't know what that is blocked on, but it is >>> good to know that it would help the kernel. >> >> I am sort of baffled by this, since the C kernel has no such thing and >> has worked fine for a few years. Is it a property of Rust that causes us >> to need atomic memcpy, or is what the C kernel is doing potentially dangerous? > > It's the same in C: a memcpy is a non-atomic access. If something else > concurrently mutates the memory you are copying from, or something else > concurrently reads/writes the memory you are copying two, that is UB. > This is not specific to memcpy; it's the same for regular pointer loads/stores. > That's why you need READ_ONCE and WRITE_ONCE to specifically indicate to the > compiler that these are special accesses that need to be treated differently. > Something similar is needed for memcpy. I'm not a compiler engineer, so I might be wrong about this, but. If I do a C `memcpy` from place A to place B where A is experiencing racy writes, if I don't interpret the data at place B after the copy operation, the rest of my C program is fine and will work as expected. I may even later copy the data at place B to place C where C might have concurrent reads and/or writes, and the kernel will not experience UB because of this. The data may be garbage, but that is fine. I am not interpreting the data, or making control flow decisions based on it. I am just moving the data. My understand is: In Rust, this program would be illegal and might experience UB in unpredictable ways, not limited to just the data that is being moved. One option I have explored is just calling C memcpy directly, but because of LTO, that is no different than doing the operation in Rust. I don't think I need atomic memcpy, I just need my program not to explode if I move some data to or from a place that is experiencing concurrent writes without synchronization. Not in general, but for some special cases where I promise not to look at the data outside of moving it. Best regards, Andreas Hindborg