Subject: Re: bug#23605: /dev/urandom not seeded across reboots

From: Leo Famulari <[email-masked]>
Date: Wed, 25 May 2016 12:38:15 -0400

On Tue, May 24, 2016 at 02:24:59PM +0200, Ludovic Courtès wrote:
> Leo Famulari <[email-masked]> skribis:
> > +      (mkdir-p "/var/run")
> > +      (close-port (open-file "/var/run/urandom-seed" "a0b"))
> 
> Or simply ‘open-output-file’.

Done in the attached diff.

> Maybe do:
> 
>   (define %random-seed-file
>     "/var/run/random-seed")

Done.

> > +         (start #~(lambda _
> > +                    (exec-command
> > +                      (zero?
> > +                        (system (string-append "cat "
> > +                                               "/var/run/urandom-seed"
> > +                                               " > /dev/urandom"))))))
> 
> Instead of spawning ‘cat’, we can do:
> 
>   (when (file-exists? #$%random-seed-file)
>     (call-with-input-file #$%random-seed-file
>       (lambda (seed)
>         (call-with-output-file "/dev/urandom"
>           (lambda (random)
>             (dump-port seed random))))))
>   #t   ;service successfully “started”

I think I've done this correctly, as attached, but I can't test it yet
since I still get an error: "service: Wrong number of arguments in form
(service urandom-seed-service-type)".

> > +         (stop #~(lambda _
> > +                   (exec-command
> > +                     (zero?
> > +                       (system* "dd" "if=/dev/urandom"
> > +                                (string-append "of=" "/var/run/urandom-seed")
> > +                                "count=1" "bs=512"))))))))
> 
> Likewise, I would suggest using:
> 
>   (let ((buf (make-bytevector 512)))
>     (call-with-input-file "/dev/urandom"
>       (lambda (random)
>         (get-bytevector-n! random buf 512)))
>     …)

I tried to fill in the …, but again, I'm struggling here :p

More advice requested! :)
diff --git a/gnu/services/base.scm b/gnu/services/base.scm
index 96bf8da..b26fee1 100644
--- a/gnu/services/base.scm
+++ b/gnu/services/base.scm
@@ -93,6 +93,8 @@
             gpm-service-type
             gpm-service
 
+            urandom-seed-service
+
             %base-services))
 
 ;;; Commentary:
@@ -1200,6 +1202,55 @@ extra rules from the packages listed in @var{rules}."
   "Return a service that uses @var{device} as a swap device."
   (service swap-service-type device))
 
+(define %random-seed-file
+  "/var/run/random-seed")
+
+(define %urandom-seed-activation
+  ;; Activation gexp for the urandom seed
+  #~(begin
+      (use-modules (guix build utils))
+
+      (mkdir-p (dirname %random-seed-file))
+      (close-port (open-output-file %random-seed-file))
+      (chmod %random-seed-file #o600)))
+
+(define (urandom-seed-shepherd-service)
+  "Return a shepherd service for the /dev/urandom seed."
+  (list (shepherd-service
+         (documentation "Preserve entropy across reboots for /dev/urandom.")
+         (provision '(urandom-seed))
+         (requirement '(user-processes)) ; whatever provides file-system /var
+         (start #~(lambda _
+                    (when (file-exists? #$%random-seed-file)
+                      (call-with-input-file #$%random-seed-file
+                        (lambda (seed)
+                          (call-with-output-file "/dev/urandom"
+                            (lambda (urandom)
+                              (dump-port seed urandom))))))
+                    #t))
+         (stop #~(lambda _
+                   (let ((buf (make-bytevector 512)))
+                     (call-with-input-file "/dev/urandom"
+                       (lambda (urandom)
+                         (get-bytevector-n! urandom buf 0 512)
+                           (call-with-output-file #$%random-seed-file
+                             (lambda (seed)
+                               (dump-port buf seed)))
+                       #t))))))))
+
+(define urandom-seed-service-type
+  (service-type (name 'urandom-seed)
+                (extensions
+                 (list (service-extension shepherd-root-service-type
+                                          urandom-seed-shepherd-service)
+                       (service-extension activation-service-type
+                                          (const %urandom-seed-activation))
+                       ;; Add urandom-seed to the system profile
+                       ;; Where is profile-service-type defined?
+                       (service-extension profile-service-type list)))))
+
+(define (urandom-seed-service)
+  (service urandom-seed-service-type))
 
 (define-record-type* <gpm-configuration>
   gpm-configuration make-gpm-configuration gpm-configuration?
@@ -1281,6 +1332,7 @@ This is the GNU operating system, welcome!\n\n")))
           (static-networking-service "lo" "127.0.0.1"
                                      #:provision '(loopback))
           (syslog-service)
+          (urandom-seed-service)
           (guix-service)
           (nscd-service)