From 8d1c2aec21e98b959345520b4cb098c5d472e3a9 Mon Sep 17 00:00:00 2001 From: Scott Baker Date: Thu, 22 Jan 2026 10:07:22 -0800 Subject: [PATCH] Use `getentropy()` for seeding PRNG in Perl_seed() On libc (*nix) systems we call `getentropy()` to get the seed needed to start the PRNG. If that call fails, we fall back to reading the filesystem via `/dev/urandom`. If that fails we fall back to hashing some state variables instead. This should be faster, less risky, and generally better than trying to read from `/dev/urandom` Foo --- Configure | 12 ++++++++++++ Cross/config.sh-arm-linux | 2 ++ Cross/config.sh-arm-linux-n770 | 2 ++ Porting/config.sh | 2 ++ config_h.SH | 12 ++++++++++++ configure.com | 2 ++ metaconfig.h | 2 ++ plan9/config_sh.sample | 2 ++ util.c | 13 +++++++++++++ win32/config.gc | 2 ++ win32/config.vc | 2 ++ 11 files changed, 53 insertions(+) diff --git a/Configure b/Configure index ef2257f438..91daabbe00 100755 --- a/Configure +++ b/Configure @@ -519,6 +519,7 @@ d_gai_strerror='' d_Gconvert='' d_getaddrinfo='' d_getcwd='' +d_getentropy='' d_getenv_preserves_other_thread='' d_getespwnam='' d_getfsstat='' @@ -702,6 +703,7 @@ d_newlocale='' d_querylocale='' d_uselocale='' i_xlocale='' +i_sysrandom='' xlocale_needed='' d_nextafter='' d_nexttoward='' @@ -12759,6 +12761,10 @@ eval $inlibc set xlocale.h i_xlocale eval $inhdr +: see if this is a sys/random.h system +set sys/random.h i_sysrandom +eval $inhdr + : see if newlocale exists set newlocale d_newlocale eval $inlibc @@ -14369,6 +14375,10 @@ eval $inlibc set getcwd d_getcwd eval $inlibc +: see if getentropy exists +set getentropy d_getentropy +eval $inlibc + : check for getenv behavior case "$d_getenv_preserves_other_thread" in '') @@ -25125,6 +25135,7 @@ d_gdbm_ndbm_h_uses_prototypes='$d_gdbm_ndbm_h_uses_prototypes' d_gdbmndbm_h_uses_prototypes='$d_gdbmndbm_h_uses_prototypes' d_getaddrinfo='$d_getaddrinfo' d_getcwd='$d_getcwd' +d_getentropy='$d_getentropy' d_getenv_preserves_other_thread='$d_getenv_preserves_other_thread' d_getespwnam='$d_getespwnam' d_getfsstat='$d_getfsstat' @@ -25718,6 +25729,7 @@ i_vfork='$i_vfork' i_wchar='$i_wchar' i_wctype='$i_wctype' i_xlocale='$i_xlocale' +i_sysrandom='$i_sysrandom' ignore_versioned_solibs='$ignore_versioned_solibs' inc_version_list='$inc_version_list' inc_version_list_init='$inc_version_list_init' diff --git a/Cross/config.sh-arm-linux b/Cross/config.sh-arm-linux index 393efbdc04..09fc1f55eb 100644 --- a/Cross/config.sh-arm-linux +++ b/Cross/config.sh-arm-linux @@ -252,6 +252,7 @@ d_gdbm_ndbm_h_uses_prototypes='undef' d_gdbmndbm_h_uses_prototypes='undef' d_getaddrinfo='undef' d_getcwd='define' +d_getentropy='undef' d_getenv_preserves_other_thread='define' d_getespwnam='undef' d_getfsstat='undef' @@ -808,6 +809,7 @@ i_sysmount='define' i_sysndir='undef' i_sysparam='define' i_syspoll='undef' +i_sysrandom='undef' i_sysresrc='define' i_syssecrt='undef' i_sysselct='define' diff --git a/Cross/config.sh-arm-linux-n770 b/Cross/config.sh-arm-linux-n770 index 9bbfea3e10..3e17b43574 100644 --- a/Cross/config.sh-arm-linux-n770 +++ b/Cross/config.sh-arm-linux-n770 @@ -251,6 +251,7 @@ d_gdbm_ndbm_h_uses_prototypes='undef' d_gdbmndbm_h_uses_prototypes='undef' d_getaddrinfo='undef' d_getcwd='define' +d_getentropy='undef' d_getenv_preserves_other_thread='define' d_getespwnam='undef' d_getfsstat='undef' @@ -806,6 +807,7 @@ i_sysmount='define' i_sysndir='undef' i_sysparam='define' i_syspoll='undef' +i_sysrandom='undef' i_sysresrc='define' i_syssecrt='undef' i_sysselct='define' diff --git a/Porting/config.sh b/Porting/config.sh index d6f1f480cc..a21bbad270 100644 --- a/Porting/config.sh +++ b/Porting/config.sh @@ -263,6 +263,7 @@ d_gdbm_ndbm_h_uses_prototypes='undef' d_gdbmndbm_h_uses_prototypes='undef' d_getaddrinfo='define' d_getcwd='define' +d_getentropy='undef' d_getenv_preserves_other_thread='define' d_getespwnam='undef' d_getfsstat='undef' @@ -830,6 +831,7 @@ i_sysmount='define' i_sysndir='undef' i_sysparam='define' i_syspoll='define' +i_sysrandom='undef' i_sysresrc='define' i_syssecrt='undef' i_sysselct='define' diff --git a/config_h.SH b/config_h.SH index 9f7082e9c6..8586c3e8d8 100755 --- a/config_h.SH +++ b/config_h.SH @@ -561,6 +561,12 @@ sed <$CONFIG_H -e 's!^#undef\(.*/\)\*!/\*#define\1 \*!' -e 's!^#un */ #$d_system HAS_SYSTEM /**/ +/* HAS_SYSRANDOM: + * This symbol, if defined, indicates that the system has the + * sys/random.h header file. + */ +#$i_sysrandom HAS_SYSRANDOM /**/ + /* HAS_TCGETPGRP: * This symbol, if defined, indicates that the tcgetpgrp routine is * available to get foreground process group ID. @@ -1604,6 +1610,12 @@ sed <$CONFIG_H -e 's!^#undef\(.*/\)\*!/\*#define\1 \*!' -e 's!^#un */ #$d_flexfnam FLEXFILENAMES /**/ +/* HAS_GETENTROPY: + * This symbol, if defined, indicates that the getentropy routine is + * available. + */ +#$d_getentropy HAS_GETENTROPY /**/ + /* HAS_GETGRENT: * This symbol, if defined, indicates that the getgrent routine is * available for sequential access of the group database. diff --git a/configure.com b/configure.com index f800aecc6e..45c230ccbc 100644 --- a/configure.com +++ b/configure.com @@ -6210,6 +6210,7 @@ $ WC "d_nice='define'" $ WC "d_nl_langinfo='" + d_nl_langinfo + "'" $ WC "d_nl_langinfo_l='undef'" $ WC "d_non_int_bitfields='define'" +$ WC "d_getentropy='undef'" $ WC "d_getenv_preserves_other_thread='" + d_getenv_preserves_other_thread + "'" $ WC "d_nv_preserves_uv='" + d_nv_preserves_uv + "'" $ WC "nv_overflows_integers_at='" + nv_overflows_integers_at + "'" @@ -6573,6 +6574,7 @@ $ WC "i_sysmount='undef'" $ WC "i_sysndir='undef'" $ WC "i_sysparam='undef'" $ WC "i_syspoll='" + i_syspoll + "'" +$ WC "i_sysrandom='undef'" $ WC "i_sysresrc='undef'" $ WC "i_syssecrt='" + i_syssecrt + "'" $ WC "i_sysselct='undef'" diff --git a/metaconfig.h b/metaconfig.h index 5ef3895889..51b0e21c55 100644 --- a/metaconfig.h +++ b/metaconfig.h @@ -44,6 +44,7 @@ * HAS_FD_SET * HAS_FFS * HAS_FFSL + * HAS_GETENTROPY * HAS_GETMNT * HAS_GMTIME64 * HAS_GNULIBC @@ -85,6 +86,7 @@ * INSTALL_USR_BIN_PERL * I_STDBOOL * I_SYS_MOUNT + * I_SYSRANDOM * I_SYS_STATFS * I_SYS_STATVFS * I_SYS_VFS diff --git a/plan9/config_sh.sample b/plan9/config_sh.sample index a4ba062588..817fa3a106 100644 --- a/plan9/config_sh.sample +++ b/plan9/config_sh.sample @@ -252,6 +252,7 @@ d_gdbm_ndbm_h_uses_prototypes='undef' d_gdbmndbm_h_uses_prototypes='undef' d_getaddrinfo='undef' d_getcwd='define' +d_getentropy='undef' d_getenv_preserves_other_thread='define' d_getespwnam='undef' d_getfsstat='undef' @@ -802,6 +803,7 @@ i_sysmount='undef' i_sysndir='undef' i_sysparam='define' i_syspoll='undef' +i_sysrandom='undef' i_sysresrc='define' i_syssecrt='undef' i_sysselct='define' diff --git a/util.c b/util.c index 70dc1892b2..b603e38872 100644 --- a/util.c +++ b/util.c @@ -38,6 +38,11 @@ #include #include +/* For get_entropy() on non-Linux systems (MacOS, Android) we need sys/random.h */ +#ifdef HAS_SYSRANDOM +#include +#endif + #ifdef __Lynx__ /* Missing protos on LynxOS */ int putenv(char *); @@ -4612,6 +4617,14 @@ Perl_seed(pTHX) #endif U64 u; +#ifdef HAS_GETENTROPY + U8 ok = (getentropy(&u, sizeof(u)) == 0); + PerlIO_printf(Perl_debug_log, "Entropy: OK:%i Seed:%lu\n", ok, u); + if (ok) { + return u; + } +#endif + int fd = PerlLIO_open_cloexec(PERL_RANDOM_DEVICE, 0); if (fd != -1) { if (PerlLIO_read(fd, (void*)&u, sizeof u) != sizeof u) { diff --git a/win32/config.gc b/win32/config.gc index 017c14d30a..2c562c389a 100644 --- a/win32/config.gc +++ b/win32/config.gc @@ -239,6 +239,7 @@ d_gdbm_ndbm_h_uses_prototypes='undef' d_gdbmndbm_h_uses_prototypes='undef' d_getaddrinfo='define' d_getcwd='define' +d_getentropy='undef' d_getenv_preserves_other_thread='define' d_getespwnam='undef' d_getfsstat='undef' @@ -799,6 +800,7 @@ i_sysmount='undef' i_sysndir='undef' i_sysparam='undef' i_syspoll='undef' +i_sysrandom='undef' i_sysresrc='undef' i_syssecrt='undef' i_sysselct='undef' diff --git a/win32/config.vc b/win32/config.vc index 77351781cd..874f3efe37 100644 --- a/win32/config.vc +++ b/win32/config.vc @@ -239,6 +239,7 @@ d_gdbm_ndbm_h_uses_prototypes='undef' d_gdbmndbm_h_uses_prototypes='undef' d_getaddrinfo='undef' d_getcwd='define' +d_getentropy='undef' d_getenv_preserves_other_thread='define' d_getespwnam='undef' d_getfsstat='undef' @@ -798,6 +799,7 @@ i_sysmount='undef' i_sysndir='undef' i_sysparam='undef' i_syspoll='undef' +i_sysrandom='undef' i_sysresrc='undef' i_syssecrt='undef' i_sysselct='undef'