summaryrefslogtreecommitdiff
path: root/src/random-seed/random-seed.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/random-seed/random-seed.c')
-rw-r--r--src/random-seed/random-seed.c148
1 files changed, 83 insertions, 65 deletions
diff --git a/src/random-seed/random-seed.c b/src/random-seed/random-seed.c
index 223b56306c..0c5f329756 100644
--- a/src/random-seed/random-seed.c
+++ b/src/random-seed/random-seed.c
@@ -6,33 +6,35 @@
#include <sys/stat.h>
#include <unistd.h>
+#include "sd-id128.h"
+
#include "alloc-util.h"
#include "fd-util.h"
#include "io-util.h"
#include "log.h"
+#include "main-func.h"
#include "mkdir.h"
#include "string-util.h"
#include "util.h"
#define POOL_SIZE_MIN 512
+#define POOL_SIZE_MAX (10*1024*1024)
-int main(int argc, char *argv[]) {
+static int run(int argc, char *argv[]) {
_cleanup_close_ int seed_fd = -1, random_fd = -1;
+ bool read_seed_file, write_seed_file;
_cleanup_free_ void* buf = NULL;
size_t buf_size = 0;
+ struct stat st;
ssize_t k;
- int r, open_rw_error;
FILE *f;
- bool refresh_seed_file = true;
+ int r;
- if (argc != 2) {
- log_error("This program requires one argument.");
- return EXIT_FAILURE;
- }
+ log_setup_service();
- log_set_target(LOG_TARGET_AUTO);
- log_parse_environment();
- log_open();
+ if (argc != 2)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "This program requires one argument.");
umask(0022);
@@ -46,31 +48,23 @@ int main(int argc, char *argv[]) {
fclose(f);
}
- if (buf_size <= POOL_SIZE_MIN)
+ if (buf_size < POOL_SIZE_MIN)
buf_size = POOL_SIZE_MIN;
- buf = malloc(buf_size);
- if (!buf) {
- r = log_oom();
- goto finish;
- }
-
r = mkdir_parents_label(RANDOM_SEED, 0755);
- if (r < 0) {
- log_error_errno(r, "Failed to create directory " RANDOM_SEED_DIR ": %m");
- goto finish;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to create directory " RANDOM_SEED_DIR ": %m");
- /* 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. */
+ /* 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. */
if (streq(argv[1], "load")) {
+ int open_rw_error;
seed_fd = open(RANDOM_SEED, O_RDWR|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600);
open_rw_error = -errno;
if (seed_fd < 0) {
- refresh_seed_file = false;
+ write_seed_file = false;
seed_fd = open(RANDOM_SEED, O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (seed_fd < 0) {
@@ -80,22 +74,54 @@ int main(int argc, char *argv[]) {
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");
- if (missing)
- r = 0;
-
- goto finish;
+ return missing ? 0 : r;
}
- }
+ } else
+ write_seed_file = true;
random_fd = open("/dev/urandom", O_RDWR|O_CLOEXEC|O_NOCTTY, 0600);
if (random_fd < 0) {
+ write_seed_file = false;
+
random_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY, 0600);
- if (random_fd < 0) {
- r = log_error_errno(errno, "Failed to open /dev/urandom: %m");
- goto finish;
- }
+ if (random_fd < 0)
+ return log_error_errno(errno, "Failed to open /dev/urandom: %m");
}
+ read_seed_file = true;
+
+ } else if (streq(argv[1], "save")) {
+
+ random_fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
+ if (random_fd < 0)
+ return log_error_errno(errno, "Failed to open /dev/urandom: %m");
+
+ seed_fd = open(RANDOM_SEED, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600);
+ if (seed_fd < 0)
+ return log_error_errno(errno, "Failed to open " RANDOM_SEED ": %m");
+
+ read_seed_file = false;
+ write_seed_file = true;
+
+ } else
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Unknown verb '%s'.", argv[1]);
+
+ if (fstat(seed_fd, &st) < 0)
+ return log_error_errno(errno, "Failed to stat() seed file " RANDOM_SEED ": %m");
+
+ /* 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)
+ buf_size = MIN(st.st_size, POOL_SIZE_MAX);
+
+ buf = malloc(buf_size);
+ if (!buf)
+ return log_oom();
+
+ if (read_seed_file) {
+ sd_id128_t mid;
+ int z;
+
k = loop_read(seed_fd, buf, buf_size, false);
if (k < 0)
r = log_error_errno(k, "Failed to read seed from " RANDOM_SEED ": %m");
@@ -110,28 +136,23 @@ int main(int argc, char *argv[]) {
log_error_errno(r, "Failed to write seed to /dev/urandom: %m");
}
- } else if (streq(argv[1], "save")) {
-
- seed_fd = open(RANDOM_SEED, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600);
- if (seed_fd < 0) {
- r = log_error_errno(errno, "Failed to open " RANDOM_SEED ": %m");
- goto finish;
+ /* Let's also write the machine ID into the random seed. 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. */
+ z = sd_id128_get_machine(&mid);
+ if (z < 0)
+ log_debug_errno(z, "Failed to get machine ID, ignoring: %m");
+ else {
+ z = loop_write(random_fd, &mid, sizeof(mid), false);
+ if (z < 0)
+ log_debug_errno(z, "Failed to write machine ID to /dev/urandom, ignoring: %m");
}
-
- random_fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
- if (random_fd < 0) {
- r = log_error_errno(errno, "Failed to open /dev/urandom: %m");
- goto finish;
- }
-
- } else {
- log_error("Unknown verb '%s'.", argv[1]);
- r = -EINVAL;
- goto finish;
}
- if (refresh_seed_file) {
-
+ if (write_seed_file) {
/* 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. */
@@ -139,21 +160,18 @@ int main(int argc, char *argv[]) {
(void) fchown(seed_fd, 0, 0);
k = loop_read(random_fd, buf, buf_size, false);
- if (k < 0) {
- r = log_error_errno(k, "Failed to read new seed from /dev/urandom: %m");
- goto finish;
- }
- if (k == 0) {
- log_error("Got EOF while reading from /dev/urandom.");
- r = -EIO;
- goto finish;
- }
+ 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.");
r = loop_write(seed_fd, buf, (size_t) k, false);
if (r < 0)
- log_error_errno(r, "Failed to write new random seed file: %m");
+ return log_error_errno(r, "Failed to write new random seed file: %m");
}
-finish:
- return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+ return r;
}
+
+DEFINE_MAIN_FUNCTION(run);