Re: [PATCH v7 1/3] random: add vgetrandom_alloc() syscall

Jason A. Donenfeld
2022-11-27T20:18:22Z

Hi Thomas,

Thanks a lot for the thorough review, here, and in the other two emails.
I appreciate you taking the time to look at it, and my apologies for
parts that are unclear or sloppy or otherwise unpolished. I'll try to
make v8 a lot better.

Comments inline below:

On Fri, Nov 25, 2022 at 09:45:31PM +0100, Thomas Gleixner wrote:
> On Thu, Nov 24 2022 at 17:55, Jason A. Donenfeld wrote:
> > ---
> > MAINTAINERS | 1 +
> > arch/x86/Kconfig | 1 +
> > arch/x86/entry/syscalls/syscall_64.tbl | 1 +
> > arch/x86/include/asm/unistd.h | 1 +
> > drivers/char/random.c | 59 +++++++++++++++++++++++++
> > include/uapi/asm-generic/unistd.h | 7 ++-
> > kernel/sys_ni.c | 3 ++
> > lib/vdso/getrandom.h | 23 ++++++++++
> > scripts/checksyscalls.sh | 4 ++
> > tools/include/uapi/asm-generic/unistd.h | 7 ++-
> > 10 files changed, 105 insertions(+), 2 deletions(-)
> > create mode 100644 lib/vdso/getrandom.h
>
> I think I asked for this before:
>
> Please split these things properly up. Provide the syscall and then wire
> it up.

Before I split it into "syscall, generic vdso, x86 vdso", as that's how
I interpreted your email. Next, I'll split it up into "generic syscall,
generic vdso, x86 vdso & syscall", since enabling the syscall without
the vdso function, or vice-versa, doesn't make sense, and having that
last step be all at once there will provide an easy thing for other
archs to look at.

> > diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> > index 67745ceab0db..331e21ba961a 100644
> > --- a/arch/x86/Kconfig
> > +++ b/arch/x86/Kconfig
> > @@ -59,6 +59,7 @@ config X86
> > #
> > select ACPI_LEGACY_TABLES_LOOKUP if ACPI
> > select ACPI_SYSTEM_POWER_STATES_SUPPORT if ACPI
> > + select ADVISE_SYSCALLS if X86_64
>
> Why is this x86_64 specific?
>
> > --- a/arch/x86/include/asm/unistd.h
> > +++ b/arch/x86/include/asm/unistd.h
> > @@ -27,6 +27,7 @@
> > # define __ARCH_WANT_COMPAT_SYS_PWRITEV64
> > # define __ARCH_WANT_COMPAT_SYS_PREADV64V2
> > # define __ARCH_WANT_COMPAT_SYS_PWRITEV64V2
> > +# define __ARCH_WANT_VGETRANDOM_ALLOC
>
> So instead of this define, why can't you do:
>
> config VGETRADOM_ALLOC
> bool
> select ADVISE_SYSCALLS
>
> and then have
>
> config GENERIC_VDSO_RANDOM_WHATEVER
> bool
> select VGETRANDOM_ALLOC
>
> This gives a clear Kconfig dependency instead of the random
> ADVISE_SYSCALLS select.

That's much better indeed. I was trying to straddle the two conventions
of `#define __ARCH_...` for syscalls and a Kconfig for vDSO functions,
but doing it all together as you've suggested is nicer.

I'll try to figure this out, though so far futzing around suggests there
might have to be both, because of unistd.h being a userspace header.
That is, include/uapi/asm-generic/unistd.h typically needs a `#if
__ARCH_WANT..., #define ...` in it. I'll give it a spin and you'll see
for v8. At the very least it should get rid of the more awkward
`select ADVISE_SYSCALLS if X86_64` part, and will better separate the
arch code from non-arch code.

>
> >--- a/drivers/char/random.c
> > +++ b/drivers/char/random.c
>
> > +#include "../../lib/vdso/getrandom.h"
>
> Seriously?
>
> include/vdso/ exists for a reason.

Er, yes, thanks.

>
> > +#ifdef __ARCH_WANT_VGETRANDOM_ALLOC
> > +/*
> > + * The vgetrandom() function in userspace requires an opaque state, which this
> > + * function provides to userspace, by mapping a certain number of special pages
> > + * into the calling process. It takes a hint as to the number of opaque states
> > + * desired, and returns the number of opaque states actually allocated, the
> > + * size of each one in bytes, and the address of the first state.
>
> As this is a syscall which can be invoked outside of the VDSO, can you
> please provide proper kernel-doc which explains the arguments, the
> functionality and the return value?

Yes, will do.

>
> > + */
> > +SYSCALL_DEFINE3(vgetrandom_alloc, unsigned int __user *, num,
> > + unsigned int __user *, size_per_each, unsigned int, flags)
> > +{
> > + size_t alloc_size, num_states;
> > + unsigned long pages_addr;
> > + unsigned int num_hint;
> > + int ret;
> > +
> > + if (flags)
> > + return -EINVAL;
> > +
> > + if (get_user(num_hint, num))
> > + return -EFAULT;
> > +
> > + num_states = clamp_t(size_t, num_hint, 1, (SIZE_MAX & PAGE_MASK) / sizeof(struct vgetrandom_state));
> > + alloc_size = PAGE_ALIGN(num_states * sizeof(struct vgetrandom_state));
> > +
> > + if (put_user(alloc_size / sizeof(struct vgetrandom_state), num) ||
> > + put_user(sizeof(struct vgetrandom_state), size_per_each))
> > + return -EFAULT;
>
> That's a total of four sizeof(struct vgetrandom_state) usage sites.
>
> size_t state_size = sizeof(struct vgetrandom_state);
>
> perhaps?

Not my style -- I like to have the constant expression at the usage site
so I don't have to remember the variable -- but I'm fine going with your
suggestion, so I'll do that for v8.

Jason