bless-boot: skip gracefully on kexec
If KExecsCount > 0 then do not attempt to mark a UKI, as the stub (and also
any addon and the bootloader) will not have been exercised, so there's no
guaranteed a full reboot with the same image will actually work.
Fixes https://github.com/systemd/systemd/issues/43738
(cherry picked from commit 06c2dfa73c)
This commit is contained in:
@@ -45,6 +45,9 @@
|
||||
left" numeric boot counters from the filename, which indicates to future invocations of the boot loader
|
||||
that the entry has completed booting successfully at least once. (This service will hence rename the boot
|
||||
loader entry file or unified kernel image file on the first successful boot.)</para>
|
||||
|
||||
<para>Note that if the system was booted via kexec and LUO is available and enabled, this service will
|
||||
skip marking the boot entry as good or bad, since kexec bypasses the EFI boot loader entirely.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include "sd-json.h"
|
||||
#include "sd-varlink.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "build.h"
|
||||
@@ -20,6 +21,7 @@
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "sync-util.h"
|
||||
#include "varlink-util.h"
|
||||
#include "verbs.h"
|
||||
#include "virt.h"
|
||||
|
||||
@@ -443,6 +445,8 @@ VERB_FULL(verb_set, "indeterminate", NULL, VERB_ANY, 1, 0, STATUS_INDETERMINATE,
|
||||
"Undo any marking as good or bad");
|
||||
static int verb_set(int argc, char *argv[], uintptr_t data, void *userdata) {
|
||||
_cleanup_free_ char *path = NULL, *prefix = NULL, *suffix = NULL, *good = NULL, *bad = NULL;
|
||||
_cleanup_(sd_varlink_unrefp) sd_varlink *link = NULL;
|
||||
sd_json_variant *reply = NULL;
|
||||
const char *target = NULL, *source1 = NULL, *source2 = NULL; /* avoid false maybe-uninitialized warning */
|
||||
uint64_t left, done;
|
||||
Status status = data;
|
||||
@@ -454,6 +458,35 @@ static int verb_set(int argc, char *argv[], uintptr_t data, void *userdata) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* kexec doesn't go through the EFI loaders, so we shouldn't try to mark an image as good/bad.
|
||||
* E.g.: booting the kernel+initrd might work, but the EFI stub might not, and we wouldn't notice */
|
||||
r = sd_varlink_connect_address(&link, "/run/systemd/io.systemd.Manager");
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to connect to service manager: %m");
|
||||
|
||||
r = varlink_call_and_log(link, "io.systemd.Manager.Describe", /* parameters= */ NULL, &reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
static const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "KExecCount", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint64, 0, 0 },
|
||||
{},
|
||||
};
|
||||
uint64_t kexec_count = 0;
|
||||
|
||||
r = sd_json_dispatch(
|
||||
sd_json_variant_by_key(reply, "runtime"),
|
||||
dispatch_table,
|
||||
SD_JSON_LOG|SD_JSON_ALLOW_EXTENSIONS,
|
||||
&kexec_count);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (kexec_count > 0) {
|
||||
log_info("System was booted via kexec, skipping boot entry marking.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = acquire_boot_count_path(&path, &prefix, &left, &done, &suffix);
|
||||
if (r == -EUNATCH) /* acquire_boot_count_path() won't log on its own for this specific error */
|
||||
return log_error_errno(r, "Not booted with boot counting in effect.");
|
||||
|
||||
@@ -80,6 +80,13 @@ if grep -qw luo_nboot=1 /proc/cmdline; then
|
||||
|
||||
assert_eq "$(busctl -j get-property org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager KExecCount | jq -r '.data')" "1"
|
||||
|
||||
# Check that bless-boot does not fail after a kexec
|
||||
if [[ -d /sys/firmware/efi ]]; then
|
||||
for verb in good bad indeterminate; do
|
||||
/usr/lib/systemd/systemd-bless-boot --path=/nonexistent "$verb"
|
||||
done
|
||||
fi
|
||||
|
||||
# The previous boot's shutdown timestamps were preserved across the kexec via LUO and are now exposed
|
||||
# as the PreviousShutdown* properties (the live Shutdown* ones describe this boot, which is not shutting
|
||||
# down, so they are unset here).
|
||||
|
||||
Reference in New Issue
Block a user