Bug #21448
closedRandom.urandom may fail to fall back to reading /dev/urandom on Linux < 3.17
Description
Origianlly reported for tmpdir: https://github.com/ruby/tmpdir/issues/50
On Linux, Random.urandom
is expected to first attempt the getrandom(2)
syscall (Linux >= 3.17), and fall back to reading from /dev/urandom
if it is not supported.
In Ruby 3.1, commit 54c91185c9273b9699693910fa95383c86f2af22 replaced the fallback routine that read from /dev/urandom
with a call to getentropy(3)
, if available at compile time.
On Linux, glibc 2.25 and musl 1.1.20 started to provide a getentropy(3)
implementation based on getrandom(2)
. If Ruby is compiled with such a libc version but run on Linux 3.16 or earlier, both getrandom()
and getentropy(3)
fail. As a result, Random.urandom
becomes unusable, even though /dev/urandom
is still available.
I couldn't find the orignal issue the commit was intended to address, except that it appears to related to macOS. Is there a scenario on macOS where CCRandomGenerateBytes()
or SecRandomCopyBytes()
might fail, while getentropy()
will still succeed?
Updated by nobu (Nobuyoshi Nakada) 5 days ago
- Backport changed from 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN to 3.2: REQUIRED, 3.3: REQUIRED, 3.4: REQUIRED
Unfortunately, despite the same signature, getentropy
is different thing in different layers depending on the platform.
-
getentropy(3)
- a library function on Linux:The
getentropy()
function is implemented usinggetrandom(2)
. -
getentropy(2)
- a system call on macOS:Unlike the random(4) pseudo-devices, it is not vulnerable to file descriptor exhaustion attacks and is available when sandboxed or in a chroot, making it more reliable for security-critical applications.
I think we should use getentropy()
only on macOS.
It could be solved by either of the following patches.
diff --git i/configure.ac w/configure.ac
index 7270bd5e8b9..144e11fcb57 100644
--- i/configure.ac
+++ w/configure.ac
@@ -2137,3 +2137,3 @@ AC_CHECK_FUNCS(getcwd)
AC_CHECK_FUNCS(getegid)
-AC_CHECK_FUNCS(getentropy)
+AS_CASE([$target_os], [darwin*], [AC_CHECK_FUNCS(getentropy)])
AC_CHECK_FUNCS(geteuid)
diff --git i/random.c w/random.c
index f6f63e4cffe..7423f48b1a5 100644
--- i/random.c
+++ w/random.c
@@ -440,3 +440,3 @@ random_init(int argc, VALUE *argv, VALUE obj)
-#ifdef HAVE_GETENTROPY
+#if defined(HAVE_GETENTROPY) && defined(__APPLE__)
# define MAX_SEED_LEN_PER_READ 256
Updated by rhenium (Kazuki Yamaguchi) 5 days ago
FWIW getentropy()
has recently made it into POSIX (with a slight difference in errno behavior compared to existing implementations). I think supporting it as an alternative makes sense, not just for macOS.
My suggestion would be to use getentropy()
as an implementation of fill_random_bytes_syscall()
rather than replacing fill_random_bytes_urandom()
.
However, that would mean it is no longer used as a fallback after CCRandomGenerateBytes()
or SecRandomCopyBytes()
fails on macOS. I'm not sure it can actually happen.
Updated by nobu (Nobuyoshi Nakada) 5 days ago
- Status changed from Open to Closed
Applied in changeset git|1181a682a6c314c92686e3701defa1eb44068c4e.
[Bug #21448] Use getentropy(2)
only on macOS
If this is not a system call, then it is using getrandom (which would
have been tried already), and cannot be used as a replacement for the
random devices.
Updated by nobu (Nobuyoshi Nakada) 3 days ago
rhenium (Kazuki Yamaguchi) wrote in #note-2:
FWIW
getentropy()
has recently made it into POSIX (with a slight difference in errno behavior compared to existing implementations). I think supporting it as an alternative makes sense, not just for macOS.
Thank you for the info.
My suggestion would be to use
getentropy()
as an implementation offill_random_bytes_syscall()
rather than replacingfill_random_bytes_urandom()
.However, that would mean it is no longer used as a fallback after
CCRandomGenerateBytes()
orSecRandomCopyBytes()
fails on macOS. I'm not sure it can actually happen.
Reordered and split in to 3 steps.