]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
boot: add an option to control action after SecureBoot enrollment (#36684)
authorItxaka <itxaka@kairos.io>
Thu, 8 May 2025 04:28:41 +0000 (06:28 +0200)
committerGitHub <noreply@github.com>
Thu, 8 May 2025 04:28:41 +0000 (13:28 +0900)
This PR provides a new option for systemd-boot
`secure-boot-enroll-action` which allows to configure the behavior after
SecureBoot keys are enrolled.

Provides the option to either reboot or power off.

The current behavior is not changed, it will by default reboot as it did
before.

It also provides a small message about the action its going to take with
a small delay so the user can read it.

man/loader.conf.xml
src/boot/boot.c
src/boot/secure-boot.c
src/boot/secure-boot.h
tools/command_ignorelist

index 22deb8568b718ae7edc18fb5c63a03d60ac0485e..f14b77b5371264ad376000b005bbbaa904ecb8e8 100644 (file)
@@ -373,6 +373,29 @@ sbvarsign --attr "${attr}" --key KEK.key --cert KEK.pem --output db.auth db db.e
         <xi:include href="version-info.xml" xpointer="v252"/></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term>secure-boot-enroll-action</term>
+        <listitem>
+          <para>Specifies the action to take after the automatic enrollment of secure boot keys is completed.</para>
+          <variablelist>
+            <varlistentry>
+              <term>reboot</term>
+              <listitem>
+                <para>Reboot the system after enrollment. This is the default.</para>
+              </listitem>
+            </varlistentry>
+            <varlistentry>
+              <term>shutdown</term>
+              <listitem>
+                <para>Shut down the system after enrollment.</para>
+              </listitem>
+            </varlistentry>
+          </variablelist>
+          <para>This option is only relevant if <literal>secure-boot-enroll</literal> is enabled.</para>
+          <xi:include href="version-info.xml" xpointer="v258"/>
+        </listitem>
+      </varlistentry>
+
       <varlistentry>
         <term>reboot-for-bitlocker</term>
 
index c7f354506c243577da9df2463aa8d9cf357cdc2f..830ba5b4584e55c079f59a273cd4ea2b9662b77f 100644 (file)
@@ -141,6 +141,7 @@ typedef struct {
         bool reboot_for_bitlocker;
         RebootOnError reboot_on_error;
         secure_boot_enroll secure_boot_enroll;
+        secure_boot_enroll_action secure_boot_enroll_action;
         bool force_menu;
         bool use_saved_entry;
         bool use_saved_entry_efivar;
@@ -325,34 +326,35 @@ static void print_status(Config *config, char16_t *loaded_image_path) {
         if (config->entry_oneshot)
                 printf("    default (one-shot): %ls\n", config->entry_oneshot);
         if (config->entry_saved)
-                printf("           saved entry: %ls\n", config->entry_saved);
-        printf("                editor: %ls\n", yes_no(config->editor));
-        printf("          auto-entries: %ls\n", yes_no(config->auto_entries));
-        printf("         auto-firmware: %ls\n", yes_no(config->auto_firmware));
-        printf("         auto-poweroff: %ls\n", yes_no(config->auto_poweroff));
-        printf("           auto-reboot: %ls\n", yes_no(config->auto_reboot));
-        printf("                  beep: %ls\n", yes_no(config->beep));
-        printf("  reboot-for-bitlocker: %ls\n", yes_no(config->reboot_for_bitlocker));
-        printf("       reboot-on-error: %s\n",  reboot_on_error_to_string(config->reboot_on_error));
-        printf("    secure-boot-enroll: %s\n",  secure_boot_enroll_to_string(config->secure_boot_enroll));
+                printf("             saved entry: %ls\n", config->entry_saved);
+        printf("                   editor: %ls\n", yes_no(config->editor));
+        printf("             auto-entries: %ls\n", yes_no(config->auto_entries));
+        printf("            auto-firmware: %ls\n", yes_no(config->auto_firmware));
+        printf("            auto-poweroff: %ls\n", yes_no(config->auto_poweroff));
+        printf("              auto-reboot: %ls\n", yes_no(config->auto_reboot));
+        printf("                     beep: %ls\n", yes_no(config->beep));
+        printf("     reboot-for-bitlocker: %ls\n", yes_no(config->reboot_for_bitlocker));
+        printf("          reboot-on-error: %s\n",  reboot_on_error_to_string(config->reboot_on_error));
+        printf("       secure-boot-enroll: %s\n",  secure_boot_enroll_to_string(config->secure_boot_enroll));
+        printf("secure-boot-enroll-action: %s\n",  secure_boot_enroll_action_to_string(config->secure_boot_enroll_action));
 
         switch (config->console_mode) {
         case CONSOLE_MODE_AUTO:
-                printf(" console-mode (config): auto\n");
+                printf("    console-mode (config): auto\n");
                 break;
         case CONSOLE_MODE_KEEP:
-                printf(" console-mode (config): keep\n");
+                printf("    console-mode (config): keep\n");
                 break;
         case CONSOLE_MODE_FIRMWARE_MAX:
-                printf(" console-mode (config): max\n");
+                printf("    console-mode (config): max\n");
                 break;
         default:
-                printf(" console-mode (config): %" PRIi64 "\n", config->console_mode);
+                printf("    console-mode (config): %" PRIi64 "\n", config->console_mode);
         }
 
         /* EFI var console mode is always a concrete value or unset. */
         if (config->console_mode_efivar != CONSOLE_MODE_KEEP)
-                printf("console-mode (EFI var): %" PRIi64 "\n", config->console_mode_efivar);
+                printf("   console-mode (EFI var): %" PRIi64 "\n", config->console_mode_efivar);
 
         if (!ps_continue())
                 return;
@@ -1080,7 +1082,14 @@ static void config_defaults_load_from_file(Config *config, char *content) {
                         else
                                 log_error("Error parsing 'secure-boot-enroll' config option, ignoring: %s",
                                           value);
-
+                } else if (streq8(key, "secure-boot-enroll-action")) {
+                        if (streq8(value, "reboot"))
+                                config->secure_boot_enroll_action = ENROLL_ACTION_REBOOT;
+                        else if (streq8(value, "shutdown"))
+                                config->secure_boot_enroll_action = ENROLL_ACTION_SHUTDOWN;
+                        else
+                                log_error("Error parsing 'secure-boot-enroll-action' config option, ignoring: %s",
+                                          value);
                 } else if (streq8(key, "console-mode")) {
                         if (streq8(value, "auto"))
                                 config->console_mode = CONSOLE_MODE_AUTO;
@@ -1436,6 +1445,7 @@ static void config_load_defaults(Config *config, EFI_FILE *root_dir) {
                 .auto_firmware = true,
                 .reboot_on_error = REBOOT_AUTO,
                 .secure_boot_enroll = ENROLL_IF_SAFE,
+                .secure_boot_enroll_action = ENROLL_ACTION_REBOOT,
                 .idx_default_efivar = IDX_INVALID,
                 .console_mode = CONSOLE_MODE_KEEP,
                 .console_mode_efivar = CONSOLE_MODE_KEEP,
@@ -2723,7 +2733,7 @@ static void save_selected_entry(const Config *config, const BootEntry *entry) {
 static EFI_STATUS call_secure_boot_enroll(const BootEntry *entry, EFI_FILE *root_dir, EFI_HANDLE parent_image) {
         assert(entry);
 
-        return secure_boot_enroll_at(root_dir, entry->path, /* force= */ true);
+        return secure_boot_enroll_at(root_dir, entry->path, /* force= */ true, /* action= */ ENROLL_ACTION_REBOOT);
 }
 
 static EFI_STATUS secure_boot_discover_keys(Config *config, EFI_FILE *root_dir) {
@@ -2774,7 +2784,7 @@ static EFI_STATUS secure_boot_discover_keys(Config *config, EFI_FILE *root_dir)
                     strcaseeq16(dirent->FileName, u"auto"))
                         /* If we auto enroll successfully this call does not return.
                          * If it fails we still want to add other potential entries to the menu. */
-                        secure_boot_enroll_at(root_dir, entry->path, config->secure_boot_enroll == ENROLL_FORCE);
+                        secure_boot_enroll_at(root_dir, entry->path, config->secure_boot_enroll == ENROLL_FORCE, config->secure_boot_enroll_action);
         }
 
         return EFI_SUCCESS;
index b6948586e52bdc85ef9e2fffb8bccca54d74d3fb..f44a6f149b0267dfec4e97abbddb6fcbe8b9fe71 100644 (file)
@@ -69,7 +69,7 @@ static EFI_STATUS set_custom_mode(bool enable) {
                                attr, sizeof(mode), &mode);
 }
 
-EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path, bool force) {
+EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path, bool force, secure_boot_enroll_action action) {
         assert(root_dir);
         assert(path);
 
@@ -185,11 +185,21 @@ EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path, bool
                 }
         }
 
-        printf("Custom Secure Boot keys successfully enrolled, rebooting the system now!\n");
         /* The system should be in secure boot mode now and we could continue a regular boot. But at least
-         * TPM PCR7 measurements should change on next boot. Reboot now so that any OS we load does not end
-         * up relying on the old PCR state. */
-        RT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
+         * TPM PCR7 measurements should change on next boot. Reboot/poweroff now so that any OS we load
+         * does not end up relying on the old PCR state.
+         */
+
+        if (action == ENROLL_ACTION_SHUTDOWN) {
+                printf("Custom Secure Boot keys successfully enrolled, powering off the system now!\n");
+                console_key_read(/* ret_key= */ NULL, /* timeout_usec= */ 2 * 1000 * 1000); /* wait a bit so user can see the message */
+                RT->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL);
+        } else {
+                assert(action == ENROLL_ACTION_REBOOT);
+                printf("Custom Secure Boot keys successfully enrolled, rebooting the system now!\n");
+                console_key_read(/* ret_key= */ NULL, /* timeout_usec= */ 2 * 1000 * 1000); /* wait a bit so user can see the message */
+                RT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
+        }
         assert_not_reached();
 
 out_deallocate:
@@ -295,4 +305,10 @@ static const char *secure_boot_enroll_table[_SECURE_BOOT_ENROLL_MAX] = {
         [ENROLL_FORCE]   = "force"
 };
 
+static const char *secure_boot_enroll_action_table[_SECURE_BOOT_ENROLL_ACTION_MAX] = {
+        [ENROLL_ACTION_REBOOT]   = "reboot",
+        [ENROLL_ACTION_SHUTDOWN] = "shutdown"
+};
+
 DEFINE_STRING_TABLE_LOOKUP_TO_STRING(secure_boot_enroll, secure_boot_enroll);
+DEFINE_STRING_TABLE_LOOKUP_TO_STRING(secure_boot_enroll_action, secure_boot_enroll_action);
index 5349fc039e6a1eb5b76d7b3309ee65f23e32591c..da5eccb6157bc9c05e823dd2e4b5ae25f11abd93 100644 (file)
@@ -12,10 +12,16 @@ typedef enum {
         _SECURE_BOOT_ENROLL_MAX,
 } secure_boot_enroll;
 
+typedef enum {
+        ENROLL_ACTION_REBOOT,   /* Reboot the system after enrollment */
+        ENROLL_ACTION_SHUTDOWN, /* Shutdown the system after enrollment */
+        _SECURE_BOOT_ENROLL_ACTION_MAX,
+} secure_boot_enroll_action;
+
 bool secure_boot_enabled(void);
 SecureBootMode secure_boot_mode(void);
 
-EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path, bool force);
+EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path, bool force, secure_boot_enroll_action action);
 
 typedef bool (*security_validator_t)(
                 const void *ctx,
@@ -27,3 +33,4 @@ void install_security_override(security_validator_t validator, const void *valid
 void uninstall_security_override(void);
 
 const char* secure_boot_enroll_to_string(secure_boot_enroll e) _const_;
+const char* secure_boot_enroll_action_to_string(secure_boot_enroll_action e) _const_;
index fed0bf052dcf4997daf4f35f04b62ade13a1a4bf..9408d5a5f95cf4b7ee63b8cd518c12a2485d60ef 100644 (file)
@@ -579,3 +579,5 @@ run0.xml ./refsect1[title="Options"]/variablelist/varlistentry[term="--pty"]
 loader.conf.xml ./refsect1[title="Options"]/variablelist/varlistentry[term="reboot-on-error"]/listitem/para/variablelist/varlistentry[term="yes"]
 loader.conf.xml ./refsect1[title="Options"]/variablelist/varlistentry[term="reboot-on-error"]/listitem/para/variablelist/varlistentry[term="no"]
 loader.conf.xml ./refsect1[title="Options"]/variablelist/varlistentry[term="reboot-on-error"]/listitem/para/variablelist/varlistentry[term="auto"]
+loader.conf.xml ./refsect1[title="Options"]/variablelist/varlistentry[term="secure-boot-enroll-action"]/listitem/variablelist/varlistentry[term="reboot"]
+loader.conf.xml ./refsect1[title="Options"]/variablelist/varlistentry[term="secure-boot-enroll-action"]/listitem/variablelist/varlistentry[term="shutdown"]