char-cat char-upper char-lower unicode varint stkstring \
wildmatch regex \
prime primetable \
- random-legacy random-fast \
+ random-legacy random-fast random-strong \
time-stamp time-timer time-conf \
bit-ffs bit-fls bit-array \
url \
# Configuration variables of the UCW library and their default values
# (c) 2005--2015 Martin Mares <mj@ucw.cz>
+# (c) 2020 Pavel Charvat <pchar@ucw.cz>
# Version of the whole package
Set("UCW_VERSION" => "6.5.13");
# Use epoll (needs support in libc and kernel, default: auto-detect)
# Set("CONFIG_UCW_EPOLL");
+# Use getrandom (needs support in libc and kernel, default: auto-detect)
+# Set("CONFIG_UCW_GETRANDOM");
+
# Use monotonic clock (default: yes on Linux, no elsewhere)
# Set("CONFIG_UCW_MONOTONIC_CLOCK");
# (c) 2005--2012 Martin Mares <mj@ucw.cz>
# (c) 2006 Robert Spalek <robert@ucw.cz>
# (c) 2008 Michal Vaner <vorner@ucw.cz>
+# (c) 2020 Pavel Charvat <pchar@ucw.cz>
package UCW::Configure::LibUCW;
use UCW::Configure;
FINIS
});
+# Detect if we have the getrandom() syscall
+TestBool("CONFIG_UCW_GETRANDOM", "Checking for getrandom", sub {
+ return UCW::Configure::C::TestCompile("getrandom", <<'FINIS' ) ? 1 : 0;
+#include <sys/random.h>
+int main(void)
+{
+ char c;
+ getrandom(&c, 1, 0);
+ return 0;
+}
+FINIS
+});
+
# Check if we want to use monotonic clock
TestBool("CONFIG_UCW_MONOTONIC_CLOCK", "Checking for monotonic clock", sub {
return Get("CONFIG_LINUX");
fastrand_seed_t fastrand_gen_seed_value(void)
{
+ // Prefer kernel's urandom if getrandom() syscall is available.
+ u64 val;
+ if (strongrand_getrandom_mem_try(&val, sizeof(val)))
+ return val;
+
// Generate a seed value as a mixture of:
// -- current time
// -- process id to deal with frequent fork() or startups
// -- counter to deal with multiple contexts, for example in threaded application
- u64 val;
static u64 static_counter;
ucwlib_lock();
val = (static_counter += 0x1927a7639274162dLLU);
--- /dev/null
+/*
+ * UCW Library -- Strong random generator
+ *
+ * (c) 2020--2022 Pavel Charvat <pchar@ucw.cz>
+ *
+ * This software may be freely distributed and used according to the terms
+ * of the GNU Lesser General Public License.
+ */
+
+#undef LOCAL_DEBUG
+
+#include <ucw/lib.h>
+#include <ucw/random.h>
+#include <ucw/threads.h>
+
+#include <errno.h>
+#include <string.h>
+
+#ifdef CONFIG_UCW_GETRANDOM
+#include <sys/random.h>
+#endif
+
+/*** getrandom() helpers ***/
+
+#ifdef CONFIG_UCW_GETRANDOM
+static bool strongrand_getrandom_detect(void)
+{
+ static int static_detected;
+ int detected;
+ ucwlib_lock();
+ detected = static_detected;
+ if (detected)
+ {
+ ucwlib_unlock();
+ return detected > 0;
+ }
+ byte buf[1];
+ int err;
+ while (1)
+ {
+ int n = getrandom(buf, 1, GRND_NONBLOCK);
+ if (n >= 0)
+ {
+ ASSERT(n == 1);
+ detected = 1;
+ break;
+ }
+ else if (errno != EINTR)
+ {
+ err = errno;
+ detected = -1;
+ break;
+ }
+ }
+ static_detected = detected;
+ ucwlib_unlock();
+ if (detected > 0)
+ {
+ DBG("RANDOM: Kernel supports getrandom()");
+ return true;
+ }
+ else if (err == ENOSYS)
+ {
+ DBG("RANDOM: Kernel does not support getrandom()");
+ return false;
+ }
+ else
+ {
+ // We print an error also for EAGAIN -- for urandom it should be possible only during early boot.
+ msg(L_ERROR, "RANDOM: Failed to call getrandom(): %s -> assuming no support", strerror(err));
+ return false;
+ }
+}
+
+bool strongrand_getrandom_mem_try(void *buf, size_t size)
+{
+ if (!strongrand_getrandom_detect())
+ return false;
+ while (size)
+ {
+ ssize_t n = getrandom(buf, size, 0);
+ if (n < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ die("RANDOM: Failed to call getrandom(): %m");
+ }
+ buf = (byte *)buf + n;
+ size -= n;
+ }
+ return true;
+}
+#else
+bool strongrand_getrandom_mem_try(void *buf UNUSED, size_t size UNUSED)
+{
+ return false;
+}
+#endif
#define fastrand_max_u64 ucw_fastrand_max_u64
#define fastrand_mem ucw_fastrand_mem
#define fastrand_double ucw_fastrand_double
+#define strongrand_getrandom_mem_try ucw_strongrand_getrandom_mem_try
#endif
/* random-fast.c */
/**
* Generate a seed for fastrand_set_seed().
*
- * We currently mix these things (you can add more if needed):
+ * Since glibc 2.25 and kernel 3.17, we use getrandom() syscall
+ * to read kernel's urandom.
+ *
+ * Otherwise we mix these things:
* -- current time
* -- process id to deal with frequent fork() or startups
* -- counter to deal with multiple contexts, for example in threaded application
/** Uniformly generate a random number from range [0.0, 1.0) + possible inaccuracies from basic floating point operations. **/
double fastrand_double(struct fastrand *c);
+/* random-strong.c */
+
+/* FIXME: interface for strong randomness */
+
+// Internals
+bool strongrand_getrandom_mem_try(void *buf, size_t size);
+
#endif