Make unpredictableSeed use getrandom (syscall) on Linux

This commit is contained in:
Elias Batek 2025-01-19 01:43:42 +01:00 committed by The Dlang Bot
parent 5b373178c7
commit f2c49d368b

View file

@ -1772,11 +1772,53 @@ else
}
}
version (linux)
{
// `getrandom()` was introduced in Linux 3.17.
// Shim for missing bindings in druntime
version (none)
import core.sys.linux.sys.random : getrandom;
else
{
import core.sys.posix.sys.types : ssize_t;
extern extern(C) ssize_t getrandom(
void* buf,
size_t buflen,
uint flags,
) @system nothrow @nogc;
}
}
/**
A "good" seed for initializing random number engines. Initializing
with $(D_PARAM unpredictableSeed) makes engines generate different
random number sequences every run.
This function utilizes the system $(I cryptographically-secure pseudo-random
number generator (CSPRNG)) or $(I pseudo-random number generator (PRNG))
where available and implemented (currently `arc4random` on applicable BSD
systems or `getrandom` on Linux) to generate high quality pseudo-random
numbers if possible.
As a consequence, calling it may block under certain circumstances (typically
during early boot when the system's entropy pool has not yet been
initialized).
On x86 CPU models which support the `RDRAND` instruction, that will be used
when no more specialized randomness source is implemented.
In the future, further platform-specific PRNGs may be incorporated.
Warning:
$(B This function must not be used for cryptographic purposes.)
Despite being implemented for certain targets, there are no guarantees
that it sources its randomness from a CSPRNG.
The implementation also includes a fallback option that provides very little
randomness and is used when no better source of randomness is available or
integrated on the target system.
As written earlier, this function only aims to provide randomness for seeding
ordinary (non-cryptographic) PRNG engines.
Returns:
A single unsigned integer seed value, different on each successive call
Note:
@ -1788,7 +1830,25 @@ how excellent the source of entropy is.
*/
@property uint unpredictableSeed() @trusted nothrow @nogc
{
version (AnyARC4Random)
version (linux)
{
uint buffer;
/*
getrandom(2):
If the _urandom_ source has been initialized, reads of up to
256 bytes will always return as many bytes as requested and
will not be interrupted by signals. No such guarantees apply
for larger buffer sizes.
*/
static assert(buffer.sizeof <= 256);
const status = (() @trusted => getrandom(&buffer, buffer.sizeof, 0))();
assert(status == buffer.sizeof);
return buffer;
}
else version (AnyARC4Random)
{
return arc4random();
}
@ -1837,7 +1897,25 @@ if (isUnsigned!UIntType)
/// ditto
@property UIntType unpredictableSeed() @nogc nothrow @trusted
{
version (AnyARC4Random)
version (linux)
{
UIntType buffer;
/*
getrandom(2):
If the _urandom_ source has been initialized, reads of up to
256 bytes will always return as many bytes as requested and
will not be interrupted by signals. No such guarantees apply
for larger buffer sizes.
*/
static assert(buffer.sizeof <= 256);
const status = (() @trusted => getrandom(&buffer, buffer.sizeof, 0))();
assert(status == buffer.sizeof);
return buffer;
}
else version (AnyARC4Random)
{
static if (UIntType.sizeof <= uint.sizeof)
{