diff --git a/gnu/services/base.scm b/gnu/services/base.scm index 25716ef152..3fe5cb3329 100644 --- a/gnu/services/base.scm +++ b/gnu/services/base.scm @@ -573,7 +573,13 @@ file systems, as well as corresponding @file{/etc/fstab} entries."))) (lambda (seed) (call-with-output-file "/dev/urandom" (lambda (urandom) - (dump-port seed urandom)))))) + (dump-port seed urandom) + + ;; Writing SEED to URANDOM isn't enough: we must + ;; also tell the kernel to account for these + ;; extra bits of entropy. + (let ((bits (* 8 (stat:size (stat seed))))) + (add-to-entropy-count urandom bits))))))) ;; Try writing from /dev/hwrng into /dev/urandom. ;; It seems that the file /dev/hwrng always exists, even diff --git a/guix/build/syscalls.scm b/guix/build/syscalls.scm index f2fdb4d9d1..bbf2531c79 100644 --- a/guix/build/syscalls.scm +++ b/guix/build/syscalls.scm @@ -68,6 +68,7 @@ statfs free-disk-space device-in-use? + add-to-entropy-count processes mkdtemp! @@ -706,6 +707,33 @@ backend device." (list (strerror err)) (list err)))))) + +;;; +;;; Random. +;;; + +;; From . +(define RNDADDTOENTCNT #x40045201) + +(define (add-to-entropy-count port-or-fd n) + "Add N to the kernel's entropy count (the value that can be read from +/proc/sys/kernel/random/entropy_avail). PORT-OR-FD must correspond to +/dev/urandom or /dev/random. Raise to 'system-error with EPERM when the +caller lacks root privileges." + (let ((fd (if (port? port-or-fd) + (fileno port-or-fd) + port-or-fd)) + (box (make-bytevector (sizeof int)))) + (bytevector-sint-set! box 0 n (native-endianness) + (sizeof int)) + (let-values (((ret err) + (%ioctl fd RNDADDTOENTCNT + (bytevector->pointer box)))) + (unless (zero? err) + (throw 'system-error "add-to-entropy-count" "~A" + (list (strerror err)) + (list err)))))) + ;;; ;;; Containers. diff --git a/tests/syscalls.scm b/tests/syscalls.scm index eeb223b950..1b3121e503 100644 --- a/tests/syscalls.scm +++ b/tests/syscalls.scm @@ -567,6 +567,19 @@ (let ((result (call-with-input-file "/var/run/utmpx" read-utmpx))) (or (utmpx? result) (eof-object? result)))) +(when (zero? (getuid)) + (test-skip 1)) +(test-equal "add-to-entropy-count" + EPERM + (call-with-output-file "/dev/urandom" + (lambda (port) + (catch 'system-error + (lambda () + (add-to-entropy-count port 77) + #f) + (lambda args + (system-error-errno args)))))) + (test-end) (false-if-exception (delete-file temp-file))