From ad5973028c42d947440cdae5e4f106152c3dda28 Mon Sep 17 00:00:00 2001
From: Laurent Bercot
Date: Wed, 8 Jun 2022 17:53:50 +0000
Subject: Prepare for 2.6.0.0; delete s6-fillurandompool; add rngseed
Signed-off-by: Laurent Bercot
---
.gitignore | 2 +-
AUTHORS | 1 +
NEWS | 5 +-
configure | 4 +
doc/index.html | 4 +-
doc/rngseed.html | 134 +++++++++++++++
doc/s6-fillurandompool.html | 74 --------
doc/upgrade.html | 4 +-
package/deps.mak | 6 +-
package/info | 2 +-
package/modes | 2 +-
package/targets.mak | 2 +-
src/minutils/deps-exe/rngseed | 2 +
src/minutils/deps-exe/s6-fillurandompool | 1 -
src/minutils/rngseed.c | 279 +++++++++++++++++++++++++++++++
src/minutils/s6-fillurandompool.c | 10 --
16 files changed, 436 insertions(+), 96 deletions(-)
create mode 100644 doc/rngseed.html
delete mode 100644 doc/s6-fillurandompool.html
create mode 100644 src/minutils/deps-exe/rngseed
delete mode 100644 src/minutils/deps-exe/s6-fillurandompool
create mode 100644 src/minutils/rngseed.c
delete mode 100644 src/minutils/s6-fillurandompool.c
diff --git a/.gitignore b/.gitignore
index bb472fe..43ea92b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,8 +5,8 @@
*.so.*
/config.mak
/src/include/s6-linux-utils/config.h
+/rngseed
/s6-chroot
-/s6-fillurandompool
/s6-freeramdisk
/s6-hostname
/s6-logwatch
diff --git a/AUTHORS b/AUTHORS
index 3d6eaf7..11f9c99 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -11,3 +11,4 @@ Thanks to:
Jorge Almeida
Olivier Brunel
Natanael Copa
+ Jason Donenfeld
diff --git a/NEWS b/NEWS
index d418b3f..1885d6c 100644
--- a/NEWS
+++ b/NEWS
@@ -1,9 +1,12 @@
Changelog for s6-linux-utils.
-In 2.5.1.8
+In 2.6.0.0
----------
- Adaptation to skalibs-2.12.0.0.
+ - s6-fillurandompool removed.
+ - New program: rngseed, replacing s6-fillurandompool, with
+a lot more features.
In 2.5.1.7
diff --git a/configure b/configure
index d3fb5a0..f407635 100755
--- a/configure
+++ b/configure
@@ -46,6 +46,7 @@ Optional features:
--enable-absolute-paths do not rely on PATH to access this package's binaries,
hardcode absolute BINDIR/foobar paths instead [disabled]
--enable-nsss use the nsss library for user information [disabled]
+ --with-seed-dir=DIR make DIR the default rngseed directory [/var/lib/rngseed]
EOF
exit 0
@@ -160,6 +161,7 @@ addlibdpath=''
vpaths=''
vpathd=''
build=
+seeddir=/var/lib/rngseed
for arg ; do
case "$arg" in
@@ -192,6 +194,7 @@ for arg ; do
--disable-absolute-paths|--enable-absolute-paths=no) abspath=false ;;
--enable-nsss|--enable-nsss=yes) usensss=true ;;
--disable-nsss|--enable-nsss=no) usensss=false ;;
+ --with-seed-file=*) seed=${arg#*=} ;;
--enable-*|--disable-*|--with-*|--without-*|--*dir=*) ;;
--host=*|--target=*) target=${arg#*=} ;;
--build=*) build=${arg#*=} ;;
@@ -476,6 +479,7 @@ else
echo "#define ${package_macro_name}_EXTBINPREFIX \"\""
fi
echo "#define ${package_macro_name}_LIBEXECPREFIX \"$libexecdir/\""
+echo "#define RNGSEED_DIR \"$seeddir\""
echo
echo "#endif"
exec 1>&3 3>&-
diff --git a/doc/index.html b/doc/index.html
index 733a1c7..d8077c2 100644
--- a/doc/index.html
+++ b/doc/index.html
@@ -63,7 +63,7 @@ library.
- The current released version of s6-linux-utils is
-2.5.1.8.
+2.6.0.0.
- Alternatively, you can checkout a copy of the
s6-linux-utils
git repository:
@@ -100,8 +100,8 @@ the previous versions of s6-linux-utils and the current one.
+ rngseed [ -r | -R ] [ -N | -n ] [ -w | -W ] [ -d dir ] [ -v verbosity ]
+
+
+
+ The behaviour of rngseed depends on what options it is given. By default, it
+just waits until the entropy pool is full, then exits 0.
+
+
+ Options
+
+ Configuration options
+
+
+ - -v verbosity : be more or less verbose.
+Default is 1, meaning rngseed will print warning and error
+messages. 0 will make it only print error messages, not warnings.
+2 or more will make it add informational messages.
+ - -d dir : use dir as the
+directory where the seed file is located (for reading as well as writing).
+dir must be located on a writable, permanent filesystem.
+Default is /var/lib/rngseed.
+
+
+ Behaviour options
+
+
+ - -r : read from a seed file. rngseed will attempt to read
+some bits from dir/seed and seed the kernel's RNG with the data.
+dir must be on a writable filesystem, because the seed file will be unlinked
+(the same data must not be used to seed the RNG twice). rngseed -r is
+typically used at boot time, in init scripts, right after mounting the
+filesystem where the seed has been saved.
+ - -R : read from a seed file, ignoring creditability.
+Behaves like -r, but will not increase the entropy count of the
+kernel RNG even if the seed file is marked as creditable.
+ - -w : write to a seed file. rngseed will save some
+random bits into dir/seed, marking the seed as creditable if the
+RNG's entropy pool is fully initialized. rngseed -w is typically used at
+shutdown time, right before unmounting filesystems; the point is to store
+a seed on disk so it can be reused on next boot by rngseed -r.
+ - -W : write to a seed file, without registering
+creditability. Behaves like -w, but does not mark the new seed
+file as creditable.
+ - -N : block. After reading a seed file if required,
+and before writing a new seed file if required, rngseed will wait until the
+entropy pool is ready. This ensures that future readings of the kernel
+RNG will be cryptographically secure, and that new seed files will be
+creditable. This is the default.
+ - -n : do not block. Immediately proceed even if the entropy
+pool is not ready. This may make a new seed file non-creditable.
+
+
+ Creditability
+
+
+ A seed is said to be creditable if it has been obtained through a
+cryptographically secure RNG. This means it is safe from replay attacks, and
+safe to use to count towards the entropy pool when seeding the kernel RNG.
+rngseed -w will normally always create a creditable seed file,
+especially if used at shutdown time: by then, the kernel's entropy pool
+should have been initialized for a while.
+
+
+
+ An uncreditable seed can be used to add to the random pool, but
+should not increment the entropy count, because it is not safe from
+replay attacks. rngseed -r will do the right thing if the seed
+it reads is uncreditable.
+
+
+
+ rngseed uses the seed file's permissions to mark creditability.
+An uncreditable seed has rights 0600; a creditable seed has rights 0400.
+
+
+ Exit codes
+
+
+ - 0: success
+ - 100: wrong usage
+ - 111: system call failure
+
+
+ Notes
+
+
+ - rngseed -N replaces the old s6-fillurandompool program,
+that only waited for the entropy pool to get ready, but did not include any
+seed file management.
+ - The options are named r and w from the seed file's
+point of view.
+rngseed -r reads from the file (and unlinks it) and writes to the kernel
+RNG. rngseed -w reads from the kernel RNG and writes to the file.
+ - rngseed is inspired by Jason Donenfeld's
+seedrng program. It is,
+however, an independent implementation of the same concept.
+
+
+
+
diff --git a/doc/s6-fillurandompool.html b/doc/s6-fillurandompool.html
deleted file mode 100644
index c07b0f4..0000000
--- a/doc/s6-fillurandompool.html
+++ /dev/null
@@ -1,74 +0,0 @@
-
-
-
-
-
- s6-linux-utils: the s6-fillurandompool program
-
-
-
-
-
-
-
-s6-linux-utils
-Software
-skarnet.org
-
-
- The s6-fillurandompool program
-
-
-s6-fillurandompool blocks until the machine's
-/dev/urandom entropy pool is filled up. Then it exits.
-
-
- Interface
-
-
- s6-fillurandompool
-
-
- Rationale
-
-
- For some reason, Linux has two separate entropy pools: one for
-/dev/random and one for /dev/urandom.
-
-
-
- Reading from /dev/random blocks when its entropy pool is
-not full enough, so it will never return weak random data. (Reading
-from /dev/random is overkill anyway, and
-you
-should not be doing it.)
-
-
-
- However, reading from /dev/urandom (which
-you should be doing)
-will not block, even though the entropy pool may not have been
-initialized yet. That's the only insecure thing about it: at boot time,
-/dev/urandom may return weak random data, until its entropy
-pool has filled up.
-
-
-
- s6-fillurandompool is meant to address this issue. Call it once
-early on in your boot scripts, before you need any serious random data;
-when it exits, the /dev/urandom pool has been properly initialized,
-and it is now safe to read from /dev/urandom every time you need
-random data, until the machine shuts down.
-
-
- Notes
-
-
- - s6-fillurandompool will only work on a Linux kernel version
-3.17 or later: this is when the
-getrandom()
-system call, which it internally uses, has been implemented.
-
-
-
-
diff --git a/doc/upgrade.html b/doc/upgrade.html
index e8e658e..bc39329 100644
--- a/doc/upgrade.html
+++ b/doc/upgrade.html
@@ -18,11 +18,13 @@
What has changed in s6-linux-utils
- in 2.5.1.8
+ in 2.6.0.0
- skalibs
dependency bumped to 2.12.0.0.
+ - s6-fillurandompool has been replaced with the new
+rngseed program.
in 2.5.1.7
diff --git a/package/deps.mak b/package/deps.mak
index c464c91..3150147 100644
--- a/package/deps.mak
+++ b/package/deps.mak
@@ -2,8 +2,8 @@
# This file has been generated by tools/gen-deps.sh
#
+src/minutils/rngseed.o src/minutils/rngseed.lo: src/minutils/rngseed.c src/include/s6-linux-utils/config.h
src/minutils/s6-chroot.o src/minutils/s6-chroot.lo: src/minutils/s6-chroot.c
-src/minutils/s6-fillurandompool.o src/minutils/s6-fillurandompool.lo: src/minutils/s6-fillurandompool.c
src/minutils/s6-freeramdisk.o src/minutils/s6-freeramdisk.lo: src/minutils/s6-freeramdisk.c
src/minutils/s6-hostname.o src/minutils/s6-hostname.lo: src/minutils/s6-hostname.c
src/minutils/s6-logwatch.o src/minutils/s6-logwatch.lo: src/minutils/s6-logwatch.c
@@ -21,10 +21,10 @@ src/minutils/s6ps_statparse.o src/minutils/s6ps_statparse.lo: src/minutils/s6ps_
src/minutils/s6ps_ttycache.o src/minutils/s6ps_ttycache.lo: src/minutils/s6ps_ttycache.c src/minutils/s6-ps.h
src/minutils/s6ps_wchan.o src/minutils/s6ps_wchan.lo: src/minutils/s6ps_wchan.c src/minutils/s6-ps.h
+rngseed: EXTRA_LIBS := -lskarnet ${SYSCLOCK_LIB}
+rngseed: src/minutils/rngseed.o
s6-chroot: EXTRA_LIBS := -lskarnet
s6-chroot: src/minutils/s6-chroot.o
-s6-fillurandompool: EXTRA_LIBS := -lskarnet
-s6-fillurandompool: src/minutils/s6-fillurandompool.o
s6-freeramdisk: EXTRA_LIBS := -lskarnet
s6-freeramdisk: src/minutils/s6-freeramdisk.o
s6-hostname: EXTRA_LIBS := -lskarnet
diff --git a/package/info b/package/info
index bcfa0a7..b6f6275 100644
--- a/package/info
+++ b/package/info
@@ -1,4 +1,4 @@
package=s6-linux-utils
-version=2.5.1.8
+version=2.6.0.0
category=admin
package_macro_name=S6_LINUX_UTILS
diff --git a/package/modes b/package/modes
index 5c61589..46b4623 100644
--- a/package/modes
+++ b/package/modes
@@ -1,5 +1,5 @@
+rngseed 0744
s6-chroot 0744
-s6-fillurandompool 0755
s6-freeramdisk 0744
s6-hostname 0755
s6-logwatch 0755
diff --git a/package/targets.mak b/package/targets.mak
index 0fa35ef..f42cb5a 100644
--- a/package/targets.mak
+++ b/package/targets.mak
@@ -1,6 +1,6 @@
BIN_TARGETS := \
+rngseed \
s6-chroot \
-s6-fillurandompool \
s6-freeramdisk \
s6-hostname \
s6-logwatch \
diff --git a/src/minutils/deps-exe/rngseed b/src/minutils/deps-exe/rngseed
new file mode 100644
index 0000000..a11a5f4
--- /dev/null
+++ b/src/minutils/deps-exe/rngseed
@@ -0,0 +1,2 @@
+-lskarnet
+${SYSCLOCK_LIB}
diff --git a/src/minutils/deps-exe/s6-fillurandompool b/src/minutils/deps-exe/s6-fillurandompool
deleted file mode 100644
index e7187fe..0000000
--- a/src/minutils/deps-exe/s6-fillurandompool
+++ /dev/null
@@ -1 +0,0 @@
--lskarnet
diff --git a/src/minutils/rngseed.c b/src/minutils/rngseed.c
new file mode 100644
index 0000000..f00c4fc
--- /dev/null
+++ b/src/minutils/rngseed.c
@@ -0,0 +1,279 @@
+/* ISC license. */
+
+#include
+
+#ifndef SKALIBS_HASCLOCKBOOT
+# error "CLOCK_BOOTTIME required"
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#define USAGE "rngseed [ -d seeddir ] [ -v verbosity ] [ -r | -R ] [ -n | -N ] [ -w | -W ]"
+#define dieusage() strerr_dieusage(100, USAGE)
+
+#define HASH_PREFIX "SeedRNG v1 Old+New Prefix"
+#define HASH_FALLBACK "SeedRNG v1 No New Seed Failure"
+
+struct flags_s
+{
+ unsigned int read: 1 ;
+ unsigned int rcred: 1 ;
+ unsigned int block: 1 ;
+ unsigned int write: 1 ;
+ unsigned int wcred: 1 ;
+} ;
+#define FLAGS_ZERO { .read = 0, .rcred = 1, .block = 1, .write = 0, .wcred = 1 }
+
+struct randpoolinfo_s
+{
+ int entropy_count ;
+ int buf_size ;
+ char buffer[512] ;
+} ;
+
+static unsigned int verbosity = 1 ;
+
+static inline void mkdirp (char *s, size_t len)
+{
+ mode_t m = umask(0) ;
+ size_t i = 1 ;
+ for (; i < len ; i++) if (s[i] == '/')
+ {
+ s[i] = 0 ;
+ if (mkdir(s, 02755) < 0 && errno != EEXIST)
+ strerr_diefu2sys(111, "mkdir ", s) ;
+ s[i] = '/' ;
+ }
+ umask(m) ;
+}
+
+static inline int read_seed_nb (char *s, size_t len)
+{
+ int wcred ;
+ size_t w = 0 ;
+#ifdef SKALIBS_HASGETRANDOM
+ while (w < len)
+ {
+ ssize_t r = getrandom(s + w, len - w, GRND_NONBLOCK) ;
+ if (r == -1)
+ {
+ if (errno == EINTR) continue ;
+ if (error_isagain(errno)) break ;
+ strerr_diefu1sys(111, "getrandom") ;
+ }
+ else w += r ;
+ }
+ wcred = w >= len ;
+ if (!wcred)
+#else
+ tain dummy = TAIN_EPOCH ;
+ iopause_fd x = { .events = IOPAUSE_READ } ;
+ x.fd = openbc_read("/dev/random") ;
+ if (x.fd == -1) strerr_diefu2sys(111, "open ", "/dev/random") ;
+ wcred = iopause(&x, 1, &dummy, &dummy) ;
+ if (wcred == -1) strerr_diefu1sys(111, "iopause") ;
+ fd_close(x.fd) ;
+#endif
+ random_devurandom(s + w, len - w) ;
+ return wcred ;
+}
+
+int main (int argc, char const *const *argv)
+{
+ blake2s_ctx ctx = BLAKE2S_INIT(32) ;
+ char const *seeddir = RNGSEED_DIR ;
+ struct flags_s flags = FLAGS_ZERO ;
+ PROG = "rngseed" ;
+ {
+ subgetopt l = SUBGETOPT_ZERO ;
+ for (;;)
+ {
+ int opt = subgetopt_r(argc, argv, "d:v:rRnNwW", &l) ;
+ if (opt == -1) break ;
+ switch (opt)
+ {
+ case 'd' : seeddir = l.arg ; break ;
+ case 'v' : if (!uint0_scan(l.arg, &verbosity)) dieusage() ; break ;
+ case 'r' : flags.read = 1 ; flags.rcred = 1 ; break ;
+ case 'R' : flags.read = 1 ; flags.rcred = 0 ; break ;
+ case 'n' : flags.block = 0 ; break ;
+ case 'N' : flags.block = 1 ; break ;
+ case 'w' : flags.write = 1 ; flags.wcred = 1 ; break ;
+ case 'W' : flags.write = 1 ; flags.wcred = 0 ; break ;
+ default : dieusage() ;
+ }
+ }
+ argc -= l.ind ; argv += l.ind ;
+ }
+
+ {
+ size_t dirlen = strlen(seeddir) ;
+ char file[dirlen + 6] ;
+ memcpy(file, seeddir, dirlen) ;
+ while (dirlen && file[dirlen-1] == '/') dirlen-- ;
+ memcpy(file + dirlen, "/seed", 6) ;
+
+ if (flags.write)
+ {
+ struct timespec ts ;
+ if (dirlen)
+ {
+ file[dirlen] = 0 ;
+ mkdirp(file, dirlen) ;
+ if (mkdir(file, 0700) == -1)
+ {
+ struct stat st ;
+ if (errno != EEXIST) strerr_diefu2sys(111, "mkdir ", file) ;
+ if (stat(file, &st) == -1)
+ strerr_diefu2sys(111, "stat ", file) ;
+ if (st.st_mode & 0077)
+ {
+ if (verbosity)
+ strerr_warnw2sys(file, "has permissive modes, changing it to 0700") ;
+ if (chmod(file, 0700) == -1)
+ strerr_diefu2sys(111, "chmod ", file) ;
+ }
+ }
+ file[dirlen] = '/' ;
+ }
+ blake2s_update(&ctx, HASH_PREFIX, sizeof(HASH_PREFIX) - 1) ;
+ clock_gettime(CLOCK_REALTIME, &ts) ;
+ blake2s_update(&ctx, (char *)&ts, sizeof ts) ;
+ clock_gettime(CLOCK_BOOTTIME, &ts) ;
+ blake2s_update(&ctx, (char *)&ts, sizeof ts) ;
+ }
+
+ if (flags.read)
+ {
+ struct randpoolinfo_s req ;
+ struct stat st ;
+ size_t seedlen ;
+ int fd ;
+ if (verbosity >= 2) strerr_warni2x("reading seed from ", file) ;
+ fd = openbc_read(file) ;
+ if (fd == -1) strerr_diefu2sys(111, "open ", file) ;
+ errno = 0 ;
+ seedlen = allread(fd, req.buffer, 512) ;
+ if (errno) strerr_diefu2sys(111, "read from ", file) ;
+ if (!seedlen) strerr_dief2x(100, "empty ", file) ;
+ if (fstat(fd, &st) == -1) strerr_diefu2sys(111, "stat ", file) ;
+ if (unlink(file) == -1) strerr_diefu2sys(111, "unlink ", file) ;
+ fd_close(fd) ;
+ if (flags.write)
+ {
+ blake2s_update(&ctx, (char *)&seedlen, sizeof(seedlen)) ;
+ blake2s_update(&ctx, req.buffer, seedlen) ;
+ }
+ if (flags.rcred && st.st_mode & S_IWUSR && verbosity)
+ strerr_warnw2x(file, " was not marked as creditable") ;
+ req.entropy_count = flags.rcred && !(st.st_mode & S_IWUSR) ? (seedlen << 3) : 0 ;
+ req.buf_size = seedlen ;
+ fd = openbc_read("/dev/urandom") ;
+ if (fd == -1) strerr_diefu2sys(111, "open ", "/dev/urandom") ;
+ if (verbosity >= 2)
+ {
+ char fmt[SIZE_FMT] ;
+ fmt[size_fmt(fmt, seedlen << 3)] = 0 ;
+ strerr_warni4x("seeding with ", fmt, " bits", req.entropy_count ? "" : " without crediting") ;
+ }
+ if (ioctl(fd, RNDADDENTROPY, &req) == -1)
+ strerr_diefu1sys(111, "seed") ;
+ fd_close(fd) ;
+ }
+
+ if (flags.block)
+ {
+ if (verbosity >= 2)
+ strerr_warni1x("waiting for the entropy pool to initialize") ;
+#ifdef SKALIBS_HASGETRANDOM
+ char c ;
+ ssize_t r = getrandom(&c, 1, 0) ;
+ if (r == -1) strerr_diefu1sys(111, "getrandom") ;
+#else
+ iopause_fd x = { .events = IOPAUSE_READ } ;
+ x.fd = openbc_read("/dev/random") ;
+ if (x.fd == -1) strerr_diefu2sys(111, "open ", "/dev/random") ;
+ if (iopause(&x, 1, 0, 0) == -1) strerr_diefu1sys(111, "iopause") ;
+ fd_close(x.fd) ;
+#endif
+ }
+
+ if (flags.write)
+ {
+ char seed[512] ;
+ size_t len = 512 ;
+ int wcred = 1 ;
+ char s[SIZE_FMT] = "" ;
+ int fd = openbc_read("/proc/sys/kernel/random/poolsize") ;
+ if (fd < 0)
+ {
+ if (verbosity) strerr_warnwu2sys("open ", "/proc/sys/kernel/random/poolsize") ;
+ }
+ else
+ {
+ size_t r ;
+ errno = 0 ;
+ r = allread(fd, s, SIZE_FMT - 1) ;
+ if (errno)
+ {
+ if (verbosity) strerr_warnwu2sys("read from ", "/proc/sys/kernel/random/poolsize") ;
+ }
+ else
+ {
+ s[r] = 0 ;
+ if (!size_scan(s, &r))
+ {
+ if (verbosity) strerr_warnwu2sys("understand ", "/proc/sys/kernel/random/poolsize") ;
+ }
+ else len = (r + 7) >> 3 ;
+ }
+ fd_close(fd) ;
+ }
+ if (len < 32) len = 32 ;
+ if (len > 512) len = 512 ;
+
+ if (verbosity >= 2)
+ {
+ s[size_fmt(s, len << 3)] = 0 ;
+ strerr_warni3x("reading ", s, " bits of random to make the seed") ;
+ }
+ if (flags.block) random_buf(seed, len) ;
+ else wcred = read_seed_nb(seed, len) ;
+ if (!wcred && verbosity) strerr_warnwu1x("make the seed creditable") ;
+ blake2s_update(&ctx, (char *)&len, sizeof(len)) ;
+ blake2s_update(&ctx, seed, len) ;
+ blake2s_final(&ctx, seed + len - 32) ;
+ if (verbosity >= 2) strerr_warni2x("writing seed to ", file) ;
+ umask(0077) ;
+ if (!openwritenclose_unsafe_sync(file, seed, len))
+ strerr_diefu2sys(111, "write to ", file) ;
+ if (flags.wcred && wcred)
+ {
+ if (chmod(file, 0400) == -1 && verbosity)
+ strerr_warnwu3sys("mark ", file, "as creditable") ;
+ }
+ }
+ }
+
+ return 0 ;
+}
diff --git a/src/minutils/s6-fillurandompool.c b/src/minutils/s6-fillurandompool.c
deleted file mode 100644
index c96437c..0000000
--- a/src/minutils/s6-fillurandompool.c
+++ /dev/null
@@ -1,10 +0,0 @@
-/* ISC license. */
-
-#include
-
-int main (void)
-{
- char c ;
- random_buf(&c, 1) ;
- return 0 ;
-}
--
cgit v1.3.1