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.
This commit is contained in:
Lennart Poettering
2025-02-07 23:30:13 +01:00
parent c88fdb1e56
commit e15d18b4c6
12 changed files with 106 additions and 7 deletions

View File

@@ -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

View File

@@ -440,6 +440,16 @@
<xi:include href="version-info.xml" xpointer="v220"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>LoaderDeviceURL</varname></term>
<listitem><para>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.</para>
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>LoaderEntries</varname></term>

View File

@@ -550,6 +550,16 @@
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>StubDeviceURL</varname></term>
<listitem><para>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.</para>
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>StubInfo</varname></term>

View File

@@ -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);

View File

@@ -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

View File

@@ -300,6 +300,7 @@ libefi_sources = files(
'shim.c',
'smbios.c',
'ticks.c',
'url-discovery.c',
'util.c',
'vmm.c',
)

View File

@@ -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,

View File

@@ -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) {

30
src/boot/url-discovery.c Normal file
View File

@@ -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;
}

4
src/boot/url-discovery.h Normal file
View File

@@ -0,0 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
char16_t *disk_get_url(EFI_HANDLE *handle);

View File

@@ -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");
}

View File

@@ -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,