factory-reset: add systemd-efivars-clear.service

This is a small service that hooks into factory-reset.target, similar to
systemd-tpm2-clear.service, and sets the LoaderFactoryResetVariables EFI
variable, asking systemd-boot to erase its EFI variables on the next
boot. Or in other words: a factory reset now resets the TPM *and* the EFI
variables owned by systemd.

The operation can be turned off via systemd.efivars_allow_clear= on the
kernel command line or $SYSTEMD_EFIVARS_ALLOW_CLEAR. With --graceful the
tool exits cleanly if the boot loader doesn't support the request.

"systemd-factory-reset cancel" now also withdraws the request, and
"bootctl remove" removes the variable too.
This commit is contained in:
Lennart Poettering authored and Lennart Poettering committed 2026-10-29 19:53:35 +01:00
1 parent 66a760e541
commit 4d041137e9
10 files changed
+178

No files matched your search

+12
View File
@@ -867,6 +867,18 @@ Clearing the TPM has the effect of invalidating all keys locked to the TPM,
including full disk encryption keys. Because of that care should be taken that
access to relevant resources is retained via other means.
-- 7e3ed2117b184dee91b825cfdff46b6e
Subject: Erasing of boot loader EFI variables requested
Defined-By: systemd
Support: %SUPPORT_URL%
Documentation: man:systemd-efivars-clear.service(8)
A request to erase all EFI variables owned by the boot loader and by systemd
has been issued to systemd-boot. This is typically done as part of a
comprehensive factory reset operation, and ensures that on the next boot
systemd-boot will erase these variables (after interactively requesting
confirmation by the user, unless configured otherwise) and reboot.
-- 1f4e0a44a88649939aaea34fc6da8c95
Subject: Process @COREDUMP_PID@ (@COREDUMP_COMM@) terminated abnormally
Defined-By: systemd
+1
View File
@@ -10,6 +10,7 @@
# Settings for systemd units distributed with systemd itself, specific to initrds.
enable systemd-confext-sysroot.service
enable systemd-efivars-clear.service
enable systemd-journald-audit.socket
enable systemd-network-generator.service
enable systemd-networkd.service
+1
View File
@@ -23,6 +23,7 @@ enable systemd-boot-clear-sysfail.service
enable systemd-boot-update.service
enable systemd-confext.service
enable systemd-coredumpd.service
enable systemd-efivars-clear.service
enable systemd-homed.service
enable systemd-homed-activate.service
enable systemd-journalctl-metrics.socket
+1
View File
@@ -1955,6 +1955,7 @@ static int remove_loader_variables(void) {
EFI_LOADER_VARIABLE_STR("LoaderEntrySysFail"),
EFI_LOADER_VARIABLE_STR("LoaderEntryLastBooted"),
EFI_LOADER_VARIABLE_STR("LoaderEntryOneShot"),
EFI_LOADER_VARIABLE_STR("LoaderFactoryResetVariables"),
EFI_LOADER_VARIABLE_STR("LoaderSystemToken")) {
int q;
+121
View File
@@ -0,0 +1,121 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "sd-json.h"
#include "sd-messages.h"
#include "build.h"
#include "efi-loader.h"
#include "efivars.h"
#include "env-util.h"
#include "log.h"
#include "main-func.h"
#include "proc-cmdline.h"
#include "verbs.h"
static bool arg_graceful = false;
COMMAND(
"systemd-efivars-clear\0",
"Request erasing of the boot loader's EFI variables from systemd-boot.",
.man_pages = "systemd-efivars-clear.service(8)\0",
);
static int parse_argv(int argc, char *argv[]) {
assert(argc >= 0);
assert(argv);
OptionParser opts = { argc, argv };
FOREACH_OPTION_OR_RETURN(c, &opts)
switch (c) {
OPTION_COMMON_HELP:
return command_print_help();
OPTION_COMMON_VERSION:
return version();
OPTION_LONG("graceful", NULL, "Exit gracefully if the boot loader does not support erasing EFI variables"):
arg_graceful = true;
break;
OPTION_COMMON_INTROSPECT_CLI:
return introspect_cli(SD_JSON_FORMAT_OFF);
}
if (option_parser_get_n_args(&opts) != 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program expects no arguments.");
return 1;
}
static int request_efivars_clear(void) {
int r, clear = -1;
r = secure_getenv_bool("SYSTEMD_EFIVARS_ALLOW_CLEAR");
if (r < 0 && r != -ENXIO)
return log_error_errno(r, "Failed to parse $SYSTEMD_EFIVARS_ALLOW_CLEAR: %m");
if (r >= 0)
clear = r;
if (clear < 0) {
bool b;
r = proc_cmdline_get_bool("systemd.efivars_allow_clear", PROC_CMDLINE_TRUE_WHEN_MISSING, &b);
if (r < 0)
return log_error_errno(r, "Failed to parse systemd.efivars_allow_clear kernel command line argument: %m");
clear = b;
}
assert(clear >= 0);
if (!clear) {
log_info("Erasing EFI variables disabled, exiting early.");
return 0;
}
r = efi_set_variable_string(EFI_LOADER_VARIABLE_STR("LoaderFactoryResetVariables"), "1");
if (r < 0)
return log_error_errno(r, "Failed to set LoaderFactoryResetVariables EFI variable: %m");
log_struct(LOG_NOTICE,
LOG_MESSAGE_ID(SD_MESSAGE_EFIVARS_CLEAR_REQUESTED_STR),
LOG_MESSAGE("Requested erasing of boot loader EFI variables. Boot loader will verify with user and erase variables on reboot."));
return 0;
}
static int run(int argc, char *argv[]) {
uint64_t features;
int r;
log_setup();
r = parse_argv(argc, argv);
if (r <= 0)
return r;
if (!is_efi_boot()) {
if (arg_graceful) {
log_notice("Not an EFI boot, exiting gracefully.");
return 0;
}
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Not an EFI boot, cannot request erasing of EFI variables.");
}
r = efi_loader_get_features(&features);
if (r < 0)
return log_error_errno(r, "Failed to query boot loader features: %m");
if (!FLAGS_SET(features, EFI_LOADER_FEATURE_FACTORY_RESET_VARIABLES)) {
if (arg_graceful) {
log_notice("Boot loader does not support erasing EFI variables, exiting gracefully.");
return 0;
}
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Boot loader does not support erasing EFI variables.");
}
return request_efivars_clear();
}
DEFINE_MAIN_FUNCTION(run);
+6
View File
@@ -180,6 +180,12 @@ static int verb_cancel(int argc, char *argv[], uintptr_t _data, void *userdata)
if (r < 0)
return log_error_errno(r, "Failed to remove FactoryResetRequest EFI variable: %m");
/* Also withdraw the request to the boot loader to erase its EFI variables, if there is one (see
* systemd-efivars-clear.service). */
r = efi_set_variable(EFI_LOADER_VARIABLE_STR("LoaderFactoryResetVariables"), /* value= */ NULL, /* size= */ 0);
if (r < 0 && r != -ENOENT)
return log_error_errno(r, "Failed to remove LoaderFactoryResetVariables EFI variable: %m");
if (!arg_quiet)
log_info("Factory reset cancelled.");
+5
View File
@@ -5,6 +5,11 @@ executables += [
'name' : 'systemd-factory-reset',
'sources' : files('factory-reset-tool.c'),
},
libexec_template + {
'name' : 'systemd-efivars-clear',
'sources' : files('efivars-clear.c'),
'conditions' : ['ENABLE_BOOTLOADER'],
},
generator_template + {
'name' : 'systemd-factory-reset-generator',
'sources' : files('factory-reset-generator.c'),
+2
View File
@@ -294,6 +294,8 @@ _SD_BEGIN_DECLARATIONS;
#define SD_MESSAGE_EK_ENROLLMENT_NEEDS_AUTHORIZATION_STR SD_ID128_MAKE_STR(8d,81,3b,6b,ec,f0,4b,85,9d,99,76,0c,bb,56,df,f1)
#define SD_MESSAGE_TPM2_CLEAR_REQUESTED SD_ID128_MAKE(43,81,88,86,1e,0b,42,7a,9d,63,8a,90,48,7a,0c,a6)
#define SD_MESSAGE_TPM2_CLEAR_REQUESTED_STR SD_ID128_MAKE_STR(43,81,88,86,1e,0b,42,7a,9d,63,8a,90,48,7a,0c,a6)
#define SD_MESSAGE_EFIVARS_CLEAR_REQUESTED SD_ID128_MAKE(7e,3e,d2,11,7b,18,4d,ee,91,b8,25,cf,df,f4,6b,6e)
#define SD_MESSAGE_EFIVARS_CLEAR_REQUESTED_STR SD_ID128_MAKE_STR(7e,3e,d2,11,7b,18,4d,ee,91,b8,25,cf,df,f4,6b,6e)
#define SD_MESSAGE_SYSCTL_CHANGED SD_ID128_MAKE(9c,f5,6b,8b,af,95,46,cf,94,78,78,3a,8d,e4,21,13)
#define SD_MESSAGE_SYSCTL_CHANGED_STR SD_ID128_MAKE_STR(9c,f5,6b,8b,af,95,46,cf,94,78,78,3a,8d,e4,21,13)
+4
View File
@@ -376,6 +376,10 @@ units = [
'conditions' : ['HAVE_LIBCRYPTSETUP', 'ENABLE_INITRD'],
'symlinks' : ['initrd.target.wants/'],
},
{
'file' : 'systemd-efivars-clear.service.in',
'conditions' : ['ENABLE_BOOTLOADER'],
},
{ 'file' : 'systemd-exit.service' },
{ 'file' : 'systemd-factory-reset@.service.in' },
{
+25
View File
@@ -0,0 +1,25 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Issue Boot Loader EFI Variable Erase Request
Documentation=man:systemd-efivars-clear.service(8)
DefaultDependencies=no
Conflicts=shutdown.target
After=systemd-pcrphase-factory-reset.service
Before=factory-reset.target shutdown.target
ConditionFirmware=uefi
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart={{LIBEXECDIR}}/systemd-efivars-clear --graceful
[Install]
WantedBy=factory-reset.target