random-seed: when we have a reasonable RNG then create random seed file if missing

Previously we'd never write the ESP random seed file (or initialize the
random seed EFI table) if it didn't already exist. Let's adjust this a
bit, and also create it fresh if we have a "good" random source, i.e. if
the EFI table already existed or if the RNG protocol is implemented by
EFI.

This is useful as it increases the chance the random seed table is
valid, and we can use it as source for randomness in later stages.
This commit is contained in:
Lennart Poettering
2026-03-25 16:19:24 +01:00
parent 9b15ddd9cf
commit 6dc6b48ec9
+45 -25
View File
@@ -185,46 +185,66 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir) {
explicit_bzero_safe(system_token, size);
}
bool created = false;
err = root_dir->Open(
root_dir,
&handle,
(char16_t *) u"\\loader\\random-seed",
EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,
0);
if (err == EFI_NOT_FOUND && seeded_by_efi) {
/* If the file does not exist, but we are reasonably well seeded, create the seed file */
created = true;
err = root_dir->Open(
root_dir,
&handle,
(char16_t *) u"\\loader\\random-seed",
EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE,
0);
}
if (err != EFI_SUCCESS) {
if (!IN_SET(err, EFI_NOT_FOUND, EFI_WRITE_PROTECTED))
log_error_status(err, "Failed to open random seed file: %m");
return err;
}
err = get_file_info(handle, &info, NULL);
if (err != EFI_SUCCESS)
return log_error_status(err, "Failed to get file info for random seed: %m");
if (!created) {
err = get_file_info(handle, &info, /* ret_size= */ NULL);
if (err != EFI_SUCCESS)
return log_error_status(err, "Failed to get file info for random seed: %m");
size = info->FileSize;
if (size < RANDOM_MAX_SIZE_MIN)
return log_error_status(EFI_INVALID_PARAMETER, "Random seed file is too short.");
if (size > RANDOM_MAX_SIZE_MAX)
return log_error_status(EFI_INVALID_PARAMETER, "Random seed file is too large.");
seed = xmalloc(size);
rsize = size;
err = handle->Read(handle, &rsize, seed);
if (err != EFI_SUCCESS)
return log_error_status(err, "Failed to read random seed file: %m");
if (rsize != size) {
explicit_bzero_safe(seed, rsize);
return log_error_status(EFI_PROTOCOL_ERROR, "Short read on random seed file.");
/* Treat a short file just like a freshly created one for robustness reasons: consider a case
* where in a previous run a file was just created and the system was then powered off. In
* such a case the file will already exist, but be too short. */
created = info->FileSize < RANDOM_MAX_SIZE_MIN;
}
sha256_process_bytes(&size, sizeof(size), &hash);
sha256_process_bytes(seed, size, &hash);
explicit_bzero_safe(seed, size);
if (created) {
size = 0;
sha256_process_bytes(&size, sizeof(size), &hash);
} else {
size = info->FileSize;
if (size > RANDOM_MAX_SIZE_MAX)
return log_error_status(EFI_INVALID_PARAMETER, "Random seed file is too large.");
err = handle->SetPosition(handle, 0);
if (err != EFI_SUCCESS)
return log_error_status(err, "Failed to seek to beginning of random seed file: %m");
seed = xmalloc(size);
rsize = size;
err = handle->Read(handle, &rsize, seed);
if (err != EFI_SUCCESS)
return log_error_status(err, "Failed to read random seed file: %m");
if (rsize != size) {
explicit_bzero_safe(seed, rsize);
return log_error_status(EFI_PROTOCOL_ERROR, "Short read on random seed file.");
}
sha256_process_bytes(&size, sizeof(size), &hash);
sha256_process_bytes(seed, size, &hash);
explicit_bzero_safe(seed, size);
err = handle->SetPosition(handle, 0);
if (err != EFI_SUCCESS)
return log_error_status(err, "Failed to seek to beginning of random seed file: %m");
}
/* Let's also include the UEFI monotonic counter (which is supposedly increasing on every single
* boot) in the hash, so that even if the changes to the ESP for some reason should not be
@@ -253,7 +273,7 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir) {
size = sizeof(random_bytes);
/* If the file size is too large, zero out the remaining bytes on disk. */
if (size < info->FileSize) {
if (!created && size < info->FileSize) {
err = handle->SetPosition(handle, size);
if (err != EFI_SUCCESS)
return log_error_status(err, "Failed to seek to offset of random seed file: %m");