boot: automatically load drop-in EFI drivers off the ESP

Fixes: #15617
This commit is contained in:
Lennart Poettering
2021-09-23 17:24:10 +02:00
parent d72f81be74
commit 2553a5482c
6 changed files with 167 additions and 0 deletions
+1
View File
@@ -1298,6 +1298,7 @@ static int verb_status(int argc, char *argv[], void *userdata) {
{ EFI_LOADER_FEATURE_ENTRY_ONESHOT, "One-shot entry control" },
{ EFI_LOADER_FEATURE_XBOOTLDR, "Support for XBOOTLDR partition" },
{ EFI_LOADER_FEATURE_RANDOM_SEED, "Support for passing random seed to OS" },
{ EFI_LOADER_FEATURE_LOAD_DRIVER, "Load drop-in drivers" },
};
_cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL, *stub = NULL;
+4
View File
@@ -7,6 +7,7 @@
#include "console.h"
#include "devicetree.h"
#include "disk.h"
#include "drivers.h"
#include "efi-loader-features.h"
#include "graphics.h"
#include "linux.h"
@@ -2428,6 +2429,7 @@ static VOID export_variables(
EFI_LOADER_FEATURE_BOOT_COUNTING |
EFI_LOADER_FEATURE_XBOOTLDR |
EFI_LOADER_FEATURE_RANDOM_SEED |
EFI_LOADER_FEATURE_LOAD_DRIVER |
0;
_cleanup_freepool_ CHAR16 *infostr = NULL, *typestr = NULL;
@@ -2538,6 +2540,8 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
return log_error_status_stall(err, L"Error installing security policy: %r", err);
}
(VOID) load_drivers(image, loaded_image, root_dir);
config_load_all_entries(&config, loaded_image, loaded_image_path, root_dir);
if (config.entry_count == 0) {
+150
View File
@@ -0,0 +1,150 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <efi.h>
#include <efilib.h>
#include "drivers.h"
#include "util.h"
static VOID efi_unload_image(EFI_HANDLE *h) {
if (*h)
(VOID) uefi_call_wrapper(BS->UnloadImage, 1, *h);
}
static EFI_STATUS load_one_driver(
EFI_HANDLE parent_image,
EFI_LOADED_IMAGE *loaded_image,
const CHAR16 *fname) {
_cleanup_(efi_unload_image) EFI_HANDLE image = NULL;
_cleanup_freepool_ EFI_DEVICE_PATH *path = NULL;
_cleanup_freepool_ CHAR16 *spath = NULL;
EFI_STATUS err;
assert(parent_image);
assert(loaded_image);
assert(fname);
spath = PoolPrint(L"\\EFI\\systemd\\drivers\\%s", fname);
if (!spath)
return log_oom();
path = FileDevicePath(loaded_image->DeviceHandle, spath);
if (!path)
return log_oom();
err = uefi_call_wrapper(
BS->LoadImage, 6,
FALSE,
parent_image,
path,
NULL, 0,
&image);
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Failed to load image %s: %r", fname, err);
err = uefi_call_wrapper(
BS->HandleProtocol, 3,
image,
&LoadedImageProtocol,
(VOID **)&loaded_image);
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Failed to find protocol in driver image s: %r", fname, err);
if (loaded_image->ImageCodeType != EfiBootServicesCode &&
loaded_image->ImageCodeType != EfiRuntimeServicesCode)
return log_error_status_stall(EFI_INVALID_PARAMETER, L"Image %s is not a driver, refusing: %r", fname);
err = uefi_call_wrapper(
BS->StartImage, 3,
image,
NULL,
NULL);
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Failed to start image %s: %r", fname, err);
TAKE_PTR(image);
return EFI_SUCCESS;
}
static EFI_STATUS reconnect(VOID) {
_cleanup_freepool_ EFI_HANDLE *handles = NULL;
UINTN n_handles = 0;
EFI_STATUS err;
/* Reconnects all handles, so that any loaded drivers can take effect. */
err = uefi_call_wrapper(
BS->LocateHandleBuffer, 5,
AllHandles,
NULL,
NULL,
&n_handles,
&handles);
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Failed to get list of handles: %r", err);
for (UINTN i = 0; i < n_handles; i++) {
err = uefi_call_wrapper(
BS->ConnectController, 4,
handles[i],
NULL,
NULL,
TRUE);
if (err == EFI_NOT_FOUND) /* No drivers for this handle */
continue;
if (EFI_ERROR(err))
log_error_status_stall(err, L"Failed to reconnect handle %u, ignoring: %r", i, err);
}
return EFI_SUCCESS;
}
EFI_STATUS load_drivers(
EFI_HANDLE parent_image,
EFI_LOADED_IMAGE *loaded_image,
EFI_FILE_HANDLE root_dir) {
_cleanup_(FileHandleClosep) EFI_FILE_HANDLE drivers_dir = NULL;
_cleanup_freepool_ EFI_FILE_INFO *dirent = NULL;
_cleanup_freepool_ EFI_DEVICE_PATH *path = NULL;
UINTN dirent_size = 0, n_succeeded = 0;
EFI_STATUS err;
err = open_directory(
root_dir,
L"\\EFI\\systemd\\drivers",
&drivers_dir);
if (err == EFI_NOT_FOUND)
return EFI_SUCCESS;
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Failed to open \\EFI\\systemd\\drivers: %r", err);
for (;;) {
_cleanup_freepool_ CHAR16 *d = NULL;
err = readdir_harder(drivers_dir, &dirent, &dirent_size);
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Failed to read extra directory of loaded image: %r", err);
if (!dirent) /* End of directory */
break;
if (dirent->FileName[0] == '.')
continue;
if (dirent->Attribute & EFI_FILE_DIRECTORY)
continue;
if (!endswith_no_case(dirent->FileName, EFI_MACHINE_TYPE_NAME L".efi"))
continue;
err = load_one_driver(parent_image, loaded_image, dirent->FileName);
if (EFI_ERROR(err))
continue;
n_succeeded++;
}
if (n_succeeded > 0)
(VOID) reconnect();
return EFI_SUCCESS;
}
+9
View File
@@ -0,0 +1,9 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <efi.h>
EFI_STATUS load_drivers(
EFI_HANDLE parent_image,
EFI_LOADED_IMAGE *loaded_image,
EFI_FILE_HANDLE root_dir);
+2
View File
@@ -5,6 +5,7 @@ efi_headers = files('''
cpio.h
devicetree.h
disk.h
drivers.h
graphics.h
linux.h
measure.h
@@ -31,6 +32,7 @@ systemd_boot_sources = '''
boot.c
console.c
devicetree.c
drivers.c
random-seed.c
sha256.c
shim.c
+1
View File
@@ -12,3 +12,4 @@
#define EFI_LOADER_FEATURE_BOOT_COUNTING (UINT64_C(1) << 4)
#define EFI_LOADER_FEATURE_XBOOTLDR (UINT64_C(1) << 5)
#define EFI_LOADER_FEATURE_RANDOM_SEED (UINT64_C(1) << 6)
#define EFI_LOADER_FEATURE_LOAD_DRIVER (UINT64_C(1) << 7)