]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
random-seed: when we have a reasonable RNG then create random seed file if missing
authorLennart Poettering <lennart@amutable.com>
Sat, 7 Mar 2026 21:11:44 +0000 (22:11 +0100)
committerLennart Poettering <lennart@amutable.com>
Wed, 25 Mar 2026 15:19:24 +0000 (16:19 +0100)
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.

src/boot/random-seed.c

index 8ef7ee7e52ed06192725c7dfa603afe8597fcea8..a31215c3b0262c3e54e8cb02bfc8e3448acdef8a 100644 (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.");
+                /* 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;
+        }
 
-        if (size > RANDOM_MAX_SIZE_MAX)
-                return log_error_status(EFI_INVALID_PARAMETER, "Random seed file is too large.");
+        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.");
 
-        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.");
-        }
+                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);
+                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");
+                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");