Discussion:
[PATCH] Use getentropy() for seeding PRNG
Janne Blomqvist
2018-08-03 13:19:03 UTC
Permalink
The getentropy function, found on Linux, OpenBSD, and recently also
FreeBSD, can be used to get random bytes to initialize the PRNG. It
is similar to the traditional way of reading from /dev/urandom, but
being a system call rather than a special file, it doesn't suffer from
problems like running out of file descriptors, or failure when running
in a container where /dev/urandom is not available.

Regtested on x86_64-pc-linux-gnu, Ok for trunk?

2018-08-03 Janne Blomqvist <***@gcc.gnu.org>

* configure.ac: Check for getentropy.
* intrinsics/random.c (getosrandom): Use getentropy if available.
* config.h.in: Regenerated.
* configure: Regenerated.
---
libgfortran/configure.ac | 3 ++-
libgfortran/intrinsics/random.c | 7 ++-----
2 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/libgfortran/configure.ac b/libgfortran/configure.ac
index bf6d3634dda..900c7466dec 100644
--- a/libgfortran/configure.ac
+++ b/libgfortran/configure.ac
@@ -312,7 +312,8 @@ if test "${hardwire_newlib:-0}" -eq 1; then
fi
else
AC_CHECK_FUNCS_ONCE(getrusage times mkstemp strtof strtold snprintf \
- ftruncate chsize chdir getlogin gethostname kill link symlink sleep ttyname \
+ ftruncate chsize chdir getentropy getlogin gethostname kill link symlink \
+ sleep ttyname \
alarm access fork setmode fcntl \
gettimeofday stat fstat lstat getpwuid vsnprintf dup \
getcwd localtime_r gmtime_r getpwuid_r ttyname_r clock_gettime \
diff --git a/libgfortran/intrinsics/random.c b/libgfortran/intrinsics/random.c
index 234c5ff95fd..1f47f32188b 100644
--- a/libgfortran/intrinsics/random.c
+++ b/libgfortran/intrinsics/random.c
@@ -309,12 +309,9 @@ getosrandom (void *buf, size_t buflen)
for (size_t i = 0; i < buflen / sizeof (unsigned int); i++)
rand_s (&b[i]);
return buflen;
+#elif defined(HAVE_GETENTROPY)
+ return getentropy (buf, buflen);
#else
- /*
- TODO: When glibc adds a wrapper for the getrandom() system call
- on Linux, one could use that.
-
- TODO: One could use getentropy() on OpenBSD. */
int flags = O_RDONLY;
#ifdef O_CLOEXEC
flags |= O_CLOEXEC;
--
2.17.1
Jakub Jelinek
2018-08-03 13:28:27 UTC
Permalink
Post by Janne Blomqvist
--- a/libgfortran/intrinsics/random.c
+++ b/libgfortran/intrinsics/random.c
@@ -309,12 +309,9 @@ getosrandom (void *buf, size_t buflen)
for (size_t i = 0; i < buflen / sizeof (unsigned int); i++)
rand_s (&b[i]);
return buflen;
+#elif defined(HAVE_GETENTROPY)
+ return getentropy (buf, buflen);
#else
I wonder if it wouldn't be better to use getentropy only if it is successful
and fall back to whatever you were doing before.

E.g. on Linux, I believe getentropy in glibc just uses the getrandom
syscall, which has only been introduced in Linux kernel 3.17.
So, if somebody is running glibc 2.25 or later on kernel < 3.17, it will
fail, even though reads from /dev/urandom could work.
Post by Janne Blomqvist
- /*
- TODO: When glibc adds a wrapper for the getrandom() system call
- on Linux, one could use that.
-
- TODO: One could use getentropy() on OpenBSD. */
int flags = O_RDONLY;
#ifdef O_CLOEXEC
flags |= O_CLOEXEC;
Jakub
Janne Blomqvist
2018-08-03 14:05:33 UTC
Permalink
Post by Jakub Jelinek
Post by Janne Blomqvist
--- a/libgfortran/intrinsics/random.c
+++ b/libgfortran/intrinsics/random.c
@@ -309,12 +309,9 @@ getosrandom (void *buf, size_t buflen)
for (size_t i = 0; i < buflen / sizeof (unsigned int); i++)
rand_s (&b[i]);
return buflen;
+#elif defined(HAVE_GETENTROPY)
+ return getentropy (buf, buflen);
#else
I wonder if it wouldn't be better to use getentropy only if it is successful
and fall back to whatever you were doing before.
E.g. on Linux, I believe getentropy in glibc just uses the getrandom
syscall, which has only been introduced in Linux kernel 3.17.
Yes, that is my understanding as well.
Post by Jakub Jelinek
So, if somebody is running glibc 2.25 or later on kernel < 3.17, it will
fail, even though reads from /dev/urandom could work.
Hmm, fair enough. So replace the random.c part of the patch with

diff --git a/libgfortran/intrinsics/random.c
b/libgfortran/intrinsics/random.c
index 234c5ff95fd..229fa6995c0 100644
--- a/libgfortran/intrinsics/random.c
+++ b/libgfortran/intrinsics/random.c
@@ -310,11 +310,10 @@ getosrandom (void *buf, size_t buflen)
rand_s (&b[i]);
return buflen;
#else
- /*
- TODO: When glibc adds a wrapper for the getrandom() system call
- on Linux, one could use that.
-
- TODO: One could use getentropy() on OpenBSD. */
+#ifdef HAVE_GETENTROPY
+ if (getentropy (buf, buflen) == 0)
+ return 0;
+#endif
int flags = O_RDONLY;
#ifdef O_CLOEXEC
flags |= O_CLOEXEC;



Just to be sure, I regtested this slightly modified patch as well. Ok for
trunk?
--
Janne Blomqvist
Janne Blomqvist
2018-08-13 10:12:12 UTC
Permalink
PING
Post by Janne Blomqvist
Post by Jakub Jelinek
Post by Janne Blomqvist
--- a/libgfortran/intrinsics/random.c
+++ b/libgfortran/intrinsics/random.c
@@ -309,12 +309,9 @@ getosrandom (void *buf, size_t buflen)
for (size_t i = 0; i < buflen / sizeof (unsigned int); i++)
rand_s (&b[i]);
return buflen;
+#elif defined(HAVE_GETENTROPY)
+ return getentropy (buf, buflen);
#else
I wonder if it wouldn't be better to use getentropy only if it is successful
and fall back to whatever you were doing before.
E.g. on Linux, I believe getentropy in glibc just uses the getrandom
syscall, which has only been introduced in Linux kernel 3.17.
Yes, that is my understanding as well.
Post by Jakub Jelinek
So, if somebody is running glibc 2.25 or later on kernel < 3.17, it will
fail, even though reads from /dev/urandom could work.
Hmm, fair enough. So replace the random.c part of the patch with
diff --git a/libgfortran/intrinsics/random.c b/libgfortran/intrinsics/
random.c
index 234c5ff95fd..229fa6995c0 100644
--- a/libgfortran/intrinsics/random.c
+++ b/libgfortran/intrinsics/random.c
@@ -310,11 +310,10 @@ getosrandom (void *buf, size_t buflen)
rand_s (&b[i]);
return buflen;
#else
- /*
- TODO: When glibc adds a wrapper for the getrandom() system call
- on Linux, one could use that.
-
- TODO: One could use getentropy() on OpenBSD. */
+#ifdef HAVE_GETENTROPY
+ if (getentropy (buf, buflen) == 0)
+ return 0;
+#endif
int flags = O_RDONLY;
#ifdef O_CLOEXEC
flags |= O_CLOEXEC;
Just to be sure, I regtested this slightly modified patch as well. Ok for
trunk?
--
Janne Blomqvist
--
Janne Blomqvist
Jakub Jelinek
2018-08-13 20:07:25 UTC
Permalink
PING
LGTM.
Post by Janne Blomqvist
diff --git a/libgfortran/intrinsics/random.c b/libgfortran/intrinsics/
random.c
index 234c5ff95fd..229fa6995c0 100644
--- a/libgfortran/intrinsics/random.c
+++ b/libgfortran/intrinsics/random.c
@@ -310,11 +310,10 @@ getosrandom (void *buf, size_t buflen)
rand_s (&b[i]);
return buflen;
#else
- /*
- TODO: When glibc adds a wrapper for the getrandom() system call
- on Linux, one could use that.
-
- TODO: One could use getentropy() on OpenBSD. */
+#ifdef HAVE_GETENTROPY
+ if (getentropy (buf, buflen) == 0)
+ return 0;
+#endif
int flags = O_RDONLY;
#ifdef O_CLOEXEC
flags |= O_CLOEXEC;
Just to be sure, I regtested this slightly modified patch as well. Ok for
trunk?
--
Janne Blomqvist
Jakub
Rainer Orth
2018-08-14 20:18:20 UTC
Permalink
Hi Janne,
PING
Post by Janne Blomqvist
Post by Jakub Jelinek
Post by Janne Blomqvist
--- a/libgfortran/intrinsics/random.c
+++ b/libgfortran/intrinsics/random.c
@@ -309,12 +309,9 @@ getosrandom (void *buf, size_t buflen)
for (size_t i = 0; i < buflen / sizeof (unsigned int); i++)
rand_s (&b[i]);
return buflen;
+#elif defined(HAVE_GETENTROPY)
+ return getentropy (buf, buflen);
#else
I wonder if it wouldn't be better to use getentropy only if it is successful
and fall back to whatever you were doing before.
E.g. on Linux, I believe getentropy in glibc just uses the getrandom
syscall, which has only been introduced in Linux kernel 3.17.
Yes, that is my understanding as well.
Post by Jakub Jelinek
So, if somebody is running glibc 2.25 or later on kernel < 3.17, it will
fail, even though reads from /dev/urandom could work.
Hmm, fair enough. So replace the random.c part of the patch with
diff --git a/libgfortran/intrinsics/random.c b/libgfortran/intrinsics/
random.c
index 234c5ff95fd..229fa6995c0 100644
--- a/libgfortran/intrinsics/random.c
+++ b/libgfortran/intrinsics/random.c
@@ -310,11 +310,10 @@ getosrandom (void *buf, size_t buflen)
rand_s (&b[i]);
return buflen;
#else
- /*
- TODO: When glibc adds a wrapper for the getrandom() system call
- on Linux, one could use that.
-
- TODO: One could use getentropy() on OpenBSD. */
+#ifdef HAVE_GETENTROPY
+ if (getentropy (buf, buflen) == 0)
+ return 0;
+#endif
int flags = O_RDONLY;
#ifdef O_CLOEXEC
flags |= O_CLOEXEC;
Just to be sure, I regtested this slightly modified patch as well. Ok for
trunk?
the patch broke Solaris 11.3+ bootstrap:

/vol/gcc/src/hg/trunk/local/libgfortran/intrinsics/random.c: In function 'getosrandom':
/vol/gcc/src/hg/trunk/local/libgfortran/intrinsics/random.c:314:7: error: implicit declaration of function 'getentropy'; did you mean 'get_nprocs'? [-Werror=implicit-function-declaration]
314 | if (getentropy (buf, buflen) == 0)
| ^~~~~~~~~~
| get_nprocs


According to the manpage, one needs to include <sys/random.h> to get the
getentropy declaration.

Fixed as follows. Bootstraps on i386-pc-solaris2.11,
i386-pc-solaris2.10 (which lacks getentropy), sparc-sun-solaris2.11, and
x86_64-pc-linux-gnu still running, but all already into make check.

Ok for mainline?

Rainer
--
-----------------------------------------------------------------------------
Rainer Orth, Center for Biotechnology, Bielefeld University


2018-08-14 Rainer Orth <***@CeBiTec.Uni-Bielefeld.DE>

* configure.ac: Check for <sys/random.h>.
* configure, config.h.in: Regenerate.
* intrinsics/random.c [HAVE_SYS_RANDOM_H]: Include <sys/random.h>.
Janne Blomqvist
2018-08-14 20:29:10 UTC
Permalink
Post by Rainer Orth
Hi Janne,
PING
On Fri, Aug 3, 2018 at 5:05 PM, Janne Blomqvist <
Post by Janne Blomqvist
Post by Jakub Jelinek
Post by Janne Blomqvist
--- a/libgfortran/intrinsics/random.c
+++ b/libgfortran/intrinsics/random.c
@@ -309,12 +309,9 @@ getosrandom (void *buf, size_t buflen)
for (size_t i = 0; i < buflen / sizeof (unsigned int); i++)
rand_s (&b[i]);
return buflen;
+#elif defined(HAVE_GETENTROPY)
+ return getentropy (buf, buflen);
#else
I wonder if it wouldn't be better to use getentropy only if it is successful
and fall back to whatever you were doing before.
E.g. on Linux, I believe getentropy in glibc just uses the getrandom
syscall, which has only been introduced in Linux kernel 3.17.
Yes, that is my understanding as well.
Post by Jakub Jelinek
So, if somebody is running glibc 2.25 or later on kernel < 3.17, it
will
Post by Janne Blomqvist
Post by Jakub Jelinek
fail, even though reads from /dev/urandom could work.
Hmm, fair enough. So replace the random.c part of the patch with
diff --git a/libgfortran/intrinsics/random.c b/libgfortran/intrinsics/
random.c
index 234c5ff95fd..229fa6995c0 100644
--- a/libgfortran/intrinsics/random.c
+++ b/libgfortran/intrinsics/random.c
@@ -310,11 +310,10 @@ getosrandom (void *buf, size_t buflen)
rand_s (&b[i]);
return buflen;
#else
- /*
- TODO: When glibc adds a wrapper for the getrandom() system call
- on Linux, one could use that.
-
- TODO: One could use getentropy() on OpenBSD. */
+#ifdef HAVE_GETENTROPY
+ if (getentropy (buf, buflen) == 0)
+ return 0;
+#endif
int flags = O_RDONLY;
#ifdef O_CLOEXEC
flags |= O_CLOEXEC;
Just to be sure, I regtested this slightly modified patch as well. Ok
for
Post by Janne Blomqvist
trunk?
implicit declaration of function 'getentropy'; did you mean 'get_nprocs'?
[-Werror=implicit-function-declaration]
314 | if (getentropy (buf, buflen) == 0)
| ^~~~~~~~~~
| get_nprocs
According to the manpage, one needs to include <sys/random.h> to get the
getentropy declaration.
Fixed as follows. Bootstraps on i386-pc-solaris2.11,
i386-pc-solaris2.10 (which lacks getentropy), sparc-sun-solaris2.11, and
x86_64-pc-linux-gnu still running, but all already into make check.
Ok for mainline?
Rainer
Sorry about that, I wasn't aware that Solaris also has added getentropy.
Patch looks good, Ok for trunk!
--
Janne Blomqvist
Paul Koning
2018-08-03 14:48:14 UTC
Permalink
Post by Janne Blomqvist
The getentropy function, found on Linux, OpenBSD, and recently also
FreeBSD, can be used to get random bytes to initialize the PRNG. It
is similar to the traditional way of reading from /dev/urandom, but
being a system call rather than a special file, it doesn't suffer from
problems like running out of file descriptors, or failure when running
in a container where /dev/urandom is not available.
I don't understand why this is useful.

getrandom, and /dev/random, are for strong (secure) RNGs. A PRNG is something entirely different. By saying we use entropy to seed it, we blur the distinction and create the false impression that the PRNG has security properties.

It would be better to initialize with something more obviously insecure, like gettimeofday().

paul
Fritz Reese
2018-08-13 14:36:35 UTC
Permalink
On Fri, Aug 3, 2018 at 9:19 AM Janne Blomqvist
Post by Janne Blomqvist
The getentropy function, found on Linux, OpenBSD, and recently also
FreeBSD, can be used to get random bytes to initialize the PRNG. It
is similar to the traditional way of reading from /dev/urandom, but
being a system call rather than a special file, it doesn't suffer from
problems like running out of file descriptors, or failure when running
in a container where /dev/urandom is not available.
Regtested on x86_64-pc-linux-gnu, Ok for trunk?
Actually, getentropy() is similar to reading from /dev/random, where
getrandom() is similar to reading from /dev/urandom. Since the
original behavior of getosrandom() is to read from /dev/urandom, I
think it is better to use getrandom() for consistent semantics.

Furthermore, getentropy() may block to achieve an appropriate degree
of randomness, since it is intended for secure use. Of course such
block time would hardly be noticeable for a one-time read of a
thousand bits or so... but on principle I think we should provide a
quick cheesy seed by default, and the user may provide his own seed if
he wants expensive secure bits.

Just my opinion. I am personally OK with the [second version of the]
patch | sed s/getentropy/getrandom/g.

Fritz
Janne Blomqvist
2018-08-13 20:11:59 UTC
Permalink
Post by Fritz Reese
On Fri, Aug 3, 2018 at 9:19 AM Janne Blomqvist
Post by Janne Blomqvist
The getentropy function, found on Linux, OpenBSD, and recently also
FreeBSD, can be used to get random bytes to initialize the PRNG. It
is similar to the traditional way of reading from /dev/urandom, but
being a system call rather than a special file, it doesn't suffer from
problems like running out of file descriptors, or failure when running
in a container where /dev/urandom is not available.
Regtested on x86_64-pc-linux-gnu, Ok for trunk?
Actually, getentropy() is similar to reading from /dev/random, where
getrandom() is similar to reading from /dev/urandom.
No, getentropy is similar to getrandom with the flags argument == 0. Which
is similar to reading /dev/urandom, except that just after boot if enough
entropy hasn't yet been gathered, it may block instead of returning some
not-quite-random data. But once it has been initialized, it will never
block again.

I agree that reading from /dev/random is overkill, but this patch isn't
doing the equivalent of that.
Post by Fritz Reese
Since the
original behavior of getosrandom() is to read from /dev/urandom, I
think it is better to use getrandom() for consistent semantics.
Furthermore, getentropy() may block to achieve an appropriate degree
of randomness, since it is intended for secure use.
The only time this might happen is just after boot, after that the entropy
never drains (in contrast to /dev/random). So unless you're planning to
write an init daemon in Fortran, this shouldn't matter.
--
Janne Blomqvist
Fritz Reese
2018-08-14 13:59:26 UTC
Permalink
On Mon, Aug 13, 2018 at 4:12 PM Janne Blomqvist
Post by Fritz Reese
On Fri, Aug 3, 2018 at 9:19 AM Janne Blomqvist
Post by Janne Blomqvist
The getentropy function, found on Linux, OpenBSD, and recently also
FreeBSD, can be used to get random bytes to initialize the PRNG. It
is similar to the traditional way of reading from /dev/urandom, but
being a system call rather than a special file, it doesn't suffer from
problems like running out of file descriptors, or failure when running
in a container where /dev/urandom is not available.
Regtested on x86_64-pc-linux-gnu, Ok for trunk?
Actually, getentropy() is similar to reading from /dev/random, where
getrandom() is similar to reading from /dev/urandom.
No, getentropy is similar to getrandom with the flags argument == 0. Which is similar to reading /dev/urandom, except that just after boot if enough entropy hasn't yet been gathered, it may block instead of returning some not-quite-random data. But once it has been initialized, it will never block again.
I agree that reading from /dev/random is overkill, but this patch isn't doing the equivalent of that.
Fair enough, I misread the documentation on getentropy(). Then I
concur with Jakub, patch looks OK.

Fritz
Loading...