From: Alice Ryhl <aliceryhl@google.com>
To: Peter Zijlstra <peterz@infradead.org>
Cc: "Boqun Feng" <boqun@kernel.org>,
"Greg KH" <gregkh@linuxfoundation.org>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Lorenzo Stoakes" <lorenzo.stoakes@oracle.com>,
"Liam R. Howlett" <Liam.Howlett@oracle.com>,
"Miguel Ojeda" <ojeda@kernel.org>,
"Boqun Feng" <boqun.feng@gmail.com>,
"Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <lossin@kernel.org>,
"Trevor Gross" <tmgross@umich.edu>,
"Danilo Krummrich" <dakr@kernel.org>,
"Will Deacon" <will@kernel.org>,
"Mark Rutland" <mark.rutland@arm.com>,
linux-mm@kvack.org, rust-for-linux@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH v2] rust: page: add byte-wise atomic memory copy methods
Date: Tue, 17 Feb 2026 11:51:20 +0000 [thread overview]
Message-ID: <aZRWOIPThLfIZ1Ph@google.com> (raw)
In-Reply-To: <20260217110911.GY1395266@noisy.programming.kicks-ass.net>
On Tue, Feb 17, 2026 at 12:09:11PM +0100, Peter Zijlstra wrote:
> On Tue, Feb 17, 2026 at 10:47:03AM +0000, Alice Ryhl wrote:
> > > > // OK!
> > > > unsigned long *a, b;
> > > > b = READ_ONCE(a);
> > > > if is_valid(b) {
> > > > // do stuff
> > > > }
> > > >
> > > > Now consider the following code:
> > > >
> > > > // Is this ok?
> > > > unsigned long *a, b;
> > > > memcpy(a, &b, sizeof(unsigned long));
> > > > if is_valid(b) {
> > > > // do stuff
> > > > }
> > >
> > > Why the hell would you want to write that? But sure. I think similar but
> > > less weird example would be with structures, where value copies end up
> > > being similar to memcpy.
> >
> > I mean sure, let's say that it was a structure or whatever instead of a
> > long. The point is that the general pattern of memcpy, then checking the
> > bytes you copied, then use the bytes you copied, is potentially
> > susceptible to this exacty optimization.
>
> > > And in that case, you can still use volatile and compiler must not do
> > > silly.
> >
> > What you mean by "volatile" here is the same as what this patch means
> > when it says "per-byte atomic". If you agree that a "volatile memcpy"
> > would be a good idea to use in this scenario, then it sounds like you
> > agree with the patch except for its naming / terminology.
>
> struct foo {
> int a, b;
> };
>
> struct foo *ptr, val;
>
> val = *(volatile struct foo *)ptr;
>
> why would we need a an explicit new memcpy for this?
In my experience with dealing with `struct page` that is mapped into a
vma, you need memcpy because the struct might be split across two
different pages in the vma. The pages are adjacent in userspace's
address space, but not necessarily adjacent from the kernel's POV.
So you might end up with something that looks like this:
struct foo val;
void *ptr1 = kmap_local_page(p1);
void *ptr2 = kmap_local_page(p2);
memcpy(ptr1 + offset, val, PAGE_SIZE - offset);
memcpy(ptr2, val + offset, sizeof(struct foo) - (PAGE_SIZE - offset));
kunmap_local(ptr2);
kunmap_local(ptr1);
if (is_valid(&val)) {
// use val
}
This exact thing happens in Binder. It has to be a memcpy.
> > > So I'm still not exactly sure why this is a problem all of a sudden?
> >
> > I mean, this is for `struct page` specifically. If you have the struct
> > page for a page that might also be mapped into a userspace vma, then the
> > way to perform a "copy_from_user" operation is to:
> >
> > 1. kmap_local_page()
> > 2. memcpy()
> > 3. kunmap_local()
> >
> > Correct me if I'm wrong, but my understanding is that on 64-bit systems,
> > kmap/kunmap are usually complete no-ops since you have enough address
> > space to simply map all pages into the kernel's address space. Not even
> > a barrier - just a `static inline` with an empty body.
>
> That is all correct -- however that cannot be all you do.
>
> Any shared memory will involved memory barriers of a sort. You cannot
> just memcpy() and think you're done.
>
> So yeah, on x86_64 those 1,2,3 are insufficient to inhibit the re-load,
> but nobody should ever just do 1,2,3 and think job-done. There must
> always be more.
>
> If it is a ring-buffer like thing, you get:
>
> * if (LOAD ->data_tail) { LOAD ->data_head
> * (A) smp_rmb() (C)
> * STORE $data LOAD $data
> * smp_wmb() (B) smp_mb() (D)
> * STORE ->data_head STORE ->data_tail
> * }
>
> if it is a seqlock like thing you get that.
>
> If it is DMA, you need dma fences.
>
> And the moment you use any of that, the re-load goes out the window.
I don't know how Andreas is using this, but the usage pattern I'm
familiar with for `struct page` from my work on Binder is this one:
1. memcpy into the page
2. return from ioctl
3. userspace reads from vma
or
1. userspace writes to vma
2. call ioctl
3. kernel reads from page
which needs no barriers whatsoever. There is nothing to prevent this
kind of optimization in this kind of code, so an evil userspace could
trigger TOCTOU bugs in the kernel that are not present in the source
code if the code was optimized like I described.
Alice
next prev parent reply other threads:[~2026-02-17 11:51 UTC|newest]
Thread overview: 44+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-12 14:51 Andreas Hindborg
2026-02-12 16:41 ` Boqun Feng
2026-02-12 17:10 ` Andreas Hindborg
2026-02-12 17:23 ` Andreas Hindborg
2026-02-13 9:55 ` Peter Zijlstra
2026-02-13 12:18 ` Greg KH
2026-02-13 12:58 ` Andreas Hindborg
2026-02-13 13:20 ` Greg KH
2026-02-13 14:13 ` Andreas Hindborg
2026-02-13 14:26 ` Peter Zijlstra
2026-02-13 15:34 ` Greg KH
2026-02-13 15:45 ` Boqun Feng
2026-02-13 15:58 ` Greg KH
2026-02-13 16:19 ` Boqun Feng
2026-02-17 9:13 ` Peter Zijlstra
2026-02-17 9:33 ` Alice Ryhl
2026-02-17 9:45 ` Peter Zijlstra
2026-02-17 10:01 ` Alice Ryhl
2026-02-17 10:25 ` Peter Zijlstra
2026-02-17 10:47 ` Alice Ryhl
2026-02-17 11:09 ` Peter Zijlstra
2026-02-17 11:51 ` Alice Ryhl [this message]
2026-02-17 12:09 ` Peter Zijlstra
2026-02-17 13:00 ` Peter Zijlstra
2026-02-17 13:54 ` Danilo Krummrich
2026-02-17 15:50 ` Peter Zijlstra
2026-02-17 16:10 ` Danilo Krummrich
2026-02-17 13:09 ` Alice Ryhl
2026-02-17 15:48 ` Peter Zijlstra
2026-02-17 23:39 ` Gary Guo
2026-02-18 8:37 ` Peter Zijlstra
2026-02-18 9:31 ` Alice Ryhl
2026-02-18 10:09 ` Peter Zijlstra
2026-02-17 13:56 ` Andreas Hindborg
2026-02-17 16:04 ` Peter Zijlstra
2026-02-17 18:43 ` Andreas Hindborg
2026-02-17 20:32 ` Jens Axboe
2026-02-17 15:52 ` Boqun Feng
2026-02-17 9:17 ` Peter Zijlstra
2026-02-17 9:23 ` Peter Zijlstra
2026-02-17 9:37 ` Alice Ryhl
2026-02-17 10:01 ` Peter Zijlstra
2026-02-17 9:33 ` Peter Zijlstra
2026-02-14 0:07 ` Gary Guo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=aZRWOIPThLfIZ1Ph@google.com \
--to=aliceryhl@google.com \
--cc=Liam.Howlett@oracle.com \
--cc=a.hindborg@kernel.org \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=boqun@kernel.org \
--cc=dakr@kernel.org \
--cc=gary@garyguo.net \
--cc=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=lorenzo.stoakes@oracle.com \
--cc=lossin@kernel.org \
--cc=mark.rutland@arm.com \
--cc=ojeda@kernel.org \
--cc=peterz@infradead.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=tmgross@umich.edu \
--cc=will@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox