From: Lennart Poettering Date: Fri, 7 Feb 2025 22:30:13 +0000 (+0100) Subject: sd-stub: if we are http booted, query source URL and write to EFI variable X-Git-Tag: v258-rc1~1280^2~22 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e15d18b4c64e13c37a4c676bf61a5ecf8bba04a3;p=thirdparty%2Fsystemd.git sd-stub: if we are http booted, query source URL and write to EFI variable This way userspace can read the field, and use it to retrieve more resources from the same place. --- diff --git a/docs/BOOT_LOADER_INTERFACE.md b/docs/BOOT_LOADER_INTERFACE.md index 4bf074df5e5..e264c2cc3c1 100644 --- a/docs/BOOT_LOADER_INTERFACE.md +++ b/docs/BOOT_LOADER_INTERFACE.md @@ -97,6 +97,9 @@ variables. All EFI variables use the vendor UUID generally only written once, by the OS installer, and is usually not touched after that. +* The EFI variable `LoaderDeviceURL` contains the URL the boot loader was + downloaded from, in UTF-16 format. Only set in case of network boots. + If `LoaderTimeInitUSec` and `LoaderTimeExecUSec` are set, `systemd-analyze` will include them in its boot-time analysis. If `LoaderDevicePartUUID` is set, systemd will mount the ESP that was used for the boot to `/boot`, but only if diff --git a/man/systemd-boot.xml b/man/systemd-boot.xml index 18b0708035d..22f3cdb4cae 100644 --- a/man/systemd-boot.xml +++ b/man/systemd-boot.xml @@ -440,6 +440,16 @@ + + LoaderDeviceURL + + If the boot loader has been invoked via network booting this variable contains the + originating URL. This may be used to automatically acquire additional resources from the same + source. + + + + LoaderEntries diff --git a/man/systemd-stub.xml b/man/systemd-stub.xml index 730d27cf6c3..273513c14bd 100644 --- a/man/systemd-stub.xml +++ b/man/systemd-stub.xml @@ -550,6 +550,16 @@ + + StubDeviceURL + + If the kernel image has been invoked via network booting this variable contains the + originating URL. This may be used to automatically acquire additional resources from the same + source. + + + + StubInfo diff --git a/src/boot/boot.c b/src/boot/boot.c index 53bd22c42d4..7c91e5d3896 100644 --- a/src/boot/boot.c +++ b/src/boot/boot.c @@ -2764,6 +2764,7 @@ static void export_loader_variables( EFI_LOADER_FEATURE_RETAIN_SHIM | EFI_LOADER_FEATURE_MENU_DISABLE | EFI_LOADER_FEATURE_MULTI_PROFILE_UKI | + EFI_LOADER_FEATURE_REPORT_URL | 0; assert(loaded_image); diff --git a/src/boot/export-vars.c b/src/boot/export-vars.c index 12fbd10b054..fb281ad394c 100644 --- a/src/boot/export-vars.c +++ b/src/boot/export-vars.c @@ -4,17 +4,25 @@ #include "efivars.h" #include "export-vars.h" #include "part-discovery.h" +#include "url-discovery.h" #include "util.h" void export_common_variables(EFI_LOADED_IMAGE_PROTOCOL *loaded_image) { assert(loaded_image); /* Export the device path this image is started from, if it's not set yet */ - if (loaded_image->DeviceHandle && - efivar_get_raw(MAKE_GUID_PTR(LOADER), u"LoaderDevicePartUUID", NULL, NULL) != EFI_SUCCESS) { - _cleanup_free_ char16_t *uuid = disk_get_part_uuid(loaded_image->DeviceHandle); - if (uuid) - efivar_set_str16(MAKE_GUID_PTR(LOADER), u"LoaderDevicePartUUID", uuid, 0); + if (loaded_image->DeviceHandle) { + if (efivar_get_raw(MAKE_GUID_PTR(LOADER), u"LoaderDevicePartUUID", /* ret_data= */ NULL, /* ret_size= */ NULL) != EFI_SUCCESS) { + _cleanup_free_ char16_t *uuid = disk_get_part_uuid(loaded_image->DeviceHandle); + if (uuid) + efivar_set_str16(MAKE_GUID_PTR(LOADER), u"LoaderDevicePartUUID", uuid, 0); + } + + if (efivar_get_raw(MAKE_GUID_PTR(LOADER), u"LoaderDeviceURL", /* ret_data= */ NULL, /* ret_size= */ NULL) != EFI_SUCCESS) { + _cleanup_free_ char16_t *url = disk_get_url(loaded_image->DeviceHandle); + if (url) + efivar_set_str16(MAKE_GUID_PTR(LOADER), u"LoaderDeviceURL", url, 0); + } } /* If LoaderImageIdentifier is not set, assume the image with this stub was loaded directly from the diff --git a/src/boot/meson.build b/src/boot/meson.build index 3af5006d598..69c8e40ad3a 100644 --- a/src/boot/meson.build +++ b/src/boot/meson.build @@ -300,6 +300,7 @@ libefi_sources = files( 'shim.c', 'smbios.c', 'ticks.c', + 'url-discovery.c', 'util.c', 'vmm.c', ) diff --git a/src/boot/proto/device-path.h b/src/boot/proto/device-path.h index 0fabae1125c..a394b0aa6d2 100644 --- a/src/boot/proto/device-path.h +++ b/src/boot/proto/device-path.h @@ -30,6 +30,8 @@ enum { MEDIA_FILEPATH_DP = 0x04, MEDIA_PIWG_FW_FILE_DP = 0x06, MEDIA_PIWG_FW_VOL_DP = 0x07, + + MSG_URI_DP = 24, }; struct _packed_ EFI_DEVICE_PATH_PROTOCOL { @@ -67,6 +69,11 @@ typedef struct { char16_t PathName[]; } _packed_ FILEPATH_DEVICE_PATH; +typedef struct { + EFI_DEVICE_PATH Header; + char Uri[]; +} _packed_ URI_DEVICE_PATH; + typedef struct { char16_t* (EFIAPI *ConvertDeviceNodeToText)( const EFI_DEVICE_PATH *DeviceNode, diff --git a/src/boot/stub.c b/src/boot/stub.c index e74b7db95ad..3b3a5f6a428 100644 --- a/src/boot/stub.c +++ b/src/boot/stub.c @@ -21,6 +21,7 @@ #include "splash.h" #include "tpm2-pcr.h" #include "uki.h" +#include "url-discovery.h" #include "util.h" #include "version.h" #include "vmm.h" @@ -151,6 +152,7 @@ static void export_stub_variables(EFI_LOADED_IMAGE_PROTOCOL *loaded_image, unsig EFI_STUB_FEATURE_DEVICETREE_ADDONS | /* We pick up .dtb addons */ EFI_STUB_FEATURE_MULTI_PROFILE_UKI | /* We grok the "@1" profile command line argument */ EFI_STUB_FEATURE_REPORT_STUB_PARTITION | /* We set StubDevicePartUUID + StubImageIdentifier */ + EFI_STUB_FEATURE_REPORT_URL | /* We set StubDeviceURL + LoaderDeviceURL */ 0; assert(loaded_image); @@ -167,6 +169,10 @@ static void export_stub_variables(EFI_LOADED_IMAGE_PROTOCOL *loaded_image, unsig _cleanup_free_ char16_t *uuid = disk_get_part_uuid(loaded_image->DeviceHandle); if (uuid) efivar_set_str16(MAKE_GUID_PTR(LOADER), u"StubDevicePartUUID", uuid, 0); + + _cleanup_free_ char16_t *url = disk_get_url(loaded_image->DeviceHandle); + if (url) + efivar_set_str16(MAKE_GUID_PTR(LOADER), u"StubDeviceURL", url, 0); } if (loaded_image->FilePath) { diff --git a/src/boot/url-discovery.c b/src/boot/url-discovery.c new file mode 100644 index 00000000000..7c7cfb6a624 --- /dev/null +++ b/src/boot/url-discovery.c @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "device-path-util.h" +#include "efi-string.h" +#include "proto/device-path.h" +#include "url-discovery.h" + +char16_t *disk_get_url(EFI_HANDLE *handle) { + EFI_STATUS err; + EFI_DEVICE_PATH *dp; + + /* export the device path this image is started from */ + + if (!handle) + return NULL; + + err = BS->HandleProtocol(handle, MAKE_GUID_PTR(EFI_DEVICE_PATH_PROTOCOL), (void **) &dp); + if (err != EFI_SUCCESS) + return NULL; + + for (; !device_path_is_end(dp); dp = device_path_next_node(dp)) { + if (dp->Type != MESSAGING_DEVICE_PATH || dp->SubType != MSG_URI_DP) + continue; + + URI_DEVICE_PATH *udp = (URI_DEVICE_PATH*) dp; + return xstrn8_to_16(udp->Uri, dp->Length); + } + + return NULL; +} diff --git a/src/boot/url-discovery.h b/src/boot/url-discovery.h new file mode 100644 index 00000000000..e4e50c387ca --- /dev/null +++ b/src/boot/url-discovery.h @@ -0,0 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +char16_t *disk_get_url(EFI_HANDLE *handle); diff --git a/src/bootctl/bootctl-status.c b/src/bootctl/bootctl-status.c index e9f3a6f5b51..03ebea38dfd 100644 --- a/src/bootctl/bootctl-status.c +++ b/src/bootctl/bootctl-status.c @@ -390,12 +390,15 @@ int verb_status(int argc, char *argv[], void *userdata) { { EFI_LOADER_FEATURE_RETAIN_SHIM, "Retain SHIM protocols" }, { EFI_LOADER_FEATURE_MENU_DISABLE, "Menu can be disabled" }, { EFI_LOADER_FEATURE_MULTI_PROFILE_UKI, "Multi-Profile UKIs are supported" }, + { EFI_LOADER_FEATURE_REPORT_URL, "Loader reports network boot URL" }, }; static const struct { uint64_t flag; const char *name; } stub_flags[] = { - { EFI_STUB_FEATURE_REPORT_BOOT_PARTITION, "Stub sets loader partition information" }, + { EFI_STUB_FEATURE_REPORT_BOOT_PARTITION, "Stub reports loader partition information" }, + { EFI_STUB_FEATURE_REPORT_STUB_PARTITION, "Stub reports stub partition information" }, + { EFI_STUB_FEATURE_REPORT_URL, "Stub reports network boot URL" }, { EFI_STUB_FEATURE_PICK_UP_CREDENTIALS, "Picks up credentials from boot partition" }, { EFI_STUB_FEATURE_PICK_UP_SYSEXTS, "Picks up system extension images from boot partition" }, { EFI_STUB_FEATURE_PICK_UP_CONFEXTS, "Picks up configuration extension images from boot partition" }, @@ -405,7 +408,6 @@ int verb_status(int argc, char *argv[], void *userdata) { { EFI_STUB_FEATURE_CMDLINE_SMBIOS, "Pick up .cmdline from SMBIOS Type 11" }, { EFI_STUB_FEATURE_DEVICETREE_ADDONS, "Pick up .dtb from addons" }, { EFI_STUB_FEATURE_MULTI_PROFILE_UKI, "Stub understands profile selector" }, - { EFI_STUB_FEATURE_REPORT_STUB_PARTITION, "Stub sets stub partition information" }, }; _cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL, *stub = NULL, *stub_path = NULL, *current_entry = NULL, *oneshot_entry = NULL, *default_entry = NULL; @@ -480,6 +482,10 @@ int verb_status(int argc, char *argv[], void *userdata) { (void) efi_loader_get_device_part_uuid(&loader_partition_uuid); print_yes_no_line(/* first= */ false, !sd_id128_is_null(loader_partition_uuid), "Boot loader set partition information"); + _cleanup_free_ char *loader_url = NULL; + (void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE_STR("LoaderDeviceURL"), &loader_url); + print_yes_no_line(/* first= */ false, !!loader_url, "Boot loader set network boot URL information"); + if (!sd_id128_is_null(loader_partition_uuid)) { if (!sd_id128_is_null(esp_uuid) && !sd_id128_equal(esp_uuid, loader_partition_uuid)) printf("WARNING: The boot loader reports a different partition UUID than the detected ESP ("SD_ID128_UUID_FORMAT_STR" vs. "SD_ID128_UUID_FORMAT_STR")!\n", @@ -493,6 +499,9 @@ int verb_status(int argc, char *argv[], void *userdata) { if (loader_path) printf(" Loader: %s%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT), strna(loader_path)); + if (loader_url) + printf(" Net Boot URL: %s\n", loader_url); + if (current_entry) printf("Current Entry: %s\n", current_entry); if (default_entry) @@ -513,6 +522,10 @@ int verb_status(int argc, char *argv[], void *userdata) { (void) efi_stub_get_device_part_uuid(&stub_partition_uuid); print_yes_no_line(/* first= */ false, !sd_id128_is_null(stub_partition_uuid), "Stub loader set partition information"); + _cleanup_free_ char *stub_url = NULL; + (void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE_STR("StubDeviceURL"), &stub_url); + print_yes_no_line(/* first= */ false, !!stub_url, "Stub set network boot URL information"); + if (!sd_id128_is_null(stub_partition_uuid)) { if (!(!sd_id128_is_null(esp_uuid) && sd_id128_equal(esp_uuid, stub_partition_uuid)) && !(!sd_id128_is_null(xbootldr_uuid) && sd_id128_equal(xbootldr_uuid, stub_partition_uuid))) @@ -526,6 +539,10 @@ int verb_status(int argc, char *argv[], void *userdata) { if (stub_path) printf(" Stub: %s%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT), strna(stub_path)); + + if (stub_url) + printf(" Net Boot URL: %s\n", stub_url); + printf("\n"); } diff --git a/src/fundamental/efivars-fundamental.h b/src/fundamental/efivars-fundamental.h index f002e81b532..678cdeeff84 100644 --- a/src/fundamental/efivars-fundamental.h +++ b/src/fundamental/efivars-fundamental.h @@ -24,6 +24,7 @@ #define EFI_LOADER_FEATURE_RETAIN_SHIM (UINT64_C(1) << 12) #define EFI_LOADER_FEATURE_MENU_DISABLE (UINT64_C(1) << 13) #define EFI_LOADER_FEATURE_MULTI_PROFILE_UKI (UINT64_C(1) << 14) +#define EFI_LOADER_FEATURE_REPORT_URL (UINT64_C(1) << 15) /* Features of the stub, i.e. systemd-stub */ #define EFI_STUB_FEATURE_REPORT_BOOT_PARTITION (UINT64_C(1) << 0) @@ -37,6 +38,7 @@ #define EFI_STUB_FEATURE_PICK_UP_CONFEXTS (UINT64_C(1) << 8) #define EFI_STUB_FEATURE_MULTI_PROFILE_UKI (UINT64_C(1) << 9) #define EFI_STUB_FEATURE_REPORT_STUB_PARTITION (UINT64_C(1) << 10) +#define EFI_STUB_FEATURE_REPORT_URL (UINT64_C(1) << 11) typedef enum SecureBootMode { SECURE_BOOT_UNSUPPORTED,