2020-11-09 05:23:58 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
2010-08-14 21:23:26 +02:00
|
|
|
|
|
|
|
#include <errno.h>
|
2015-10-24 22:58:24 +02:00
|
|
|
#include <fcntl.h>
|
2019-07-22 13:51:30 +02:00
|
|
|
#include <linux/random.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#if USE_SYS_RANDOM_H
|
|
|
|
# include <sys/random.h>
|
|
|
|
#endif
|
2010-08-14 21:23:26 +02:00
|
|
|
#include <sys/stat.h>
|
2019-07-22 13:51:30 +02:00
|
|
|
#include <sys/xattr.h>
|
2015-10-24 22:58:24 +02:00
|
|
|
#include <unistd.h>
|
2010-08-14 21:23:26 +02:00
|
|
|
|
2018-08-06 15:58:16 +02:00
|
|
|
#include "sd-id128.h"
|
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2015-10-25 13:14:12 +01:00
|
|
|
#include "fd-util.h"
|
2019-04-30 19:25:29 +02:00
|
|
|
#include "fs-util.h"
|
2015-10-25 14:08:25 +01:00
|
|
|
#include "io-util.h"
|
2010-08-14 21:23:26 +02:00
|
|
|
#include "log.h"
|
2018-11-19 20:26:37 +01:00
|
|
|
#include "main-func.h"
|
2020-03-02 06:48:21 +01:00
|
|
|
#include "missing_random.h"
|
2019-10-31 03:07:23 +01:00
|
|
|
#include "missing_syscall.h"
|
2012-04-10 21:54:31 +02:00
|
|
|
#include "mkdir.h"
|
2019-07-22 13:51:30 +02:00
|
|
|
#include "parse-util.h"
|
2019-07-19 19:34:10 +02:00
|
|
|
#include "random-util.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "string-util.h"
|
|
|
|
#include "util.h"
|
2019-07-22 13:51:30 +02:00
|
|
|
#include "xattr-util.h"
|
|
|
|
|
|
|
|
typedef enum CreditEntropy {
|
|
|
|
CREDIT_ENTROPY_NO_WAY,
|
|
|
|
CREDIT_ENTROPY_YES_PLEASE,
|
|
|
|
CREDIT_ENTROPY_YES_FORCED,
|
|
|
|
} CreditEntropy;
|
|
|
|
|
|
|
|
static CreditEntropy may_credit(int seed_fd) {
|
|
|
|
_cleanup_free_ char *creditable = NULL;
|
|
|
|
const char *e;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(seed_fd >= 0);
|
|
|
|
|
|
|
|
e = getenv("SYSTEMD_RANDOM_SEED_CREDIT");
|
|
|
|
if (!e) {
|
|
|
|
log_debug("$SYSTEMD_RANDOM_SEED_CREDIT is not set, not crediting entropy.");
|
|
|
|
return CREDIT_ENTROPY_NO_WAY;
|
|
|
|
}
|
|
|
|
if (streq(e, "force")) {
|
|
|
|
log_debug("$SYSTEMD_RANDOM_SEED_CREDIT is set to 'force', crediting entropy.");
|
|
|
|
return CREDIT_ENTROPY_YES_FORCED;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = parse_boolean(e);
|
|
|
|
if (r <= 0) {
|
|
|
|
if (r < 0)
|
|
|
|
log_warning_errno(r, "Failed to parse $SYSTEMD_RANDOM_SEED_CREDIT, not crediting entropy: %m");
|
|
|
|
else
|
|
|
|
log_debug("Crediting entropy is turned off via $SYSTEMD_RANDOM_SEED_CREDIT, not crediting entropy.");
|
|
|
|
|
|
|
|
return CREDIT_ENTROPY_NO_WAY;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Determine if the file is marked as creditable */
|
|
|
|
r = fgetxattr_malloc(seed_fd, "user.random-seed-creditable", &creditable);
|
|
|
|
if (r < 0) {
|
|
|
|
if (IN_SET(r, -ENODATA, -ENOSYS, -EOPNOTSUPP))
|
|
|
|
log_debug_errno(r, "Seed file is not marked as creditable, not crediting.");
|
|
|
|
else
|
|
|
|
log_warning_errno(r, "Failed to read extended attribute, ignoring: %m");
|
|
|
|
|
|
|
|
return CREDIT_ENTROPY_NO_WAY;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = parse_boolean(creditable);
|
|
|
|
if (r <= 0) {
|
|
|
|
if (r < 0)
|
|
|
|
log_warning_errno(r, "Failed to parse user.random-seed-creditable extended attribute, ignoring: %s", creditable);
|
|
|
|
else
|
|
|
|
log_debug("Seed file is marked as not creditable, not crediting.");
|
|
|
|
|
|
|
|
return CREDIT_ENTROPY_NO_WAY;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Don't credit the random seed if we are in first-boot mode, because we are supposed to start from
|
|
|
|
* scratch. This is a safety precaution for cases where we people ship "golden" images with empty
|
|
|
|
* /etc but populated /var that contains a random seed. */
|
|
|
|
if (access("/run/systemd/first-boot", F_OK) < 0) {
|
|
|
|
|
|
|
|
if (errno != ENOENT) {
|
|
|
|
log_warning_errno(errno, "Failed to check whether we are in first-boot mode, not crediting entropy: %m");
|
|
|
|
return CREDIT_ENTROPY_NO_WAY;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If ENOENT all is good, we are not in first-boot mode. */
|
|
|
|
} else {
|
|
|
|
log_debug("Not crediting entropy, since booted in first-boot mode.");
|
|
|
|
return CREDIT_ENTROPY_NO_WAY;
|
|
|
|
}
|
|
|
|
|
|
|
|
return CREDIT_ENTROPY_YES_PLEASE;
|
|
|
|
}
|
2010-08-14 21:23:26 +02:00
|
|
|
|
2018-11-16 15:06:40 +01:00
|
|
|
static int run(int argc, char *argv[]) {
|
2013-08-13 22:01:55 +02:00
|
|
|
_cleanup_close_ int seed_fd = -1, random_fd = -1;
|
2019-07-22 13:51:30 +02:00
|
|
|
bool read_seed_file, write_seed_file, synchronous;
|
2013-08-13 22:01:55 +02:00
|
|
|
_cleanup_free_ void* buf = NULL;
|
2019-07-19 19:34:10 +02:00
|
|
|
size_t buf_size;
|
random-seed: read the full seed file, even if it is larger than 512 byte
Previously, we'd only ever read 512 byte from the random seed file,
under the assumption we won't need more. With this change we'll read the
full file, even if it is larger.
The idea behind htis change is that people can dump additional data into the
random seed file offline if they like, and it can be low quality, and
we'll seed the pool with it anyway. Moreover, if people are paranoid and
want us to save/restore a bigger seed, it's easy to do: just truncate
the file to the right size and we'll save/restore as much in the future.
This also reworks the file a bit, introducing two clear if blocks that
load and that save the random seed, and that each are conditionalized
more carefully.
2018-08-06 15:52:45 +02:00
|
|
|
struct stat st;
|
2013-08-13 22:01:55 +02:00
|
|
|
ssize_t k;
|
random-seed: read the full seed file, even if it is larger than 512 byte
Previously, we'd only ever read 512 byte from the random seed file,
under the assumption we won't need more. With this change we'll read the
full file, even if it is larger.
The idea behind htis change is that people can dump additional data into the
random seed file offline if they like, and it can be low quality, and
we'll seed the pool with it anyway. Moreover, if people are paranoid and
want us to save/restore a bigger seed, it's easy to do: just truncate
the file to the right size and we'll save/restore as much in the future.
This also reworks the file a bit, introducing two clear if blocks that
load and that save the random seed, and that each are conditionalized
more carefully.
2018-08-06 15:52:45 +02:00
|
|
|
int r;
|
2010-08-14 21:23:26 +02:00
|
|
|
|
2018-11-20 11:18:22 +01:00
|
|
|
log_setup_service();
|
2010-08-14 21:23:26 +02:00
|
|
|
|
2018-11-20 23:40:44 +01:00
|
|
|
if (argc != 2)
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
"This program requires one argument.");
|
2018-11-16 15:06:40 +01:00
|
|
|
|
2011-08-01 20:52:18 +02:00
|
|
|
umask(0022);
|
|
|
|
|
2019-07-19 19:34:10 +02:00
|
|
|
buf_size = random_pool_size();
|
2010-08-18 19:38:45 +02:00
|
|
|
|
2019-03-07 15:06:37 +01:00
|
|
|
r = mkdir_parents(RANDOM_SEED, 0755);
|
2018-11-16 15:06:40 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to create directory " RANDOM_SEED_DIR ": %m");
|
2010-09-20 15:04:10 +02:00
|
|
|
|
random-seed: read the full seed file, even if it is larger than 512 byte
Previously, we'd only ever read 512 byte from the random seed file,
under the assumption we won't need more. With this change we'll read the
full file, even if it is larger.
The idea behind htis change is that people can dump additional data into the
random seed file offline if they like, and it can be low quality, and
we'll seed the pool with it anyway. Moreover, if people are paranoid and
want us to save/restore a bigger seed, it's easy to do: just truncate
the file to the right size and we'll save/restore as much in the future.
This also reworks the file a bit, introducing two clear if blocks that
load and that save the random seed, and that each are conditionalized
more carefully.
2018-08-06 15:52:45 +02:00
|
|
|
/* When we load the seed we read it and write it to the device and then immediately update the saved seed with
|
|
|
|
* new data, to make sure the next boot gets seeded differently. */
|
2010-08-14 21:23:26 +02:00
|
|
|
|
|
|
|
if (streq(argv[1], "load")) {
|
|
|
|
|
2013-08-13 22:01:55 +02:00
|
|
|
seed_fd = open(RANDOM_SEED, O_RDWR|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600);
|
|
|
|
if (seed_fd < 0) {
|
2019-07-22 10:24:26 +02:00
|
|
|
int open_rw_error = -errno;
|
|
|
|
|
random-seed: read the full seed file, even if it is larger than 512 byte
Previously, we'd only ever read 512 byte from the random seed file,
under the assumption we won't need more. With this change we'll read the
full file, even if it is larger.
The idea behind htis change is that people can dump additional data into the
random seed file offline if they like, and it can be low quality, and
we'll seed the pool with it anyway. Moreover, if people are paranoid and
want us to save/restore a bigger seed, it's easy to do: just truncate
the file to the right size and we'll save/restore as much in the future.
This also reworks the file a bit, introducing two clear if blocks that
load and that save the random seed, and that each are conditionalized
more carefully.
2018-08-06 15:52:45 +02:00
|
|
|
write_seed_file = false;
|
2016-02-05 01:45:08 +01:00
|
|
|
|
2013-08-13 22:01:55 +02:00
|
|
|
seed_fd = open(RANDOM_SEED, O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
|
|
|
if (seed_fd < 0) {
|
2016-02-05 01:45:08 +01:00
|
|
|
bool missing = errno == ENOENT;
|
|
|
|
|
|
|
|
log_full_errno(missing ? LOG_DEBUG : LOG_ERR,
|
|
|
|
open_rw_error, "Failed to open " RANDOM_SEED " for writing: %m");
|
|
|
|
r = log_full_errno(missing ? LOG_DEBUG : LOG_ERR,
|
|
|
|
errno, "Failed to open " RANDOM_SEED " for reading: %m");
|
2018-11-16 15:06:40 +01:00
|
|
|
return missing ? 0 : r;
|
2010-08-14 21:23:26 +02:00
|
|
|
}
|
random-seed: read the full seed file, even if it is larger than 512 byte
Previously, we'd only ever read 512 byte from the random seed file,
under the assumption we won't need more. With this change we'll read the
full file, even if it is larger.
The idea behind htis change is that people can dump additional data into the
random seed file offline if they like, and it can be low quality, and
we'll seed the pool with it anyway. Moreover, if people are paranoid and
want us to save/restore a bigger seed, it's easy to do: just truncate
the file to the right size and we'll save/restore as much in the future.
This also reworks the file a bit, introducing two clear if blocks that
load and that save the random seed, and that each are conditionalized
more carefully.
2018-08-06 15:52:45 +02:00
|
|
|
} else
|
|
|
|
write_seed_file = true;
|
2010-08-14 21:23:26 +02:00
|
|
|
|
2013-08-13 22:01:55 +02:00
|
|
|
random_fd = open("/dev/urandom", O_RDWR|O_CLOEXEC|O_NOCTTY, 0600);
|
2019-07-22 10:24:50 +02:00
|
|
|
if (random_fd < 0)
|
|
|
|
return log_error_errno(errno, "Failed to open /dev/urandom: %m");
|
2010-08-14 21:23:26 +02:00
|
|
|
|
random-seed: read the full seed file, even if it is larger than 512 byte
Previously, we'd only ever read 512 byte from the random seed file,
under the assumption we won't need more. With this change we'll read the
full file, even if it is larger.
The idea behind htis change is that people can dump additional data into the
random seed file offline if they like, and it can be low quality, and
we'll seed the pool with it anyway. Moreover, if people are paranoid and
want us to save/restore a bigger seed, it's easy to do: just truncate
the file to the right size and we'll save/restore as much in the future.
This also reworks the file a bit, introducing two clear if blocks that
load and that save the random seed, and that each are conditionalized
more carefully.
2018-08-06 15:52:45 +02:00
|
|
|
read_seed_file = true;
|
2019-07-22 13:51:30 +02:00
|
|
|
synchronous = true; /* make this invocation a synchronous barrier for random pool initialization */
|
2010-08-14 21:23:26 +02:00
|
|
|
|
|
|
|
} else if (streq(argv[1], "save")) {
|
|
|
|
|
random-seed: read the full seed file, even if it is larger than 512 byte
Previously, we'd only ever read 512 byte from the random seed file,
under the assumption we won't need more. With this change we'll read the
full file, even if it is larger.
The idea behind htis change is that people can dump additional data into the
random seed file offline if they like, and it can be low quality, and
we'll seed the pool with it anyway. Moreover, if people are paranoid and
want us to save/restore a bigger seed, it's easy to do: just truncate
the file to the right size and we'll save/restore as much in the future.
This also reworks the file a bit, introducing two clear if blocks that
load and that save the random seed, and that each are conditionalized
more carefully.
2018-08-06 15:52:45 +02:00
|
|
|
random_fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
2018-11-16 15:06:40 +01:00
|
|
|
if (random_fd < 0)
|
|
|
|
return log_error_errno(errno, "Failed to open /dev/urandom: %m");
|
random-seed: read the full seed file, even if it is larger than 512 byte
Previously, we'd only ever read 512 byte from the random seed file,
under the assumption we won't need more. With this change we'll read the
full file, even if it is larger.
The idea behind htis change is that people can dump additional data into the
random seed file offline if they like, and it can be low quality, and
we'll seed the pool with it anyway. Moreover, if people are paranoid and
want us to save/restore a bigger seed, it's easy to do: just truncate
the file to the right size and we'll save/restore as much in the future.
This also reworks the file a bit, introducing two clear if blocks that
load and that save the random seed, and that each are conditionalized
more carefully.
2018-08-06 15:52:45 +02:00
|
|
|
|
2013-08-13 22:01:55 +02:00
|
|
|
seed_fd = open(RANDOM_SEED, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600);
|
2018-11-16 15:06:40 +01:00
|
|
|
if (seed_fd < 0)
|
|
|
|
return log_error_errno(errno, "Failed to open " RANDOM_SEED ": %m");
|
2010-08-14 21:23:26 +02:00
|
|
|
|
random-seed: read the full seed file, even if it is larger than 512 byte
Previously, we'd only ever read 512 byte from the random seed file,
under the assumption we won't need more. With this change we'll read the
full file, even if it is larger.
The idea behind htis change is that people can dump additional data into the
random seed file offline if they like, and it can be low quality, and
we'll seed the pool with it anyway. Moreover, if people are paranoid and
want us to save/restore a bigger seed, it's easy to do: just truncate
the file to the right size and we'll save/restore as much in the future.
This also reworks the file a bit, introducing two clear if blocks that
load and that save the random seed, and that each are conditionalized
more carefully.
2018-08-06 15:52:45 +02:00
|
|
|
read_seed_file = false;
|
|
|
|
write_seed_file = true;
|
2019-07-22 13:51:30 +02:00
|
|
|
synchronous = false;
|
2018-11-20 23:40:44 +01:00
|
|
|
} else
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
"Unknown verb '%s'.", argv[1]);
|
2010-08-14 21:23:26 +02:00
|
|
|
|
2018-11-16 15:06:40 +01:00
|
|
|
if (fstat(seed_fd, &st) < 0)
|
|
|
|
return log_error_errno(errno, "Failed to stat() seed file " RANDOM_SEED ": %m");
|
random-seed: read the full seed file, even if it is larger than 512 byte
Previously, we'd only ever read 512 byte from the random seed file,
under the assumption we won't need more. With this change we'll read the
full file, even if it is larger.
The idea behind htis change is that people can dump additional data into the
random seed file offline if they like, and it can be low quality, and
we'll seed the pool with it anyway. Moreover, if people are paranoid and
want us to save/restore a bigger seed, it's easy to do: just truncate
the file to the right size and we'll save/restore as much in the future.
This also reworks the file a bit, introducing two clear if blocks that
load and that save the random seed, and that each are conditionalized
more carefully.
2018-08-06 15:52:45 +02:00
|
|
|
|
|
|
|
/* If the seed file is larger than what we expect, then honour the existing size and save/restore as much as it says */
|
|
|
|
if ((uint64_t) st.st_size > buf_size)
|
2019-07-19 19:34:10 +02:00
|
|
|
buf_size = MIN(st.st_size, RANDOM_POOL_SIZE_MAX);
|
random-seed: read the full seed file, even if it is larger than 512 byte
Previously, we'd only ever read 512 byte from the random seed file,
under the assumption we won't need more. With this change we'll read the
full file, even if it is larger.
The idea behind htis change is that people can dump additional data into the
random seed file offline if they like, and it can be low quality, and
we'll seed the pool with it anyway. Moreover, if people are paranoid and
want us to save/restore a bigger seed, it's easy to do: just truncate
the file to the right size and we'll save/restore as much in the future.
This also reworks the file a bit, introducing two clear if blocks that
load and that save the random seed, and that each are conditionalized
more carefully.
2018-08-06 15:52:45 +02:00
|
|
|
|
|
|
|
buf = malloc(buf_size);
|
2018-11-16 15:06:40 +01:00
|
|
|
if (!buf)
|
|
|
|
return log_oom();
|
random-seed: read the full seed file, even if it is larger than 512 byte
Previously, we'd only ever read 512 byte from the random seed file,
under the assumption we won't need more. With this change we'll read the
full file, even if it is larger.
The idea behind htis change is that people can dump additional data into the
random seed file offline if they like, and it can be low quality, and
we'll seed the pool with it anyway. Moreover, if people are paranoid and
want us to save/restore a bigger seed, it's easy to do: just truncate
the file to the right size and we'll save/restore as much in the future.
This also reworks the file a bit, introducing two clear if blocks that
load and that save the random seed, and that each are conditionalized
more carefully.
2018-08-06 15:52:45 +02:00
|
|
|
|
|
|
|
if (read_seed_file) {
|
2018-08-06 15:58:16 +02:00
|
|
|
sd_id128_t mid;
|
2019-07-22 13:51:30 +02:00
|
|
|
|
|
|
|
/* First, let's write the machine ID into /dev/urandom, not crediting entropy. Why? As an
|
|
|
|
* extra protection against "golden images" that are put together sloppily, i.e. images which
|
|
|
|
* are duplicated on multiple systems but where the random seed file is not properly
|
|
|
|
* reset. Frequently the machine ID is properly reset on those systems however (simply
|
|
|
|
* because it's easier to notice, if it isn't due to address clashes and so on, while random
|
|
|
|
* seed equivalence is generally not noticed easily), hence let's simply write the machined
|
|
|
|
* ID into the random pool too. */
|
|
|
|
r = sd_id128_get_machine(&mid);
|
|
|
|
if (r < 0)
|
|
|
|
log_debug_errno(r, "Failed to get machine ID, ignoring: %m");
|
|
|
|
else {
|
|
|
|
r = loop_write(random_fd, &mid, sizeof(mid), false);
|
|
|
|
if (r < 0)
|
|
|
|
log_debug_errno(r, "Failed to write machine ID to /dev/urandom, ignoring: %m");
|
|
|
|
}
|
random-seed: read the full seed file, even if it is larger than 512 byte
Previously, we'd only ever read 512 byte from the random seed file,
under the assumption we won't need more. With this change we'll read the
full file, even if it is larger.
The idea behind htis change is that people can dump additional data into the
random seed file offline if they like, and it can be low quality, and
we'll seed the pool with it anyway. Moreover, if people are paranoid and
want us to save/restore a bigger seed, it's easy to do: just truncate
the file to the right size and we'll save/restore as much in the future.
This also reworks the file a bit, introducing two clear if blocks that
load and that save the random seed, and that each are conditionalized
more carefully.
2018-08-06 15:52:45 +02:00
|
|
|
|
|
|
|
k = loop_read(seed_fd, buf, buf_size, false);
|
|
|
|
if (k < 0)
|
2019-07-22 13:51:30 +02:00
|
|
|
log_error_errno(k, "Failed to read seed from " RANDOM_SEED ": %m");
|
|
|
|
else if (k == 0)
|
random-seed: read the full seed file, even if it is larger than 512 byte
Previously, we'd only ever read 512 byte from the random seed file,
under the assumption we won't need more. With this change we'll read the
full file, even if it is larger.
The idea behind htis change is that people can dump additional data into the
random seed file offline if they like, and it can be low quality, and
we'll seed the pool with it anyway. Moreover, if people are paranoid and
want us to save/restore a bigger seed, it's easy to do: just truncate
the file to the right size and we'll save/restore as much in the future.
This also reworks the file a bit, introducing two clear if blocks that
load and that save the random seed, and that each are conditionalized
more carefully.
2018-08-06 15:52:45 +02:00
|
|
|
log_debug("Seed file " RANDOM_SEED " not yet initialized, proceeding.");
|
2019-07-22 13:51:30 +02:00
|
|
|
else {
|
|
|
|
CreditEntropy lets_credit;
|
|
|
|
|
random-seed: read the full seed file, even if it is larger than 512 byte
Previously, we'd only ever read 512 byte from the random seed file,
under the assumption we won't need more. With this change we'll read the
full file, even if it is larger.
The idea behind htis change is that people can dump additional data into the
random seed file offline if they like, and it can be low quality, and
we'll seed the pool with it anyway. Moreover, if people are paranoid and
want us to save/restore a bigger seed, it's easy to do: just truncate
the file to the right size and we'll save/restore as much in the future.
This also reworks the file a bit, introducing two clear if blocks that
load and that save the random seed, and that each are conditionalized
more carefully.
2018-08-06 15:52:45 +02:00
|
|
|
(void) lseek(seed_fd, 0, SEEK_SET);
|
|
|
|
|
2019-07-22 13:51:30 +02:00
|
|
|
lets_credit = may_credit(seed_fd);
|
2018-08-06 15:58:16 +02:00
|
|
|
|
2019-07-22 13:51:30 +02:00
|
|
|
/* Before we credit or use the entropy, let's make sure to securely drop the
|
|
|
|
* creditable xattr from the file, so that we never credit the same random seed
|
|
|
|
* again. Note that further down we'll write a new seed again, and likely mark it as
|
|
|
|
* credible again, hence this is just paranoia to close the short time window between
|
|
|
|
* the time we upload the random seed into the kernel and download the new one from
|
|
|
|
* it. */
|
|
|
|
|
|
|
|
if (fremovexattr(seed_fd, "user.random-seed-creditable") < 0) {
|
|
|
|
if (!IN_SET(errno, ENODATA, ENOSYS, EOPNOTSUPP))
|
|
|
|
log_warning_errno(errno, "Failed to remove extended attribute, ignoring: %m");
|
|
|
|
|
|
|
|
/* Otherwise, there was no creditable flag set, which is OK. */
|
|
|
|
} else {
|
|
|
|
r = fsync_full(seed_fd);
|
|
|
|
if (r < 0) {
|
|
|
|
log_warning_errno(r, "Failed to synchronize seed to disk, not crediting entropy: %m");
|
|
|
|
|
|
|
|
if (lets_credit == CREDIT_ENTROPY_YES_PLEASE)
|
|
|
|
lets_credit = CREDIT_ENTROPY_NO_WAY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-11 09:53:29 +02:00
|
|
|
r = random_write_entropy(random_fd, buf, k,
|
|
|
|
IN_SET(lets_credit, CREDIT_ENTROPY_YES_PLEASE, CREDIT_ENTROPY_YES_FORCED));
|
|
|
|
if (r < 0)
|
|
|
|
log_error_errno(r, "Failed to write seed to /dev/urandom: %m");
|
2018-08-06 15:58:16 +02:00
|
|
|
}
|
random-seed: read the full seed file, even if it is larger than 512 byte
Previously, we'd only ever read 512 byte from the random seed file,
under the assumption we won't need more. With this change we'll read the
full file, even if it is larger.
The idea behind htis change is that people can dump additional data into the
random seed file offline if they like, and it can be low quality, and
we'll seed the pool with it anyway. Moreover, if people are paranoid and
want us to save/restore a bigger seed, it's easy to do: just truncate
the file to the right size and we'll save/restore as much in the future.
This also reworks the file a bit, introducing two clear if blocks that
load and that save the random seed, and that each are conditionalized
more carefully.
2018-08-06 15:52:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (write_seed_file) {
|
2019-07-22 13:51:30 +02:00
|
|
|
bool getrandom_worked = false;
|
2010-08-14 21:23:26 +02:00
|
|
|
|
2019-07-22 13:51:30 +02:00
|
|
|
/* This is just a safety measure. Given that we are root and most likely created the file
|
|
|
|
* ourselves the mode and owner should be correct anyway. */
|
|
|
|
r = fchmod_and_chown(seed_fd, 0600, 0, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to adjust seed file ownership and access mode.");
|
|
|
|
|
|
|
|
/* Let's make this whole job asynchronous, i.e. let's make ourselves a barrier for
|
|
|
|
* proper initialization of the random pool. */
|
|
|
|
k = getrandom(buf, buf_size, GRND_NONBLOCK);
|
|
|
|
if (k < 0 && errno == EAGAIN && synchronous) {
|
|
|
|
log_notice("Kernel entropy pool is not initialized yet, waiting until it is.");
|
|
|
|
k = getrandom(buf, buf_size, 0); /* retry synchronously */
|
|
|
|
}
|
2018-11-16 15:06:40 +01:00
|
|
|
if (k < 0)
|
2019-07-22 13:51:30 +02:00
|
|
|
log_debug_errno(errno, "Failed to read random data with getrandom(), falling back to /dev/urandom: %m");
|
|
|
|
else if ((size_t) k < buf_size)
|
|
|
|
log_debug("Short read from getrandom(), falling back to /dev/urandom: %m");
|
|
|
|
else
|
|
|
|
getrandom_worked = true;
|
|
|
|
|
|
|
|
if (!getrandom_worked) {
|
|
|
|
/* Retry with classic /dev/urandom */
|
|
|
|
k = loop_read(random_fd, buf, buf_size, false);
|
|
|
|
if (k < 0)
|
|
|
|
return log_error_errno(k, "Failed to read new seed from /dev/urandom: %m");
|
|
|
|
if (k == 0)
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EIO),
|
|
|
|
"Got EOF while reading from /dev/urandom.");
|
|
|
|
}
|
2015-04-21 18:08:09 +02:00
|
|
|
|
|
|
|
r = loop_write(seed_fd, buf, (size_t) k, false);
|
|
|
|
if (r < 0)
|
2018-11-16 15:06:40 +01:00
|
|
|
return log_error_errno(r, "Failed to write new random seed file: %m");
|
2019-07-22 13:51:30 +02:00
|
|
|
|
|
|
|
if (ftruncate(seed_fd, k) < 0)
|
|
|
|
return log_error_errno(r, "Failed to truncate random seed file: %m");
|
|
|
|
|
|
|
|
r = fsync_full(seed_fd);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to synchronize seed file: %m");
|
|
|
|
|
|
|
|
/* If we got this random seed data from getrandom() the data is suitable for crediting
|
|
|
|
* entropy later on. Let's keep that in mind by setting an extended attribute. on the file */
|
|
|
|
if (getrandom_worked)
|
|
|
|
if (fsetxattr(seed_fd, "user.random-seed-creditable", "1", 1, 0) < 0)
|
2020-06-11 09:51:25 +02:00
|
|
|
log_full_errno(ERRNO_IS_NOT_SUPPORTED(errno) ? LOG_DEBUG : LOG_WARNING, errno,
|
2019-07-22 13:51:30 +02:00
|
|
|
"Failed to mark seed file as creditable, ignoring: %m");
|
2010-08-14 21:23:26 +02:00
|
|
|
}
|
|
|
|
|
2019-07-22 13:51:30 +02:00
|
|
|
return 0;
|
2010-08-14 21:23:26 +02:00
|
|
|
}
|
2018-11-16 15:06:40 +01:00
|
|
|
|
|
|
|
DEFINE_MAIN_FUNCTION(run);
|