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
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
|
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
|
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>
|
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>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "sd-json.h"
|
#include "sd-json.h"
|
||||||
|
#include "sd-varlink.h"
|
||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "build.h"
|
#include "build.h"
|
||||||
@@ -20,6 +21,7 @@
|
|||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
#include "sync-util.h"
|
#include "sync-util.h"
|
||||||
|
#include "varlink-util.h"
|
||||||
#include "verbs.h"
|
#include "verbs.h"
|
||||||
#include "virt.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");
|
"Undo any marking as good or bad");
|
||||||
static int verb_set(int argc, char *argv[], uintptr_t data, void *userdata) {
|
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_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 */
|
const char *target = NULL, *source1 = NULL, *source2 = NULL; /* avoid false maybe-uninitialized warning */
|
||||||
uint64_t left, done;
|
uint64_t left, done;
|
||||||
Status status = data;
|
Status status = data;
|
||||||
@@ -454,6 +458,35 @@ static int verb_set(int argc, char *argv[], uintptr_t data, void *userdata) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
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);
|
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 */
|
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.");
|
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"
|
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
|
# 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
|
# as the PreviousShutdown* properties (the live Shutdown* ones describe this boot, which is not shutting
|
||||||
# down, so they are unset here).
|
# down, so they are unset here).
|
||||||
|
|||||||
Reference in New Issue
Block a user