summaryrefslogtreecommitdiff
path: root/random.c
diff options
context:
space:
mode:
authorNobuyoshi Nakada <nobu@ruby-lang.org>2025-06-22 02:00:56 +0900
committerNobuyoshi Nakada <nobu@ruby-lang.org>2025-06-22 02:00:56 +0900
commitd84a811f31a65821642b165d712f380c0cc060e0 (patch)
tree5e8ba00bd2951f9db2e8ac750228dd5b998a8886 /random.c
parentec20f7feb64d9cd8989ada24315ac4af0bb4158c (diff)
[Bug #21448] Reorder trials in `fill_random_bytes`
First try dedicated system calls, such as `getrandom` or `getentropy`, next possible libraries, then fallback to `/dev/urandom`.
Diffstat (limited to 'random.c')
-rw-r--r--random.c65
1 files changed, 38 insertions, 27 deletions
diff --git a/random.c b/random.c
index 682dd16fec..1611c3db97 100644
--- a/random.c
+++ b/random.c
@@ -447,30 +447,8 @@ random_init(int argc, VALUE *argv, VALUE obj)
# define HAVE_GETRANDOM 1
#endif
-#if defined(HAVE_GETENTROPY) && !defined(HAVE_GETRANDOM)
-/*
- * In the case both `getentropy` and `getrandom` are defined, assume
- * that the former is implemented using the latter, and use the latter
- * in the `syscall` version.
- * Otherwise, in the case only `getentropy`, assume it is defined as
- * the replacement for security purpose of `/dev/urandom`.
- */
-# define MAX_SEED_LEN_PER_READ 256
-static int
-fill_random_bytes_urandom(void *seed, size_t size)
-{
- unsigned char *p = (unsigned char *)seed;
- while (size) {
- size_t len = size < MAX_SEED_LEN_PER_READ ? size : MAX_SEED_LEN_PER_READ;
- if (getentropy(p, len) != 0) {
- return -1;
- }
- p += len;
- size -= len;
- }
- return 0;
-}
-#elif USE_DEV_URANDOM
+/* fill random bytes by reading random device directly */
+#if USE_DEV_URANDOM
static int
fill_random_bytes_urandom(void *seed, size_t size)
{
@@ -510,6 +488,7 @@ fill_random_bytes_urandom(void *seed, size_t size)
# define fill_random_bytes_urandom(seed, size) -1
#endif
+/* fill random bytes by library */
#if 0
#elif defined MAC_OS_X_VERSION_10_7 && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7
@@ -527,7 +506,7 @@ fill_random_bytes_urandom(void *seed, size_t size)
# endif
static int
-fill_random_bytes_syscall(void *seed, size_t size, int unused)
+fill_random_bytes_lib(void *seed, size_t size)
{
#if USE_COMMON_RANDOM
CCRNGStatus status = CCRandomGenerateBytes(seed, size);
@@ -560,7 +539,7 @@ fill_random_bytes_syscall(void *seed, size_t size, int unused)
(defined(__FreeBSD__) && __FreeBSD_version >= 1200079))
// [Bug #15039] arc4random_buf(3) should used only if we know it is fork-safe
static int
-fill_random_bytes_syscall(void *buf, size_t size, int unused)
+fill_random_bytes_lib(void *buf, size_t size)
{
arc4random_buf(buf, size);
return 0;
@@ -643,11 +622,17 @@ fill_random_bytes_bcrypt(void *seed, size_t size)
}
static int
-fill_random_bytes_syscall(void *seed, size_t size, int unused)
+fill_random_bytes_lib(void *seed, size_t size)
{
if (fill_random_bytes_bcrypt(seed, size) == 0) return 0;
return fill_random_bytes_crypt(seed, size);
}
+#else
+# define fill_random_bytes_lib(seed, size) -1
+#endif
+
+/* fill random bytes by dedicated syscall */
+#if 0
#elif defined HAVE_GETRANDOM
static int
fill_random_bytes_syscall(void *seed, size_t size, int need_secure)
@@ -671,6 +656,31 @@ fill_random_bytes_syscall(void *seed, size_t size, int need_secure)
}
return -1;
}
+#elif defined(HAVE_GETENTROPY)
+/*
+ * The Open Group Base Specifications Issue 8 - IEEE Std 1003.1-2024
+ * https://pubs.opengroup.org/onlinepubs/9799919799/functions/getentropy.html
+ *
+ * NOTE: `getentropy`(3) on Linux is implemented using `getrandom`(2),
+ * prefer the latter over this if both are defined.
+ */
+#ifndef GETENTROPY_MAX
+# define GETENTROPY_MAX 256
+#endif
+static int
+fill_random_bytes_syscall(void *seed, size_t size, int need_secure)
+{
+ unsigned char *p = (unsigned char *)seed;
+ while (size) {
+ size_t len = size < GETENTROPY_MAX ? size : GETENTROPY_MAX;
+ if (getentropy(p, len) != 0) {
+ return -1;
+ }
+ p += len;
+ size -= len;
+ }
+ return 0;
+}
#else
# define fill_random_bytes_syscall(seed, size, need_secure) -1
#endif
@@ -680,6 +690,7 @@ ruby_fill_random_bytes(void *seed, size_t size, int need_secure)
{
int ret = fill_random_bytes_syscall(seed, size, need_secure);
if (ret == 0) return ret;
+ if (fill_random_bytes_lib(seed, size) == 0) return 0;
return fill_random_bytes_urandom(seed, size);
}