You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In some scenarios (e.g. for seeding HashMap) it's desirable to get potentially less secure numbers than to block indefinitely. The motivation is largely equivalent to motivation behind the GRND_NONBLOCK flag used in the getrandom syscall. We probably should add support for such scenarios, either by adding an additional argument or by introducing a separate set of non-blocking functions.
I support adding a non-blocking API for targets that have native non-blocking syscalls like getrandom on Linux.
I'm less eager to implement support for legacy non-blocking reading from "/dev/[u]random".
The caller should implement their own fallback logic for when getrandom isn't available.
getrandom should not simulate a non-blocking syscall on systems that have no non-blocking API.
I don't think applications should have to do #[cfg]-based conditional code to access a non-blocking API. The API should be present everywhere, and in environments where it isn't available, it should return "no non-blocking API available."
Failing to get random bytes from a non-blocking call is not an error; it is an expected condition. It shouldn't be modeled as an error.
This suggests an API something like this:
#[must_use]enumNonBlocking<'a>{/// The system successfully filled the buffer with random data.Filled(&'a[u8]),/// The system is not ready to fulfill the request, but it might be ready later.NotReady,/// The system doesn't implement a non-blocking API.NotImplemented}fngetrandom_nonblocking<'a>(dest:&'amut[u8]) -> Result<NonBlocking<'a>>{ ...}fngetrandom_uninit_nonblocking<'a>(dest:&'amut[MaybeUninit<u8>])) -> Result<NonBlocking<'a>>{ ...}
I'm less eager to implement support for legacy non-blocking reading from "/dev/[u]random".
I agree. We could support sources which respect entropy estimates, but I don't think they are used much in practice nowadays.
The caller should implement their own fallback logic for when getrandom isn't available.
I think some platforms may provide randomness even if PRNG did not get enough initialization entropy (like /dev/urandom on Linux and randABytes on VxWorks). In such cases I think it would be better to return less secure randomness than ask users to implement their own fallback (which likely will be even less secure). In other words, we probably should add an option "give me random numbers even if they may be not secure enough".
Failing to get random bytes from a non-blocking call is not an error; it is an expected condition. It shouldn't be modeled as an error.
I think it's fine to return EAGAIN-like errors when user has explicitly asked for a non-blocking source. Our API is relatively low level and "try again" error codes is a common approach with OS APIs.
To summarize, we probably need combination of the following options:
Secure, may block (default).
Secure, non-blocking, returns "try again" instead of blocking or "not supported".
Potentially insecure, may block (on systems which do not support non-blocking API uses the blocking secure API).
Potentially insecure, non-blocking, returns "try again" instead of blocking or "not supported".
It may be represented as two separate options: quality of generated randomness and blocking behavior. The former also may include the "super secure" option to cover the GRND_RANDOM flag.
My proposed new API for this crate would be to introduce a getrandom::Opts structure which would initially be empty, but could have fields added over time to support things like #365. This would allow us to introduce new functionality by just adding new fields to Opts . Specifically, the API would be:
#[non_exhaustive]// Possible now that MSRV >= 1.40#[derive(Clone,Copy,Debug,Default)]pubstructOpts{}implOpts{pubconstfnnew() -> Self;}pubfnfill(buf:&mut[u8],opts:Opts) -> Result<(),Error>;/// Do we even want this? See discussion belowpubfnfill_uninit(buf:&mut[MaybeUninit<u8>],opts:Opts) -> Result<&mut[u8],Error>;/// Convenience wrapper for `fill(buf, Opts::new())`/// I don't think we would want to deprecate this.pubfngetrandom(buf:&mut[u8]) -> Result<(),Error>;
Handling register_custom_getrandom!()
I would propose having the register_custom_getrandom! support both functions with the type of fill and those with the type of fill_uninit (if we keep the uninit methods). We can use traits/generics to have the macro work with either function type. Similar to the current implementation, the macro would generate a #[no_mangle]extern "Rust" function, but it would have a different signature:
I would also propose having the macro also create an unsafe fn __getrandom_custom(dest: *mut u8, len: usize) function, allowing the custom implementation registered with the next version of getrandom to still work with getrandom 0.2 without folks having to do tricks like those suggested in #433 (comment)
Which targets could even support non-blocking mode at all? For each one, how would it do so?
What would actually use this API? For which use case? At one point we thought maybe libstd would, but I don't think it will ever use getrandom, as it's already implemented what it needs itself.
The one option I know some people definitely need is "don't fall back to /dev/urandom, and don't link in the use_file code at all unless something else in this process is using getrandom without this option." That would require a separate constructor for Opts at least.
An (off by default) insecure or best_effort flag saying "try to get the best randomness the OS currently has, but try to avoid blocking on the OS to acquire more entropy"
This would correspond to GRND_INSECURE
Implementations would still be permitted to block, so we could still support the same number of platforms.
The main use-case would be seeding HashMaps or other non-cryptographic uses.
We want this even if we aren't used by libstd, as many external crates maintain hashmaps seeded via getrandom.
A flag which disables fallback sources of entropy
For example, don't read from a file on Linux
Unclear if this would be platform-specific or platform-agnostic
Activity
briansmith commentedon Oct 5, 2023
getrandomon Linux.getrandomisn't available.getrandomshould not simulate a non-blocking syscall on systems that have no non-blocking API.#[cfg]-based conditional code to access a non-blocking API. The API should be present everywhere, and in environments where it isn't available, it should return "no non-blocking API available."This suggests an API something like this:
newpavlov commentedon Oct 16, 2023
I agree. We could support sources which respect entropy estimates, but I don't think they are used much in practice nowadays.
I think some platforms may provide randomness even if PRNG did not get enough initialization entropy (like
/dev/urandomon Linux andrandAByteson VxWorks). In such cases I think it would be better to return less secure randomness than ask users to implement their own fallback (which likely will be even less secure). In other words, we probably should add an option "give me random numbers even if they may be not secure enough".I think it's fine to return
EAGAIN-like errors when user has explicitly asked for a non-blocking source. Our API is relatively low level and "try again" error codes is a common approach with OS APIs.To summarize, we probably need combination of the following options:
It may be represented as two separate options: quality of generated randomness and blocking behavior. The former also may include the "super secure" option to cover the
GRND_RANDOMflag.josephlr commentedon Jun 4, 2024
Copying from #439
My proposed new API for this crate would be to introduce a
getrandom::Optsstructure which would initially be empty, but could have fields added over time to support things like #365. This would allow us to introduce new functionality by just adding new fields toOpts. Specifically, the API would be:Handling
register_custom_getrandom!()I would propose having the
register_custom_getrandom!support both functions with the type offilland those with the type offill_uninit(if we keep theuninitmethods). We can use traits/generics to have the macro work with either function type. Similar to the current implementation, the macro would generate a#[no_mangle]extern "Rust"function, but it would have a different signature:I would also propose having the macro also create an
unsafe fn __getrandom_custom(dest: *mut u8, len: usize)function, allowing the custom implementation registered with the next version ofgetrandomto still work withgetrandom 0.2without folks having to do tricks like those suggested in #433 (comment)briansmith commentedon Jun 4, 2024
Which targets could even support non-blocking mode at all? For each one, how would it do so?
What would actually use this API? For which use case? At one point we thought maybe libstd would, but I don't think it will ever use getrandom, as it's already implemented what it needs itself.
The one option I know some people definitely need is "don't fall back to /dev/urandom, and don't link in the
use_filecode at all unless something else in this process is using getrandom without this option." That would require a separate constructor forOptsat least.josephlr commentedon Jun 4, 2024
My initial ideas for flags in
Optswould be:insecureorbest_effortflag saying "try to get the best randomness the OS currently has, but try to avoid blocking on the OS to acquire more entropy"GRND_INSECUREHashMaps or other non-cryptographic uses.getrandom.Remove the unstable `rustc-dep-of-std` feature (#694)
Remove the unstable `rustc-dep-of-std` feature (rust-random#694)