[LEDE-DEV] [PATCH] urandom-seed: add initial implementation

Etienne Champetier champetier.etienne at gmail.com
Fri Jun 3 04:15:12 PDT 2016


Hi John,

2016-06-03 11:00 GMT+02:00 John Crispin <john at phrozen.org>:
> Hi Etienne,
>
> comment inline ...
>
> On 02/06/2016 23:21, Etienne CHAMPETIER wrote:
>> This package:
>> 1) seed /dev/urandom with a saved seed as early as possible
>>     (using /lib/preinit/81_urandom_seed)
>> 2) save a new seed using getrandom() so we are sure /dev/urandom
>>    pool is initialized (using /etc/init.d/urandom_seed)
>>
>> seed size is 512 bytes (ie /proc/sys/kernel/random/poolsize / 8)
>> it's the same size as in ubuntu 14.04 and all systemd systems
>>
>> seed file is /etc/urandom.seed (need a writable path)
>>
>> seeding /dev/urandom doesn't change entropy estimation, so we still have
>> "random: ubus urandom read with 4 bits of entropy available"
>> messages in the logs, but we can now ignore them
>>
>> Once tested on enough configuration (jffs2/ext4/ubifs/...)
>> this package should be added to DEFAULT_PACKAGES
>>
>> We could also add an urandom.seed at build time to improve first boot
>>
>> Signed-off-by: Etienne CHAMPETIER <champetier.etienne at gmail.com>
>> ---
>>  package/utils/urandom-seed/Makefile                | 53 ++++++++++++++++++++
>>  .../urandom-seed/files/81_urandom_seed.preinit     | 15 ++++++
>>  package/utils/urandom-seed/files/getrandom.c       | 58 ++++++++++++++++++++++
>>  package/utils/urandom-seed/files/urandom_seed.init | 19 +++++++
>>  4 files changed, 145 insertions(+)
>>  create mode 100644 package/utils/urandom-seed/Makefile
>>  create mode 100644 package/utils/urandom-seed/files/81_urandom_seed.preinit
>>  create mode 100644 package/utils/urandom-seed/files/getrandom.c
>>  create mode 100644 package/utils/urandom-seed/files/urandom_seed.init
>>
>> diff --git a/package/utils/urandom-seed/Makefile b/package/utils/urandom-seed/Makefile
>> new file mode 100644
>> index 0000000..ac58bfc
>> --- /dev/null
>> +++ b/package/utils/urandom-seed/Makefile
>> @@ -0,0 +1,53 @@
>> +#
>> +# Copyright (C) 2016 Etienne CHAMPETIER <champetier.etienne at gmail.com>
>> +#
>> +# This is free software, licensed under the GNU General Public License v2.
>> +# See /LICENSE for more information.
>> +#
>> +
>> +include $(TOPDIR)/rules.mk
>> +
>> +PKG_NAME:=urandom-seed
>> +PKG_RELEASE:=1
>> +PKG_LICENSE:=GPL-2.0
>> +PKG_LICENSE_FILES:=COPYING
>> +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)_$(PKG_RELEASE)
>> +PKG_FLAGS:=nonshared
>> +
>> +include $(INCLUDE_DIR)/package.mk
>> +
>> +define Package/urandom-seed
>> +  SECTION:=utils
>> +  CATEGORY:=Base system
>> +  TITLE:=Seed /dev/urandom on startup
>> +  MAINTAINER:=Etienne CHAMPETIER <champetier.etienne at gmail.com>
>> +endef
>> +
>> +define Package/urandom-seed/description
>> +This package takes care of loading a previously saved seed into /dev/urandom,
>> +and save a new seed from getrandom()
>> +endef
>> +
>> +define Build/Prepare
>> +     mkdir -p $(PKG_BUILD_DIR)
>> +endef
>> +
>> +define Build/Configure
>> +endef
>> +
>> +define Build/Compile
>> +     $(TARGET_CC) $(TARGET_CFLAGS) ./files/getrandom.c -o $(PKG_BUILD_DIR)/getrandom
>> +endef
>> +
>> +define Package/urandom-seed/install
>> +     $(INSTALL_DIR) $(1)/usr/bin
>> +     $(INSTALL_BIN) $(PKG_BUILD_DIR)/getrandom $(1)/usr/bin/
>> +
>> +     $(INSTALL_DIR) $(1)/lib/preinit
>> +     $(INSTALL_DATA) ./files/81_urandom_seed.preinit $(1)/lib/preinit/81_urandom_seed
>> +
>> +     $(INSTALL_DIR) $(1)/etc/init.d
>> +     $(INSTALL_BIN) ./files/urandom_seed.init $(1)/etc/init.d/urandom_seed
>> +endef
>> +
>> +$(eval $(call BuildPackage,urandom-seed))
>> diff --git a/package/utils/urandom-seed/files/81_urandom_seed.preinit b/package/utils/urandom-seed/files/81_urandom_seed.preinit
>> new file mode 100644
>> index 0000000..27ff587
>> --- /dev/null
>> +++ b/package/utils/urandom-seed/files/81_urandom_seed.preinit
>> @@ -0,0 +1,15 @@
>> +#!/bin/sh
>> +
>> +do_urandom_seed() {
>> +    S=/etc/urandom.seed
>> +    U=/dev/urandom
>> +
>> +    [ -c $U ] || { echo "Something is wrong with $U"; return; }
>> +    [ -f $S ] || { echo "Seed file not found: $S"; return; }
>> +    [ -O $S -a -G $S -a ! -x $S ] || { echo "Wrong owner / permissions for $S"; return; }
>> +
>> +    echo "Seeding $U with $S"
>> +    cat $S > $U
>> +}
>> +
>> +boot_hook_add preinit_main do_urandom_seed
>> diff --git a/package/utils/urandom-seed/files/getrandom.c b/package/utils/urandom-seed/files/getrandom.c
>> new file mode 100644
>> index 0000000..2093ef8
>> --- /dev/null
>> +++ b/package/utils/urandom-seed/files/getrandom.c
>> @@ -0,0 +1,58 @@
>> +/*
>> + * Copyright (C) 2016 Etienne Champetier <champetier.etienne at gmail.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + */
>> +#define _GNU_SOURCE
>> +#include <errno.h>
>> +#include <linux/random.h>
>> +#include <stdio.h>
>> +#include <stdlib.h>
>> +#include <string.h>
>> +#include <sys/syscall.h>
>> +#include <unistd.h>
>> +
>> +#define ERROR_EXIT(fmt, ...) do { \
>> +        fprintf(stderr, fmt, ## __VA_ARGS__); \
>> +        return EXIT_FAILURE; \
>> +        } while (0)
>> +
>> +int usage(char *name)
>> +{
>> +    fprintf(stderr, "Usage: %s <nb>\n", name);
>> +    fprintf(stderr, " => return <nb> bytes from getrandom()\n");
>> +    return EXIT_FAILURE;
>> +}
>> +
>> +int main(int argc, char *argv[])
>> +{
>> +    if (argc != 2)
>> +        return usage(argv[0]);
>> +
>> +    if (isatty(STDOUT_FILENO))
>> +        ERROR_EXIT("Not outputting random to a tty\n");
>> +
>> +    int nbtot = atoi(argv[1]);
>> +    if (nbtot < 1)
>> +        ERROR_EXIT("Invalid <nb> param (must be > 0)\n");
>> +
>> +    char buf[256];
>> +    int len = sizeof(buf);
>> +    while (nbtot > 0) {
>> +        if (nbtot <= sizeof(buf))
>> +            len = nbtot;
>> +        if (syscall(SYS_getrandom, buf, len, 0) == -1)
>> +            ERROR_EXIT("getrandom() failed: %s\n", strerror(errno));
>> +        if (write(STDOUT_FILENO, buf, len) != len)
>> +            ERROR_EXIT("write() failed: %s\n", strerror(errno));
>> +        nbtot -= sizeof(buf);
>> +    }
>> +}
>
> i was wondering if we really need this extra tool to do the job. i see
> you are using the new get_random syscall. i assume there is no other way
> to get that randomness from the userland using a script ? normally i
> would go for /dev/(u)random but obvioulsy that is not possible here.
>
see
https://github.com/jedisct1/libsodium/issues/374
and the link inside it
http://crypto.stackexchange.com/questions/34019/on-linux-does-dev-random-unblocking-imply-that-dev-urandom-is-seeded

apparently /dev/urandom is initialized first and then /dev/random, so
we can poll()/select() on /dev/random and when it returns it means
/dev/urandom is initialized, but is there any already available
command to poll/select a file? (also i haven't double checked these
findings)
At the end of the second link you also see that minimum read on
/dev/random is 64bits (so dd with size 1 bits will use 64bits)

getrandom() was created for multiple good reasons, has clearly defined
and safe behaviour so this is the way to go for me.
I think we can afford 4K of binary (uncompressed) for a big step up in
security :)

> if we really need this tool, i would prefer to just integrate it into
> the procd.git tree to avoid having an extra package. we would want to
> always install it anyhow.

what about ubox.git for getrandom, and base-files for the preinit and init?

if i have more time to kill i'll try to submit a getrandom like to
busybox (but no promise)

>
> rest looks good on first glance, thanks for the effort.

Your welcome, thanks for the review

>
>         John
>

Etienne

>
>
>> diff --git a/package/utils/urandom-seed/files/urandom_seed.init b/package/utils/urandom-seed/files/urandom_seed.init
>> new file mode 100644
>> index 0000000..b2aba28
>> --- /dev/null
>> +++ b/package/utils/urandom-seed/files/urandom_seed.init
>> @@ -0,0 +1,19 @@
>> +#!/bin/sh /etc/rc.common
>> +
>> +START=99
>> +
>> +SEED=/etc/urandom.seed
>> +
>> +save_seed() {
>> +    touch $SEED.tmp
>> +    chown root:root $SEED.tmp
>> +    chmod 600 $SEED.tmp
>> +    getrandom 512 > $SEED.tmp
>> +
>> +    logger "Saving urandom seed to $SEED"
>> +    mv $SEED.tmp $SEED
>> +}
>> +
>> +boot() {
>> +    save_seed
>> +}
>>



More information about the Lede-dev mailing list