From d7c61f365d9a8cc4b61756ff284e85cfe47ccea3 Mon Sep 17 00:00:00 2001 From: Elias Batek Date: Sun, 19 Jan 2025 01:43:42 +0100 Subject: [PATCH] Make `unpredictableSeed` use `getrandom` (syscall) on Linux --- std/random.d | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 80 insertions(+), 2 deletions(-) diff --git a/std/random.d b/std/random.d index c2210248edf..6c113984c28 100644 --- a/std/random.d +++ b/std/random.d @@ -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) {