]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #25319 from zx2c4-forks/krngseed
authorLuca Boccassi <bluca@debian.org>
Wed, 16 Nov 2022 14:07:54 +0000 (15:07 +0100)
committerGitHub <noreply@github.com>
Wed, 16 Nov 2022 14:07:54 +0000 (15:07 +0100)
boot: implement kernel EFI RNG seed protocol with proper hashing

1  2 
man/systemd-boot.xml
src/boot/bootctl.c

diff --combined man/systemd-boot.xml
index 57b66803fadf37ed1409fb86b155cdbfdf356779,081deb8d6c20902f8c7050c668929974d6d24444..f96c4c6512464d4f612a9c590b250f4d26f6fcf4
          to view this data. </para></listitem>
        </varlistentry>
  
-       <varlistentry>
-         <term><varname>LoaderRandomSeed</varname></term>
-         <listitem><para>A binary random seed <command>systemd-boot</command> may optionally pass to the
-         OS. This is a volatile EFI variable that is hashed at boot from the combination of a random seed
-         stored in the ESP (in <filename>/loader/random-seed</filename>) and a "system token" persistently
-         stored in the EFI variable <varname>LoaderSystemToken</varname> (see below). During early OS boot the
-         system manager reads this variable and passes it to the OS kernel's random pool, crediting the full
-         entropy it contains. This is an efficient way to ensure the system starts up with a fully initialized
-         kernel random pool — as early as the initrd phase. <command>systemd-boot</command> reads
-         the random seed from the ESP, combines it with the "system token", and both derives a new random seed
-         to update in-place the seed stored in the ESP, and the random seed to pass to the OS from it via
-         SHA256 hashing in counter mode. This ensures that different physical systems that boot the same
-         "golden" OS image — i.e. containing the same random seed file in the ESP — will still pass a
-         different random seed to the OS. It is made sure the random seed stored in the ESP is fully
-         overwritten before the OS is booted, to ensure different random seed data is used between subsequent
-         boots.</para>
-         <para>See <ulink url="https://systemd.io/RANDOM_SEEDS">Random Seeds</ulink> for
-         further information.</para></listitem>
-       </varlistentry>
        <varlistentry>
          <term><varname>LoaderSystemToken</varname></term>
  
      <filename>/etc/kernel/tries</filename> when a boot loader entry is first created.</para>
    </refsect1>
  
 +  <refsect1>
 +    <title>Using systemd-boot in virtual machines.</title>
 +
 +    <para>When using qemu with OVMF (UEFI Firmware for virtual machines) the <option>-kernel</option> switch
 +    works not only for linux kernels, but for any EFI binary, including sd-boot and unified linux
 +    kernels.  Example command line for loading sd-boot on x64:</para>
 +
 +    <para>
 +      <command>qemu-system-x86_64 <replaceable>[ ... ]</replaceable>
 +      -kernel /usr/lib/systemd/boot/efi/systemd-bootx64.efi</command>
 +    </para>
 +
 +    <para>systemd-boot will detect that it was started directly instead of being loaded from ESP and will
 +    search for the ESP in that case, taking into account boot order information from the hypervisor (if
 +    available).</para>
 +  </refsect1>
 +
    <refsect1>
      <title>See Also</title>
      <para>
diff --combined src/boot/bootctl.c
index 430887fe676e0e9ac8766417716a4a2990526014,984b7e3a6d4d1db1382aecdad6a083fb5832729b..e04424b379389433329a34943fed00c6d1e0370b
@@@ -586,11 -586,11 +586,11 @@@ static int print_efi_option(uint16_t id
  
          r = efi_get_boot_option(id, &title, &partition, &path, &active);
          if (r < 0)
 -                return log_error_errno(r, "Failed to read boot option %u: %m", id);
 +                return log_debug_errno(r, "Failed to read boot option 0x%04X: %m", id);
  
          /* print only configured entries with partition information */
          if (!path || sd_id128_is_null(partition)) {
 -                log_debug("Ignoring boot entry %u without partition information.", id);
 +                log_debug("Ignoring boot entry 0x%04X without partition information.", id);
                  return 0;
          }
  
@@@ -1886,8 -1886,6 +1886,6 @@@ static int verb_status(int argc, char *
                  printf("\n");
  
                  printf("%sRandom Seed:%s\n", ansi_underline(), ansi_normal());
-                 have = access(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderRandomSeed)), F_OK) >= 0;
-                 printf(" Passed to OS: %s\n", yes_no(have));
                  have = access(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderSystemToken)), F_OK) >= 0;
                  printf(" System Token: %s\n", have ? "set" : "not set");
  
@@@ -1977,10 -1975,10 +1975,10 @@@ static int verb_list(int argc, char *ar
  
  static int install_random_seed(const char *esp) {
          _cleanup_(unlink_and_freep) char *tmp = NULL;
-         _cleanup_free_ void *buffer = NULL;
+         unsigned char buffer[RANDOM_EFI_SEED_SIZE];
          _cleanup_free_ char *path = NULL;
          _cleanup_close_ int fd = -1;
-         size_t sz, token_size;
+         size_t token_size;
          ssize_t n;
          int r;
  
          if (!path)
                  return log_oom();
  
-         sz = random_pool_size();
-         buffer = malloc(sz);
-         if (!buffer)
-                 return log_oom();
-         r = crypto_random_bytes(buffer, sz);
+         r = crypto_random_bytes(buffer, sizeof(buffer));
          if (r < 0)
                  return log_error_errno(r, "Failed to acquire random seed: %m");
  
                  return log_error_errno(fd, "Failed to open random seed file for writing: %m");
          }
  
-         n = write(fd, buffer, sz);
+         n = write(fd, buffer, sizeof(buffer));
          if (n < 0)
                  return log_error_errno(errno, "Failed to write random seed file: %m");
-         if ((size_t) n != sz)
+         if ((size_t) n != sizeof(buffer))
                  return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short write while writing random seed file.");
  
          if (rename(tmp, path) < 0)
  
          tmp = mfree(tmp);
  
-         log_info("Random seed file %s successfully written (%zu bytes).", path, sz);
+         log_info("Random seed file %s successfully written (%zu bytes).", path, sizeof(buffer));
  
          if (!arg_touch_variables)
                  return 0;
                  if (r != -ENOENT)
                          return log_error_errno(r, "Failed to test system token validity: %m");
          } else {
-                 if (token_size >= sz) {
+                 if (token_size >= sizeof(buffer)) {
                          /* Let's avoid writes if we can, and initialize this only once. */
                          log_debug("System token already written, not updating.");
                          return 0;
                  }
  
-                 log_debug("Existing system token size (%zu) does not match our expectations (%zu), replacing.", token_size, sz);
+                 log_debug("Existing system token size (%zu) does not match our expectations (%zu), replacing.", token_size, sizeof(buffer));
          }
  
-         r = crypto_random_bytes(buffer, sz);
+         r = crypto_random_bytes(buffer, sizeof(buffer));
          if (r < 0)
                  return log_error_errno(r, "Failed to acquire random seed: %m");
  
           * and possibly get identification information or too much insight into the kernel's entropy pool
           * state. */
          RUN_WITH_UMASK(0077) {
-                 r = efi_set_variable(EFI_LOADER_VARIABLE(LoaderSystemToken), buffer, sz);
+                 r = efi_set_variable(EFI_LOADER_VARIABLE(LoaderSystemToken), buffer, sizeof(buffer));
                  if (r < 0) {
                          if (!arg_graceful)
                                  return log_error_errno(r, "Failed to write 'LoaderSystemToken' EFI variable: %m");
                          else
                                  log_warning_errno(r, "Unable to write 'LoaderSystemToken' EFI variable, ignoring: %m");
                  } else
-                         log_info("Successfully initialized system token in EFI variable with %zu bytes.", sz);
+                         log_info("Successfully initialized system token in EFI variable with %zu bytes.", sizeof(buffer));
          }
  
          return 0;