summaryrefslogtreecommitdiff
path: root/absl/random/internal/seed_material.cc
diff options
context:
space:
mode:
Diffstat (limited to 'absl/random/internal/seed_material.cc')
-rw-r--r--absl/random/internal/seed_material.cc40
1 files changed, 39 insertions, 1 deletions
diff --git a/absl/random/internal/seed_material.cc b/absl/random/internal/seed_material.cc
index 4d38a574..0fcba509 100644
--- a/absl/random/internal/seed_material.cc
+++ b/absl/random/internal/seed_material.cc
@@ -50,6 +50,12 @@
#endif
+#if defined(__GLIBC__) && \
+ (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25))
+// glibc >= 2.25 has getentropy()
+#define ABSL_RANDOM_USE_GET_ENTROPY 1
+#endif
+
#if defined(ABSL_RANDOM_USE_BCRYPT)
#include <bcrypt.h>
@@ -122,8 +128,29 @@ bool ReadSeedMaterialFromOSEntropyImpl(absl::Span<uint32_t> values) {
#else
+#if defined(ABSL_RANDOM_USE_GET_ENTROPY)
+// On *nix, use getentropy() if supported. Note that libc may support
+// getentropy(), but the kernel may not, in which case this function will return
+// false.
+bool ReadSeedMaterialFromGetEntropy(absl::Span<uint32_t> values) {
+ auto buffer = reinterpret_cast<uint8_t*>(values.data());
+ size_t buffer_size = sizeof(uint32_t) * values.size();
+ while (buffer_size > 0) {
+ // getentropy() has a maximum permitted length of 256.
+ size_t to_read = std::min<size_t>(buffer_size, 256);
+ int result = getentropy(buffer, to_read);
+ if (result < 0) {
+ return false;
+ }
+ buffer += to_read;
+ buffer_size -= to_read;
+ }
+ return true;
+}
+#endif // defined(ABSL_RANDOM_GETENTROPY)
+
// On *nix, read entropy from /dev/urandom.
-bool ReadSeedMaterialFromOSEntropyImpl(absl::Span<uint32_t> values) {
+bool ReadSeedMaterialFromDevURandom(absl::Span<uint32_t> values) {
const char kEntropyFile[] = "/dev/urandom";
auto buffer = reinterpret_cast<uint8_t*>(values.data());
@@ -150,6 +177,17 @@ bool ReadSeedMaterialFromOSEntropyImpl(absl::Span<uint32_t> values) {
return success;
}
+bool ReadSeedMaterialFromOSEntropyImpl(absl::Span<uint32_t> values) {
+#if defined(ABSL_RANDOM_USE_GET_ENTROPY)
+ if (ReadSeedMaterialFromGetEntropy(values)) {
+ return true;
+ }
+#endif
+ // Libc may support getentropy, but the kernel may not, so we still have
+ // to fallback to ReadSeedMaterialFromDevURandom().
+ return ReadSeedMaterialFromDevURandom(values);
+}
+
#endif
} // namespace