mirror of
https://github.com/systemd/systemd.git
synced 2026-11-06 05:17:24 +00:00
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:
1 parent
66a760e541
commit
4d041137e9
10 files changed
+178
No files matched your search
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
@@ -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,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'),
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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' },
|
||||
{
|
||||
|
||||
@@ -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
|
||||
Reference in new issue
Block a user