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

John Crispin john at phrozen.org
Fri Jun 3 04:19:07 PDT 2016



On 03/06/2016 13:15, Etienne Champetier wrote:
> 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 :)

ok at rat-tail of possible problems

> 
>> 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?
> 

ok, ubox.git is probably more appropriate

	John


> 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