-
Notifications
You must be signed in to change notification settings - Fork 182
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
rndr: Add support for aarch64 RNDR register backend #494
Conversation
Personally, I don't think we should do this. For example, we do not allow to overwrite Linux entropy source with RDRAND-based implementation. At the very least, it should be done with a configuration flag (i.e. Why do you want to use RNDR instead of the |
"Want" is a strong way to put it, the main goal here is to add support for the architecture feature. What the associated policy is is an open question as far as I'm concerned and that's why I'm asking for outside opinions :) The situation as it currently stands is as follows. The way the
If we directly have At the same time this crate is mainly supposed to be used for seeding anyway so the performance improvement might just not matter all that much. I'm happy to go either way depending on maintainer preference, both approaches have benefits and drawbacks. Though the annoying downside is that we can only guarantee that we can detect if the feature is available at runtime on Linux meaning that we can only use this 100% safely on systems where the |
Linux should also use other sources to get entropy which gets mixed into its in-kernel CSPRNG, no? I think the same concerns which were raised against using RDRAND as the only entropy source can be applied to RNDR as well. It may be worth to allow users to overwrite entropy source with RDRAND/RNDR (or with a custom impl) using opt-in configuration flags, but it requires a separate discussion. It probably will be part of the future v0.3 release. We can leave this PR open for now and return to it later. |
Maybe it should, though as it is implemented at least as of two weeks ago or so that does not seem to be the case, at least for the aarch64 implementation. It'll try the TrustZone TRNG, failing that RNDR and failing that just use the number of CPU cycles since the last interrupt as the seed.
Agreed, that would be useful for sure. I can just move the |
This would make the RNDR backend unreachable. It may be worth to make RNDR support similar to RDRAND, i.e. you could remove the Linux-specific fallback and instead make the RNDR backend available on all AArch64 targets which are not supported by default after |
Yes that could work. The issue there is that on |
You could require enabling the #[cfg(not(target_feature = "rand"))]
compile_error!("The RNDR backend requires for the `rand` target feature to be enabled at compile time"); But I am not sure if such backend will be useful in practice. Plus, the RNDR detection code could be useful when we will allow users to opt-in into RNDR on Linux targets. |
For sure, the compile-time is easy. The worry is more that if the crate is compiled for the feature but the binary ran on a CPU that doesn't have it the program will crash on a SIGILL. But I suppose this would only be relevant for embedded targets anyway where the users will know what they're building for. Yeah my thinking is that it is good to have the support merged in first and then work on opt-in interfaces for the backends without actually making it the default. |
AArch64 platforms from version Armv8.4 onwards may implement FEAT_RNG. FEAT_RNG introduces the RNDR (and RNDRRS) register, reading from which returns a random number. Add support for using the RNDR register as a backend for getrandom. The implementation is hidden behind a new "rndr" crate feature. For the backend to work, users must ensure that the target platform supports FEAT_RNG because it is not possible to reliably detect the feature at runtime across platforms.
Currently, detecting whether FEAT_RNG is available without std relies on the Linux Kernel's MRS emulation. This commit adds a safe rndr_with_fallback backend for Linux systems. With this backend, getrandom will use the RNDR register on Linux systems where it is available and automatically fallback onto using Linux's getrandom syscall on systems where it is not. This implementation allows the crate to be build for Linux with this feature in advance and then run without having to know whether FEAT_RNG is implemented or not. For the time being, this backend is not used by default on any platform configuration. The intention is for it to be usable as an opt-in when an opt-in mechanism is available in the crate.
badb406
to
f3c5244
Compare
I did as you suggested for the Note: I stumbled onto an issue while writing the test in that it is currently not possible to write integration tests for any module that has |
Hi, is there some way we could move this forward? Would you like to see any specific changes? |
As I wrote above, I don't think we should merge it until v0.3 which should have a proper way to change backends at compile time (hopefully, it will be done before the end of this year). IIUC RNDR is a relatively new extension which has a very limited support in existing hardware (e.g. see the rng column in this list). |
I see, that makes sense. The specific use-case I'm trying to enable is making it possible for users of |
You can define a crate like How fast is RNDR in practice? Usually, hardware-based TRNGs are relatively small, so I think relative overhead of going through the |
It's just a register accessible from EL0 so pretty much as fast as it gets. Though it is possible for it not to return a random number and the retries might introduce some latency, that'll depend on the HW implementation. Still very fast even with the retries, given that the syscall on Linux goes through its own chacha implementation in addition to the syscall overhead. The docs for the Linux syscall specifically state that the implementation is pretty slow and not supposed to be fast:
It's probably not a big difference for small use-cases, but overhead starts to matter a lot if you're generating millions+ of numbers for ML workloads and such. |
It's not a matter of reading from the register, but about throughput achievable in practice, i.e. how much data can be provided by the hardware. Usually, HW generators seeded by "true" RNGs are relatively slow compared to user-space PRNGs. For example, RDRAND provides up to 800 MB/s, which is fast, but still slower than even ChaCha8 CSPRNG.
In such cases users most certainly should use lightweight user-space PRNGs, especially if the workload is not very sensitive to quality of random data. |
That'll depend on the specific hardware implementation and vary a lot in practice, like it does with the x86 implementations. On the wider point I agree though. On the machines I have access to which have the feature the throughput was better than rdrand on Intel machines but still worse than software PRNGs so you're right in that it's better to use those when throughput is a concern, fair enough. |
This PR removes `linux_disable_fallback`, `rdrand`, `js`, `test-in-browser`, and `custom` crate features. As their replacement two new configuration flags are introduced: `getrandom_browser_test` and `getrandom_backend`. The latter can have the following values: `custom`, `rdrand`, `linux_getrandom`, `wasm_js`, `esp_idf`. `getrandom_backend` allows to change default backends which resolves issues like #346 and provides more flexibility to users. For example, it allows to use RDRAND or RDRND (see #494) directly instead of syscall-based interfaces. We previously did not allow such overwrites because of security concerns, but they do not apply in this case since configuration flags used by a project can not be controlled by its upstream dependencies. The `register_custom_getrandom!` macro is removed in favor of explicitly defining the `__getrandom_custom` function. It does not look like the macro was widely used in practice and it's probably easier to explain the `extern fn` approach (especially to embedded developers) than the "magical" registration macro. The new configuration flags also allow a great simplification of our testing code. Finally, ESP-IDF support is no longer enabled by default because of the concerns raised in #397. Users can enable it by enabling the `esp_idf` opt-in backend. Closes #230 Closes #346 Closes #397 Closes #498
@mrkajetanp |
Closing in favor of #512. |
AArch64 platforms from version Armv8.4 onwards may implement FEAT_RNG. FEAT_RNG introduces the RNDR (and RNDRRS) register, reading from which returns a random number.
Add support for using the RNDR register as a backend for getrandom. The implementation is hidden behind a new "rndr" crate feature.
Currently, detecting whether FEAT_RNG is available without std relies on the Linux Kernel's MRS emulation. For that reason the
rndr
implementation is marked as unsafe, because we cannot always detect whether the register is available or not.This commit also adds a safe rndr_with_fallback backend for Linux systems. With this backend, getrandom will use the RNDR register on Linux systems where it is available and automatically fallback onto using Linux's getrandom syscall on systems where it is not.
This implementation allows the crate to be build for Linux with this feature in advance and then run without having to know whether FEAT_RNG is implemented or not.
Implementation questions that might use some discussion:
If the
rndr
feature is switched on, should the behaviour be for the crate to prefer seeding using RNDR over the getrandom syscall or should it only be a fallback in the same way as Intel's RDRAND?if two or more dependencies both depend on
getrandom
,cargo
will still only build it once. However, it unifies all the features, so if any one dependency enablesrdnr
, they will all get it. Should there be somedisable_aarch64_rndr
feature to turn it off for those cases or should it be left as-is?Feature detection with
no_std
relies on Linux MRS emulation which was only merged in Linux 4.11 while the minimum supported kernel version for Rust on aarch64 is 4.1. How should we handle this potential pitfall given that we cannot runtime-detect the feature on those few kernel versions.