[PATCH 2/2] linux: use __getrandom_nocancel in getentropy
Adhemerval Zanella Netto
adhemerval.zanella@linaro.org
Wed Feb 12 12:57:44 GMT 2025
On 09/02/25 00:14, Cristian Rodríguez wrote:
> On Sat, Feb 8, 2025 at 2:05 PM Cristian Rodríguez <cristian@rodriguez.im> wrote:
>>
>> It must use the VDSO implementation if available instead of a raw
>> syscall.
>>
>> Signed-off-by: Cristian Rodríguez <cristian@rodriguez.im>
>
>
> I looked at the other implementations around and needs this needs to
>
> - be made POSIX.2024 compatible, where the only possible errors are
> EINVAL and maybe ENOSYS.
> - The different BSDs implementations where this function originally
> comes from all abort on irrecoverable errors, either by explicit
> raise(SIGKILL) or because getentropy is just a wrapper against
> arc4random_buf
>
> I got to the poin that I think it has just ot be implemented like this now:
>
> int
> getentropy (void *buffer, size_t length)
> {
> /* The interface is documented to return EINVAL for buffer lengths
> longer than 256 bytes. */
> if (length > GETENTROPY_MAX)
> {
> __set_errno (EINVAL);
> return -1;
> }
> __arc4random_buf(buffer, length);
> return 0;
> }
>
> Will that fly here ?
It would change getentropy semantics slight, since arc4random will try
to open/read/close the /dev/urandom if getrandom is not available (due
syscall filtering or old kernels). In this case with current code,
getentropy() will fail with ENOSYS; while for arc4random() it will abort()
if /dev/urandom is not available or if it can't be open (ENFILE, etc.).
I am not sure if this is problem, but I think it would be safe to avoid
changing for now.
Now that we have __getrandom_nocancel, we can just do something like:
static void
getentropy_fatal (void)
{
__libc_fatal ("Fatal glibc error: cannot get entropy for getentropy\n");
}
/* Write LENGTH bytes of randomness starting at BUFFER. Return 0 on
success and -1 on failure. */
int
getentropy (void *buffer, size_t length)
{
if (length > 256)
{
__set_errno (EINVAL);
return -1;
}
/* Try to fill the buffer completely. Even with the 256 byte limit
above, we might still receive an EINTR error (when blocking
during boot). */
void *end = buffer + length;
while (buffer < end)
{
/* NB: No cancellation point. */
ssize_t bytes = __getrandom_nocancel (buffer, end - buffer, 0);
if (bytes < 0)
{
switch (errno)
{
case EINTR:
continue;
case ENOSYS:
return -1;
default:
getentropy_fatal ();
}
}
else if (bytes == 0)
/* No more bytes available. This should not happen under normal
circumstances. */
getentropy_fatal ();
/* Try again in case of a short read. */
buffer += bytes;
}
return 0;
}
And remove both sysdeps/mach/hurd/getentropy.c and sysdeps/unix/sysv/linux/getentropy.c
More information about the Libc-alpha
mailing list