On Mon, Nov 10, 2025 at 12:40:17PM +0100, Jason A. Donenfeld wrote:
> On Mon, Nov 10, 2025 at 12:24:13PM +0100, Thomas Weißschuh wrote:
> > > > > For example, one clean way of
> > > > > doing that would be to make vdso_k_rng_data always valid by having it
> > > > > initially point to __initdata memory, and then when it's time to
> > > > > initialize the real datapage, memcpy() the __initdata memory to the
> > > > > new
> > > > > specially allocated memory. Then we don't need the complex state
> > > > > tracking that this commit and the prior one introduce.
> > > >
> > > > Wouldn't that require synchronization between the update path and the
> > > > memcpy()
> > > > path? Also if the pointer is going to change at some point we'll
> > > > probably need
> > > > to use READ_ONCE()/WRITE_ONCE(). In general I would be happy about a
> > > > cleaner
> > > > solution for this but didn't find a great one.
> > >
> > > This is still before userspace has started, and interrupts are disabled,
> > > so I don't think so?
> >
> > Interrupts being disabled is a good point. But we are still leaking
> > implementation details from the random code into the vdso datastore.
>
> It wouldn't. You do this generically with memcpy().
With "implementation details" I meant the fact that it is fine to swap out the
datapage behind its back. And the fact that the memcpy() can not introduce any
races.
> > > Also, you only care about being after
> > > mm_core_init(), right? So move your thing before sched_init() and then
> > > you'll really have nothing to worry about.
> >
> > The callchains random_init_early() -> crng_reseed()/_credit_init_bits()
> > could
> > still touch the datapage before it is allocated.
> > Adding conditionals to prevent those is essentially what my patch does.
>
> I think I wasn't very clear in my proposal, because this isn't an issue
> in it.
I interpreted your previous mail as two different proposals:
1) do the memcpy() thing
2) move the page allocation after mm_core_init()
Now it makes more sense.
> Global scope:
>
> static struct vdso_rng_data placeholder_vdso_k_rng_data __initdata;
> struct vdso_rng_data *vdso_k_rng_data = &placeholder_vdso_k_rng_data;
>
> Then,
>
> void __init vdso_setup_data_pages(void)
> {
> ...
> vdso_k_rng_data = blabla();
> ...
> memcpy(vdso_k_rng_data, &placeholder_vdso_k_rng_data,
> sizeof(*vdso_k_rng_data);
> ...
> }
>
> If vdso_setup_data_pages() is called early enough in init, this is safe
> to do, and then you don't need to muck up the random code with awful
> state machine ordering stuff.
Yes it is safe, but this safety is not obvious in my opinion.
However I'll use your proposal for the next revision.
Thomas