Mail archive
alpine-user

Re: [alpine-user] Startup hangs (aports: sshd?)

From: Steffen Nurpmeso <steffen_at_sdaoden.eu>
Date: Sat, 19 Jan 2019 00:00:12 +0100

Hello again.

Steffen Nurpmeso wrote in <20190117140207.lqzvY%steffen_at_sdaoden.eu>:
 |After upgrading to [edge] i see a possibly endless hang upon
 |startup, which seems to be caused by PRNG init. I have seen the
 |AlpineLinux bug report from two years ago. I have seen hangs of
 |about one to two minutes on the VM since, hmm, not too long, maybe
 |two or three months?, and on the bare metal we do hang also about
 ..

So what am i supposed to do, entirely switch to linux-virt on the
VM? I mean, ok, i could do that, but for example on this laptop
i have multiple installations, and can either boot them from
within each other via qemu, as well as via refit.

Anyway, i have written something that saves entropy in a file and
fills it in via ioctl(2), the stuff goes

  #?0|essex:tmp$ ./zt save /tmp/t.dat
  - 3420 bits of entropy available at /dev/random
  - 2396 bits of entropy remain at /dev/random
  - 1024 bits / 115 bytes of entropy saved to /tmp/t.dat
...
  #?0|essex:/etc/init.d# /tmp/zt load /tmp/t.dat
  - 2631 bits of entropy available at /dev/random
  - 115 bytes / 1024 bits of entropy read from /tmp/t.dat
  - Entropy added
  - 2905 bits of entropy are at at /dev/random

So call this two hour hack stupid, but i will use it.
I will look out for linux-virt after the next kernel update.
A nice weekend i wish.

/*_at_ Save and load Linux (2.6.0+) entropy.
 *_at_ Synopsis: entropy-saver save [file]
 *_at_ Synopsis: entropy-saver load [file]
 *_at_ "file" defaults to a_RAND_FILE_STORE.
 *
 * Copyright (c) 2019 Steffen (Daode) Nurpmeso <steffen_at_sdaoden.eu>.
 * SPDX-License-Identifier: ISC
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/* Random device*/
#define a_RAND_DEV "/dev/random"

/* Maximum number of bytes we handle (must be LT INT_MAX/8!) */
#define a_RAND_NO_BYTES 512

/* Default storage */
#define a_RAND_FILE_STORE "/var/lib/misc/random.dat"

#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sysexits.h>
#include <unistd.h>

#include <linux/random.h>
#include <linux/version.h>

#if KERNEL_VERSION(2,6,0) >= LINUX_VERSION_CODE
# error Linux kernel version and IOCTL usage incompatible.
#endif

static char const a_rand_file_store[] = a_RAND_FILE_STORE;

int
main(int argc, char **argv){
   enum {a_LOAD, a_SAVE};

   struct{
      struct rand_pool_info rpi;
      char buf[a_RAND_NO_BYTES];
   } x;
   char *rpibuf; /* To make C++ happy: rpi.buf is char[0] */
   ssize_t len;
   char const *store;
   int rv, accu, randfd, storfd, iocarg;

   if(argc < 2 || argc > 3)
      goto jeuse;

   if(!strcmp(argv[1], "load"))
      accu = a_LOAD;
   else if(!strcmp(argv[1], "save"))
      accu = a_SAVE;
   else{
jeuse:
      fprintf(stderr,
         "Synopsis: entropy-saver save [storage-file]\n"
         "Synopsis: entropy-saver load [storage-file]\n"
         "\n"
         "storage-file defaults to " a_RAND_FILE_STORE "\n"
         "Exit: sysexits.h: EX_USAGE, EX_NOPERM, EX_IOERR, EX_TEMPFAIL\n");
      rv = EX_USAGE;
      goto jleave;
   }

   randfd = open(a_RAND_DEV, (O_RDONLY | O_NONBLOCK));
   if(randfd == -1){
      accu = errno;
      fprintf(stderr, "Failed to open " a_RAND_DEV ": %s\n",
         strerror(accu));
      rv = (accu == EACCES || accu == EPERM) ? EX_NOPERM : EX_IOERR;
      goto jleave;
   }

   store = (argv[2] != NULL) ? argv[2] : a_rand_file_store;
   storfd = open(store, (accu == a_LOAD ? O_RDONLY
         : O_WRONLY | O_CREAT | O_TRUNC), (S_IRUSR | S_IWUSR));
   if(storfd == -1){
      accu = errno;
      fprintf(stderr, "Failed to open %s: %s\n", store, strerror(accu));
      rv = (accu == EACCES || accu == EPERM) ? EX_NOPERM : EX_IOERR;
      goto jerr1;
   }

   /* For at least statistics */
   rv = ioctl(randfd, (int)RNDGETENTCNT, &iocarg);
   if(rv == -1){
      fprintf(stderr, "Failed to query available entropy of " a_RAND_DEV
         ": %s\n", strerror(errno));
      rv = EX_IOERR;
      goto jerr2;
   }
   x.rpi.entropy_count = iocarg;

   rpibuf = (char*)x.rpi.buf;

   if(accu == a_LOAD){
      printf("- %d bits of entropy available at " a_RAND_DEV "\n",
         x.rpi.entropy_count);

      /* INT: entropy bits */
      len = read(storfd, &x.rpi.entropy_count, sizeof x.rpi.entropy_count);
      if(len == -1){
         fprintf(stderr, "Failed to read from %s: %s\n",
            store, strerror(errno));
         rv = EX_IOERR;
         goto jerr2;
      }
      if(len != sizeof x.rpi.entropy_count){
         fprintf(stderr, "Storage %s: seems corrupted (false format)\n",
            store);
         rv = EX_IOERR;
         goto jerr2;
      }
      if(x.rpi.entropy_count < 128 || x.rpi.entropy_count > a_RAND_NO_BYTES*8){
         fprintf(stderr, "Storage %s seems corrupted (%d entropy bits)\n",
            store, x.rpi.entropy_count);
         rv = EX_IOERR;
         goto jerr2;
      }

      /* REST: pool bytes */
      len = read(storfd, rpibuf, sizeof x.buf);
      if(len == -1){
         fprintf(stderr, "Failed to read from %s: %s\n",
            store, strerror(errno));
         rv = EX_IOERR;
         goto jerr2;
      }
      if(len == 0){
         fprintf(stderr, "Storage %s: seems corrupted (no entropy)\n",
            store);
         rv = EX_TEMPFAIL;
         goto jerr2;
      }
      x.rpi.buf_size = (int)len;

      if(read(storfd, &accu, 1) != 0){
         fprintf(stderr, "Storage %s: seems corrupted (no EOF seen)\n",
            store);
         rv = EX_IOERR;
         goto jerr2;
      }

      printf("- %d bytes / %d bits of entropy read from %s\n",
         x.rpi.buf_size, x.rpi.entropy_count, store);

      accu = ioctl(randfd, RNDADDENTROPY, &x.rpi);
      if(accu == -1){
         fprintf(stderr, "Failed to add %d bits of entropy to " a_RAND_DEV
            ": %s\n", x.rpi.entropy_count, strerror(errno));
         rv = EX_IOERR;
         goto jerr2;
      }

      printf("- Entropy added\n");

      /* For at least statistics */
      rv = ioctl(randfd, (int)RNDGETENTCNT, &iocarg);
      if(rv != -1)
         printf("- %d bits of entropy are at at " a_RAND_DEV "\n", iocarg);
   }else{
      printf("- %d bits of entropy available at " a_RAND_DEV "%s\n",
         x.rpi.entropy_count,
         (x.rpi.entropy_count <= 128 ? ": temporary failure" : ""));
      if(x.rpi.entropy_count <= 128){
         rv = EX_TEMPFAIL;
         goto jerr2;
      }

      len = read(randfd, rpibuf, sizeof x.buf);
      if(len == -1){
         fprintf(stderr, "Failed to read from " a_RAND_DEV ": %s\n",
            strerror(errno));
         rv = EX_IOERR;
         goto jerr2;
      }
      x.rpi.buf_size = (int)len;

      rv = ioctl(randfd, (int)RNDGETENTCNT, &iocarg);
      if(rv == -1){
         fprintf(stderr, "Failed to query remaining entropy of " a_RAND_DEV
            ": %s\n", strerror(errno));
         rv = EX_IOERR;
         goto jerr2;
      }
      printf("- %d bits of entropy remain at " a_RAND_DEV "\n", iocarg);
      x.rpi.entropy_count -= iocarg;

      if(x.rpi.entropy_count <= 128){
         fprintf(stderr, "Insufficient entropy to save from " a_RAND_DEV
            " (%d bits)\n", x.rpi.entropy_count);
         rv = EX_TEMPFAIL;
         goto jerr2;
      }

      if((ssize_t)sizeof(x.rpi.entropy_count) != write(storfd,
               &x.rpi.entropy_count, sizeof x.rpi.entropy_count) ||
            len != write(storfd, rpibuf, len)){
         fprintf(stderr, "Failed to write to %s: %s\n",
            store, strerror(errno));
         rv = EX_IOERR;
         goto jerr2;
      }

      printf("- %d bits / %d bytes of entropy saved to %s\n",
         x.rpi.entropy_count, x.rpi.buf_size, store);
   }

   rv = 0;
jerr2:
   if(close(storfd) == -1)
      fprintf(stderr, "Error closing %s: %s\n", store, strerror(errno));
jerr1:
   if(close(randfd) == -1)
      fprintf(stderr, "Error closing " a_RAND_DEV ": %s\n",
         strerror(errno));
jleave:
   return rv;
}

/* s-it-mode */

--steffen
|
|Der Kragenbaer, The moon bear,
|der holt sich munter he cheerfully and one by one
|einen nach dem anderen runter wa.ks himself off
|(By Robert Gernhardt)


---
Unsubscribe:  alpine-user+unsubscribe_at_lists.alpinelinux.org
Help:         alpine-user+help_at_lists.alpinelinux.org
---
Received on Sat Jan 19 2019 - 00:00:12 UTC