]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/random-seed/random-seed.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
11 #include "alloc-util.h"
16 #include "string-util.h"
19 #define POOL_SIZE_MIN 512
20 #define POOL_SIZE_MAX (10*1024*1024)
22 int main(int argc
, char *argv
[]) {
23 _cleanup_close_
int seed_fd
= -1, random_fd
= -1;
24 bool read_seed_file
, write_seed_file
;
25 _cleanup_free_
void* buf
= NULL
;
33 log_error("This program requires one argument.");
37 log_set_target(LOG_TARGET_AUTO
);
38 log_parse_environment();
43 /* Read pool size, if possible */
44 f
= fopen("/proc/sys/kernel/random/poolsize", "re");
46 if (fscanf(f
, "%zu", &buf_size
) > 0)
47 /* poolsize is in bits on 2.6, but we want bytes */
53 if (buf_size
< POOL_SIZE_MIN
)
54 buf_size
= POOL_SIZE_MIN
;
56 r
= mkdir_parents_label(RANDOM_SEED
, 0755);
58 log_error_errno(r
, "Failed to create directory " RANDOM_SEED_DIR
": %m");
62 /* When we load the seed we read it and write it to the device and then immediately update the saved seed with
63 * new data, to make sure the next boot gets seeded differently. */
65 if (streq(argv
[1], "load")) {
68 seed_fd
= open(RANDOM_SEED
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_CREAT
, 0600);
69 open_rw_error
= -errno
;
71 write_seed_file
= false;
73 seed_fd
= open(RANDOM_SEED
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
75 bool missing
= errno
== ENOENT
;
77 log_full_errno(missing
? LOG_DEBUG
: LOG_ERR
,
78 open_rw_error
, "Failed to open " RANDOM_SEED
" for writing: %m");
79 r
= log_full_errno(missing
? LOG_DEBUG
: LOG_ERR
,
80 errno
, "Failed to open " RANDOM_SEED
" for reading: %m");
87 write_seed_file
= true;
89 random_fd
= open("/dev/urandom", O_RDWR
|O_CLOEXEC
|O_NOCTTY
, 0600);
91 write_seed_file
= false;
93 random_fd
= open("/dev/urandom", O_WRONLY
|O_CLOEXEC
|O_NOCTTY
, 0600);
95 r
= log_error_errno(errno
, "Failed to open /dev/urandom: %m");
100 read_seed_file
= true;
102 } else if (streq(argv
[1], "save")) {
104 random_fd
= open("/dev/urandom", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
106 r
= log_error_errno(errno
, "Failed to open /dev/urandom: %m");
110 seed_fd
= open(RANDOM_SEED
, O_WRONLY
|O_CLOEXEC
|O_NOCTTY
|O_CREAT
, 0600);
112 r
= log_error_errno(errno
, "Failed to open " RANDOM_SEED
": %m");
116 read_seed_file
= false;
117 write_seed_file
= true;
120 log_error("Unknown verb '%s'.", argv
[1]);
125 if (fstat(seed_fd
, &st
) < 0) {
126 r
= log_error_errno(errno
, "Failed to stat() seed file " RANDOM_SEED
": %m");
130 /* If the seed file is larger than what we expect, then honour the existing size and save/restore as much as it says */
131 if ((uint64_t) st
.st_size
> buf_size
)
132 buf_size
= MIN(st
.st_size
, POOL_SIZE_MAX
);
134 buf
= malloc(buf_size
);
140 if (read_seed_file
) {
144 k
= loop_read(seed_fd
, buf
, buf_size
, false);
146 r
= log_error_errno(k
, "Failed to read seed from " RANDOM_SEED
": %m");
149 log_debug("Seed file " RANDOM_SEED
" not yet initialized, proceeding.");
151 (void) lseek(seed_fd
, 0, SEEK_SET
);
153 r
= loop_write(random_fd
, buf
, (size_t) k
, false);
155 log_error_errno(r
, "Failed to write seed to /dev/urandom: %m");
158 /* Let's also write the machine ID into the random seed. Why? As an extra protection against "golden
159 * images" that are put together sloppily, i.e. images which are duplicated on multiple systems but
160 * where the random seed file is not properly reset. Frequently the machine ID is properly reset on
161 * those systems however (simply because it's easier to notice, if it isn't due to address clashes and
162 * so on, while random seed equivalence is generally not noticed easily), hence let's simply write the
163 * machined ID into the random pool too. */
164 z
= sd_id128_get_machine(&mid
);
166 log_debug_errno(z
, "Failed to get machine ID, ignoring: %m");
168 z
= loop_write(random_fd
, &mid
, sizeof(mid
), false);
170 log_debug_errno(z
, "Failed to write machine ID to /dev/urandom, ignoring: %m");
174 if (write_seed_file
) {
176 /* This is just a safety measure. Given that we are root and
177 * most likely created the file ourselves the mode and owner
178 * should be correct anyway. */
179 (void) fchmod(seed_fd
, 0600);
180 (void) fchown(seed_fd
, 0, 0);
182 k
= loop_read(random_fd
, buf
, buf_size
, false);
184 r
= log_error_errno(k
, "Failed to read new seed from /dev/urandom: %m");
188 log_error("Got EOF while reading from /dev/urandom.");
193 r
= loop_write(seed_fd
, buf
, (size_t) k
, false);
195 log_error_errno(r
, "Failed to write new random seed file: %m");
199 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;