diff --git a/docs/BOOT_LOADER_INTERFACE.md b/docs/BOOT_LOADER_INTERFACE.md
index 4bf074df5e..e264c2cc3c 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 18b0708035..22f3cdb4ca 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 730d27cf6c..273513c14b 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 53bd22c42d..7c91e5d389 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 12fbd10b05..fb281ad394 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 3af5006d59..69c8e40ad3 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 0fabae1125..a394b0aa6d 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 e74b7db95a..3b3a5f6a42 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 0000000000..7c7cfb6a62
--- /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 0000000000..e4e50c387c
--- /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 e9f3a6f5b5..03ebea38df 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 f002e81b53..678cdeeff8 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,