1
0
mirror of https://github.com/systemd/systemd synced 2026-03-29 03:04:52 +02:00

Compare commits

..

No commits in common. "37eb7108fbe67550e92ed97e092fc0507bd4b4b1" and "cf7c7512f588a5e93908cc9114cf25d9dabb2445" have entirely different histories.

27 changed files with 285 additions and 1599 deletions

8
TODO
View File

@ -83,14 +83,6 @@ Janitorial Clean-ups:
Features:
* we probably should extend the root verity hash of the root fs into some PCR
on boot. (i.e. maybe add a crypttab option tpm2-measure=8 or so to measure it
into PCR 8)
* add a "policy" to the dissection logic. i.e. a bit mask what is OK to mount,
what must be read-only, what requires encryption, and what requires
authentication.
* in uefi stub: query firmware regarding which PCRs are being used, store that
in EFI var. then use this when enrolling TPM2 in cryptsetup to verify that
the selected PCRs actually are used by firmware.

View File

@ -309,12 +309,10 @@ You basically have three options:
3. 🙁 The *i-like-continents* option. In this option you'd leave your manager
daemon where it is, and would not turn on delegation on its unit. However,
as you start your first managed process (a container, for example) you would
register a new scope unit with systemd, and that scope unit would have
`Delegate=` turned on, and it would contain the PID of this process; all
your managed processes subsequently created should also be moved into this
scope. From systemd's PoV there'd be two units: your manager service and the
big scope that contains all your managed processes in one.
as first thing you register a new scope unit with systemd, and that scope
unit would have `Delegate=` turned on, and then you place all your
containers underneath it. From systemd's PoV there'd be two units: your
manager service and the big scope that contains all your containers in one.
BTW: if for whatever reason you say "I hate D-Bus, I'll never call any D-Bus
API, kthxbye", then options #1 and #3 are not available, as they generally

View File

@ -954,10 +954,6 @@ manpages = [
['systemd-sleep.conf', '5', ['sleep.conf.d'], ''],
['systemd-socket-activate', '1', [], ''],
['systemd-socket-proxyd', '8', [], ''],
['systemd-stub',
'7',
['linuxaa64.efi.stub', 'linuxia32.efi.stub', 'linuxx64.efi.stub'],
'ENABLE_EFI'],
['systemd-suspend.service',
'8',
['systemd-hibernate.service',

View File

@ -25,7 +25,7 @@
<title>Description</title>
<para><command>systemd-boot</command> (short: <command>sd-boot</command>) is a simple UEFI boot
manager. It provides a textual menu to select the entry to boot and an editor for the kernel command
manager. It provides a graphical menu to select the entry to boot and an editor for the kernel command
line. <command>systemd-boot</command> supports systems with UEFI firmware only.</para>
<para><command>systemd-boot</command> loads boot entry information from the EFI system partition (ESP),
@ -102,12 +102,6 @@
may be used to copy kernel images onto the ESP or the Extended Boot Loader Partition and to generate
description files compliant with the Boot Loader
Specification.</para>
<para><citerefentry><refentrytitle>systemd-stub</refentrytitle><manvolnum>7</manvolnum></citerefentry>
may be used as UEFI boot stub for executed kernels, which is useful to show graphical boot splashes
before transitioning into the Linux world. It is also capable of automatically picking up auxiliary
credential files (for boot parameterization) and system extension images, as companion files to the
booted kernel images.</para>
</refsect1>
<refsect1>
@ -280,37 +274,25 @@
usually mounted to <filename>/efi/</filename>, <filename>/boot/</filename> or
<filename>/boot/efi/</filename> during OS runtime. It also processes files on the Extended Boot Loader
partition which is typically mounted to <filename>/boot/</filename>, if it
exists.</para>
<para><command>systemd-boot</command> reads runtime configuration such as the boot timeout and default
exists. <command>systemd-boot</command> reads runtime configuration such as the boot timeout and default
entry from <filename>/loader/loader.conf</filename> on the ESP (in combination with data read from EFI
variables). See
<citerefentry><refentrytitle>loader.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
<para>Boot entry description files following the <ulink
<citerefentry><refentrytitle>loader.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>. Boot
entry description files following the <ulink url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot
Loader Specification</ulink> are read from <filename>/loader/entries/</filename> on the ESP and the
Extended Boot Loader partition. Unified kernel boot entries following the <ulink
url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink> are read from
<filename>/loader/entries/</filename> on the ESP and the Extended Boot Loader partition.</para>
<para>Unified kernel boot entries following the <ulink
url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink> are read from
<filename>/EFI/Linux/</filename> on the ESP and the Extended Boot Loader partition.</para>
<para>Optionally, a random seed for early boot entropy pool provisioning is stored in
<filename>/loader/random-seed</filename> in the ESP.</para>
<para>During initialization, <command>sd-boot</command> automatically loads all driver files placed in
the <filename>/EFI/systemd/drivers/</filename> directory of the ESP. The files placed there must have an
extension of the EFI architecture ID followed by <filename>.efi</filename> (e.g. for x86-64 this means a
suffix of <filename>x64.efi</filename>). This may be used to automatically load file system drivers and
similar, to extend the native firmware support.</para>
<filename>/EFI/Linux/</filename> on the ESP and the Extended Boot Loader partition. Optionally, a random
seed for early boot entropy pool provisioning is stored in <filename>/loader/random-seed</filename> in
the ESP.</para>
</refsect1>
<refsect1>
<title>EFI Variables</title>
<para>The following EFI variables are defined, set and read by <command>systemd-boot</command>, under the
vendor UUID <literal>4a67b082-0a4c-41cf-b6c7-440b29bb8c4f</literal>, for communication between the boot
loader and the OS:</para>
<para>The following EFI variables are defined, set and read by <command>systemd-boot</command>, under the vendor
UUID <literal>4a67b082-0a4c-41cf-b6c7-440b29bb8c4f</literal>, for communication between the OS and the boot
loader:</para>
<variablelist class='efi-variables'>
<varlistentry>
@ -511,7 +493,6 @@
<citerefentry><refentrytitle>systemd-bless-boot.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-boot-system-token.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>kernel-install</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-stub</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
<ulink url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink>,
<ulink url="https://systemd.io/BOOT_LOADER_INTERFACE">Boot Loader Interface</ulink>
</para>

View File

@ -1,204 +0,0 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
<refentry id="systemd-stub" conditional='ENABLE_EFI'
xmlns:xi="http://www.w3.org/2001/XInclude">
<refentryinfo>
<title>systemd-stub</title>
<productname>systemd</productname>
</refentryinfo>
<refmeta>
<refentrytitle>systemd-stub</refentrytitle>
<manvolnum>7</manvolnum>
</refmeta>
<refnamediv>
<refname>systemd-stub</refname>
<refname>linuxx64.efi.stub</refname>
<refname>linuxia32.efi.stub</refname>
<refname>linuxaa64.efi.stub</refname>
<refpurpose>A simple UEFI kernel boot stub</refpurpose>
</refnamediv>
<refsynopsisdiv>
<para><filename>/usr/lib/systemd/boot/efi/linuxx64.efi.stub</filename></para>
<para><filename>/usr/lib/systemd/boot/efi/linuxia32.efi.stub</filename></para>
<para><filename>/usr/lib/systemd/boot/efi/linuxaa64.efi.stub</filename></para>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para><command>systemd-stub</command> (stored in per-architecture files
<filename>linuxx64.efi.stub</filename>, <filename>linuxia32.efi.stub</filename>,
<filename>linuxaa64.efi.stub</filename> on disk) is a simple UEFI boot stub. An UEFI boot stub is
attached to a Linux kernel binary image, and is a piece of code that runs in the UEFI firmware
environment before transitioning into the Linux kernel environment. The UEFI boot stub ensures a Linux
kernel is executable as regular UEFI binary, and is able to do various preparations before switching the
system into the Linux world.</para>
<para>The UEFI boot stub looks for various resources for the kernel invocation inside the UEFI PE binary
itself. This allows combining various resources inside a single PE binary image, which may then be signed
via UEFI SecureBoot as a whole, covering all individual resources at once. Specifically it may
include:</para>
<itemizedlist>
<listitem><para>The ELF Linux kernel images will be looked for in the <literal>.linux</literal> PE
section of the executed image.</para></listitem>
<listitem><para>The initial RAM disk (initrd) will be looked for in the <literal>.initrd</literal> PE
section.</para></listitem>
<listitem><para>The kernel command line to pass to the invoked kernel will be looked for in the
<literal>.cmdline</literal> PE section.</para></listitem>
<listitem><para>A boot splash (in Windows <filename>.BMP</filename> format) to show on screen before
invoking the kernel will be looked for in the <literal>.splash</literal> PE section.</para></listitem>
</itemizedlist>
<para>If UEFI SecureBoot is enabled and the <literal>.cmdline</literal> section is present in the executed
image, any attempts to override the kernel command line by passing one as invocation parameters to the
EFI binary are ignored. Thus, in order to allow overriding the kernel command line, either disable UEFI
SecureBoot, or don't include a kernel command line PE section in the kernel image file. If a command line
is accepted via EFI invocation parameters to the EFI binary it is measured into TPM PCR 8 (if a TPM is
present).</para>
</refsect1>
<refsect1>
<title>Companion Files</title>
<para>The <command>systemd-stub</command> UEFI boot stub automatically collects two types of auxiliary
companion files optionally placed in a drop-in directory next to the EFI binary and dynamically generates
<command>cpio</command> initrd archives from them, and passes them to the kernel. Specifically:</para>
<itemizedlist>
<listitem><para>For a kernel binary called <filename><replaceable>foo</replaceable>.efi</filename> it
will look for files with the <filename>.cred</filename> suffix in a directory named
<filename><replaceable>foo</replaceable>.efi.extra.d/</filename>, next to it. A <command>cpio</command>
archive is generated from all files found that way, placing them in the
<filename>/.extra/credentials/</filename> directory of the initrd file hierarchy. The main initrd may
then access them in this directory. This is supposed to be used to store auxiliary, encrypted,
authenticated credentials for use with <varname>LoadCredentialEncrypted=</varname> in the UEFI System
Partition. See
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
details on encrypted credentials. The generated <command>cpio</command> archive is measured into TPM
PCR 4 (if a TPM is present)</para></listitem>
<listitem><para>Similar, files <filename><replaceable>foo</replaceable>.efi.extra.d/*.raw</filename>
are packed up as <command>cpio</command> archive and placed in the <filename>/.extra/sysext/</filename>
directory in the initrd file hierarchy. This is supposed to be used to pass additional system extension
images to the initrd. See
<citerefentry><refentrytitle>systemd-sysext</refentrytitle><manvolnum>8</manvolnum></citerefentry> for
details on system extension images. The generated <command>cpio</command> archive containing these
system extension images is measured into TPM PCR 8 (if a TPM is present).</para></listitem>
</itemizedlist>
<para>Both mechanisms may be used to parameterize and extend trusted (i.e. signed), immutable initrd
images in a reasonably safe way: all data they contain is measured into TPM PCRs. On access they should be
further validated: in case of the credentials case by encrypting/authenticating them via TPM, as exposed
by <command>systemd-creds encrypt -T</command> (see
<citerefentry><refentrytitle>systemd-creds</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
details); in case of the system extension images by using signed Verity images.</para>
</refsect1>
<refsect1>
<title>EFI Variables</title>
<para>The following EFI variables are defined, set and read by <command>systemd-stub</command>, under the
vendor UUID <literal>4a67b082-0a4c-41cf-b6c7-440b29bb8c4f</literal>, for communication between the boot
stub and the OS:</para>
<variablelist class='efi-variables'>
<varlistentry>
<term><varname>LoaderDevicePartUUID</varname></term>
<listitem><para>Contains the partition UUID of the EFI System Partition the EFI image was run
from. <citerefentry><refentrytitle>systemd-gpt-auto-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
uses this information to automatically find the disk booted from, in order to discover various other
partitions on the same disk automatically.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>LoaderFirmwareInfo</varname></term>
<term><varname>LoaderFirmwareType</varname></term>
<listitem><para>Brief firmware information. Use
<citerefentry><refentrytitle>bootctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> to view this
data.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>LoaderImageIdentifier</varname></term>
<listitem><para>The path of EFI executable, relative to the EFI System Partition's root
directory. Use
<citerefentry><refentrytitle>bootctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> to view
this data.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>StubInfo</varname></term>
<listitem><para>Brief stub information. Use
<citerefentry><refentrytitle>bootctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> to view
this data.</para></listitem>
</varlistentry>
</variablelist>
<para>Note that some of the variables above may also be set by the boot loader. The stub will only set
them if they aren't set already. Some of these variables are defined by the <ulink
url="https://systemd.io/BOOT_LOADER_INTERFACE">Boot Loader Interface</ulink>.</para>
</refsect1>
<refsect1>
<title>Assembling Kernel Images</title>
<para>In order to assemble an UEFI PE kernel image from various components as described above, use an
<citerefentry><refentrytitle>objcopy</refentrytitle><manvolnum>1</manvolnum></citerefentry> command line
like this:</para>
<programlisting>objcopy \
--add-section .osrel=os-release --change-section-vma .osrel=0x20000 \
--add-section .cmdline=cmdline.txt --change-section-vma .cmdline=0x30000 \
--add-section .splash=splash.bmp --change-section-vma .splash=0x40000 \
--add-section .linux=vmlinux --change-section-vma .linux=0x2000000 \
--add-section .initrd=initrd.cpio --change-section-vma .initrd=0x3000000 \
/usr/lib/systemd/boot/efi/linuxx64.efi.stub \
foo-unsigned.efi</programlisting>
<para>This generates one PE executable file <filename>foo-unsigned.efi</filename> from the six individual
files for OS release information, kernel command line, boot splash image, kernel image, main initrd and
UEFI boot stub.</para>
<para>To then sign the resulting image for UEFI SecureBoot use an
<citerefentry><refentrytitle>sbsign</refentrytitle><manvolnum>1</manvolnum></citerefentry> command like
the following:</para>
<programlisting>sbsign \
--key mykey.pem \
--cert mykey.crt \
--output foo.efi \
foo-unsigned.efi</programlisting>
<para>This expects a pair of X.509 private key and certificate as parameters and then signs the UEFI PE
executable we generated above for UEFI SecureBoot and generates a signed UEFI PE executable as
result.</para>
</refsect1>
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-creds</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-sysext</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<ulink url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink>,
<ulink url="https://systemd.io/BOOT_LOADER_INTERFACE">Boot Loader Interface</ulink>,
<citerefentry><refentrytitle>objcopy</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sbsign</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
</refsect1>
</refentry>

View File

@ -1636,6 +1636,8 @@ if get_option('efi')
have = true
conf.set_quoted('EFI_MACHINE_TYPE_NAME', EFI_MACHINE_TYPE_NAME)
conf.set('SD_TPM_PCR', get_option('tpm-pcrindex'))
else
have = false
endif

View File

@ -416,6 +416,8 @@ option('efi-libdir', type : 'string',
description : 'path to the EFI lib directory')
option('efi-includedir', type : 'string', value : '/usr/include/efi',
description : 'path to the EFI header directory')
option('tpm-pcrindex', type : 'integer', value : 8,
description : 'TPM PCR register number to use')
option('sbat-distro', type : 'string',
description : 'SBAT distribution ID, e.g. fedora, or auto for autodetection')
option('sbat-distro-generation', type : 'integer', value : 1,

View File

@ -14,7 +14,7 @@ InstallDirectory=mkosi.installdir
SourceFileTransferFinal=copy-git-others
[Host]
QemuHeadless=no
QemuHeadless=yes
NetworkVeth=yes
[Validation]

View File

@ -722,7 +722,7 @@ static int find_slot(sd_id128_t uuid, const char *path, uint16_t *id) {
for (i = 0; i < n; i++)
if (i != options[i]) {
*id = i;
return 0;
return 1;
}
/* use the next one */
@ -1298,7 +1298,6 @@ 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;

View File

@ -7,7 +7,6 @@
#include "console.h"
#include "devicetree.h"
#include "disk.h"
#include "drivers.h"
#include "efi-loader-features.h"
#include "graphics.h"
#include "linux.h"
@ -367,7 +366,7 @@ static UINTN entry_lookup_key(Config *config, UINTN start, CHAR16 key) {
}
static VOID print_status(Config *config, CHAR16 *loaded_image_path) {
UINT64 key;
UINT64 key, indvar;
UINTN timeout;
BOOLEAN modevar;
_cleanup_freepool_ CHAR16 *partstr = NULL, *defaultstr = NULL;
@ -395,7 +394,8 @@ static VOID print_status(Config *config, CHAR16 *loaded_image_path) {
if (shim_loaded())
Print(L"Shim: present\n");
Print(L"OsIndicationsSupported: %d\n", get_os_indications_supported());
if (efivar_get_uint64_le(EFI_GLOBAL_GUID, L"OsIndicationsSupported", &indvar) == EFI_SUCCESS)
Print(L"OsIndicationsSupported: %d\n", indvar);
Print(L"\n--- press key ---\n\n");
console_key_read(&key, 0);
@ -517,8 +517,7 @@ static BOOLEAN menu_run(
BOOLEAN refresh = TRUE, highlight = FALSE;
UINTN x_start = 0, y_start = 0, y_status = 0;
UINTN x_max, y_max;
CHAR16 **lines = NULL;
_cleanup_freepool_ CHAR16 *clearline = NULL, *status = NULL;
CHAR16 **lines = NULL, *status = NULL, *clearline = NULL;
UINTN timeout_remain = config->timeout_sec;
INT16 idx;
BOOLEAN exit = FALSE, run = TRUE;
@ -902,6 +901,7 @@ static BOOLEAN menu_run(
for (UINTN i = 0; i < config->entry_count; i++)
FreePool(lines[i]);
FreePool(lines);
FreePool(clearline);
clear_screen(COLOR_NORMAL);
return run;
@ -1225,7 +1225,7 @@ static VOID config_entry_bump_counters(
_cleanup_(FileHandleClosep) EFI_FILE_HANDLE handle = NULL;
static const EFI_GUID EfiFileInfoGuid = EFI_FILE_INFO_ID;
_cleanup_freepool_ EFI_FILE_INFO *file_info = NULL;
UINTN file_info_size;
UINTN file_info_size, a, b;
EFI_STATUS r;
assert(entry);
@ -1243,9 +1243,26 @@ static VOID config_entry_bump_counters(
if (EFI_ERROR(r))
return;
r = get_file_info_harder(handle, &file_info, &file_info_size);
if (EFI_ERROR(r))
return;
a = StrLen(entry->current_name);
b = StrLen(entry->next_name);
file_info_size = OFFSETOF(EFI_FILE_INFO, FileName) + (a > b ? a : b) + 1;
for (;;) {
file_info = AllocatePool(file_info_size);
r = uefi_call_wrapper(handle->GetInfo, 4, handle, (EFI_GUID*) &EfiFileInfoGuid, &file_info_size, file_info);
if (!EFI_ERROR(r))
break;
if (r != EFI_BUFFER_TOO_SMALL || file_info_size * 2 < file_info_size) {
log_error_stall(L"Failed to get file info for '%s': %r", old_path, r);
return;
}
file_info_size *= 2;
FreePool(file_info);
}
/* And rename the file */
StrCpy(file_info->FileName, entry->next_name);
@ -1470,11 +1487,9 @@ static VOID config_load_entries(
Config *config,
EFI_HANDLE *device,
EFI_FILE *root_dir,
const CHAR16 *loaded_image_path) {
CHAR16 *loaded_image_path) {
_cleanup_(FileHandleClosep) EFI_FILE_HANDLE entries_dir = NULL;
_cleanup_freepool_ EFI_FILE_INFO *f = NULL;
UINTN f_size = 0;
EFI_STATUS err;
assert(config);
@ -1482,17 +1497,22 @@ static VOID config_load_entries(
assert(root_dir);
assert(loaded_image_path);
err = open_directory(root_dir, L"\\loader\\entries", &entries_dir);
err = uefi_call_wrapper(root_dir->Open, 5, root_dir, &entries_dir, (CHAR16*) L"\\loader\\entries", EFI_FILE_MODE_READ, 0ULL);
if (EFI_ERROR(err))
return;
for (;;) {
CHAR16 buf[256];
UINTN bufsize;
EFI_FILE_INFO *f;
_cleanup_freepool_ CHAR8 *content = NULL;
err = readdir_harder(entries_dir, &f, &f_size);
if (f_size == 0 || EFI_ERROR(err))
bufsize = sizeof(buf);
err = uefi_call_wrapper(entries_dir->Read, 3, entries_dir, &bufsize, buf);
if (bufsize == 0 || EFI_ERROR(err))
break;
f = (EFI_FILE_INFO *) buf;
if (f->FileName[0] == '.')
continue;
if (f->Attribute & EFI_FILE_DIRECTORY)
@ -1509,7 +1529,7 @@ static VOID config_load_entries(
}
}
static INTN config_entry_compare(const ConfigEntry *a, const ConfigEntry *b) {
static INTN config_entry_compare(ConfigEntry *a, ConfigEntry *b) {
INTN r;
assert(a);
@ -1547,7 +1567,24 @@ static INTN config_entry_compare(const ConfigEntry *a, const ConfigEntry *b) {
static VOID config_sort_entries(Config *config) {
assert(config);
sort_pointer_array((void**) config->entries, config->entry_count, (compare_pointer_func_t) config_entry_compare);
for (UINTN i = 1; i < config->entry_count; i++) {
BOOLEAN more;
more = FALSE;
for (UINTN k = 0; k < config->entry_count - i; k++) {
ConfigEntry *entry;
if (config_entry_compare(config->entries[k], config->entries[k+1]) <= 0)
continue;
entry = config->entries[k];
config->entries[k] = config->entries[k+1];
config->entries[k+1] = entry;
more = TRUE;
}
if (!more)
break;
}
}
static INTN config_entry_find(Config *config, CHAR16 *id) {
@ -1941,23 +1978,21 @@ static VOID config_entry_add_linux(
EFI_FILE *root_dir) {
_cleanup_(FileHandleClosep) EFI_FILE_HANDLE linux_dir = NULL;
_cleanup_freepool_ EFI_FILE_INFO *f = NULL;
ConfigEntry *entry;
UINTN f_size = 0;
EFI_STATUS err;
ConfigEntry *entry;
assert(config);
assert(device);
assert(root_dir);
err = open_directory(root_dir, L"\\EFI\\Linux", &linux_dir);
err = uefi_call_wrapper(root_dir->Open, 5, root_dir, &linux_dir, (CHAR16*) L"\\EFI\\Linux", EFI_FILE_MODE_READ, 0ULL);
if (EFI_ERROR(err))
return;
for (;;) {
_cleanup_freepool_ CHAR16 *os_name_pretty = NULL, *os_name = NULL, *os_id = NULL,
*os_version = NULL, *os_version_id = NULL, *os_build_id = NULL, *os_image_version = NULL;
_cleanup_freepool_ CHAR8 *content = NULL;
CHAR16 buf[256];
UINTN bufsize = sizeof buf;
EFI_FILE_INFO *f;
const CHAR8 *sections[] = {
(CHAR8 *)".osrel",
(CHAR8 *)".cmdline",
@ -1965,14 +2000,22 @@ static VOID config_entry_add_linux(
};
UINTN offs[ELEMENTSOF(sections)-1] = {};
UINTN szs[ELEMENTSOF(sections)-1] = {};
CHAR8 *content = NULL;
CHAR8 *line;
UINTN pos = 0;
CHAR8 *key, *value;
CHAR16 *os_name_pretty = NULL;
CHAR16 *os_name = NULL;
CHAR16 *os_id = NULL;
CHAR16 *os_version = NULL;
CHAR16 *os_version_id = NULL;
CHAR16 *os_build_id = NULL;
err = readdir_harder(linux_dir, &f, &f_size);
if (f_size == 0 || EFI_ERROR(err))
err = uefi_call_wrapper(linux_dir->Read, 3, linux_dir, &bufsize, buf);
if (bufsize == 0 || EFI_ERROR(err))
break;
f = (EFI_FILE_INFO *) buf;
if (f->FileName[0] == '.')
continue;
if (f->Attribute & EFI_FILE_DIRECTORY)
@ -2028,28 +2071,16 @@ static VOID config_entry_add_linux(
os_build_id = stra_to_str(value);
continue;
}
if (strcmpa((const CHAR8*) "IMAGE_VERSION", key) == 0) {
FreePool(os_image_version);
os_image_version = stra_to_str(value);
continue;
}
}
if ((os_name_pretty || os_name) && os_id && (os_image_version || os_version || os_version_id || os_build_id)) {
if ((os_name_pretty || os_name) && os_id && (os_version || os_version_id || os_build_id)) {
_cleanup_freepool_ CHAR16 *path = NULL;
path = PoolPrint(L"\\EFI\\Linux\\%s", f->FileName);
entry = config_entry_add_loader(
config,
device,
LOADER_LINUX,
f->FileName,
/* key= */ 'l',
os_name_pretty ?: os_name,
path,
os_image_version ?: (os_version ?: (os_version_id ? : os_build_id)));
entry = config_entry_add_loader(config, device, LOADER_LINUX, f->FileName, 'l',
os_name_pretty ?: os_name, path,
os_version ?: (os_version_id ? : os_build_id));
FreePool(content);
content = NULL;
@ -2067,6 +2098,14 @@ static VOID config_entry_add_linux(
config_entry_parse_tries(entry, L"\\EFI\\Linux", f->FileName, L".efi");
}
FreePool(os_name_pretty);
FreePool(os_name);
FreePool(os_id);
FreePool(os_version);
FreePool(os_version_id);
FreePool(os_build_id);
FreePool(content);
}
}
@ -2325,8 +2364,14 @@ static EFI_STATUS image_start(
loaded_image->LoadOptions = options;
loaded_image->LoadOptionsSize = StrSize(loaded_image->LoadOptions);
#if ENABLE_TPM
/* Try to log any options to the TPM, especially to catch manually edited options */
(VOID) tpm_log_load_options(options);
err = tpm_log_event(SD_TPM_PCR,
(EFI_PHYSICAL_ADDRESS) (UINTN) loaded_image->LoadOptions,
loaded_image->LoadOptionsSize, loaded_image->LoadOptions);
if (EFI_ERROR(err))
log_error_stall(L"Unable to add image options measurement: %r", err);
#endif
}
efivar_set_time_usec(LOADER_GUID, L"LoaderTimeExecUSec", 0);
@ -2391,11 +2436,7 @@ static VOID config_write_entries_to_variable(Config *config) {
(void) efivar_set_raw(LOADER_GUID, L"LoaderEntries", buffer, sz, 0);
}
static VOID export_variables(
EFI_LOADED_IMAGE *loaded_image,
const CHAR16 *loaded_image_path,
UINT64 init_usec) {
EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
static const UINT64 loader_features =
EFI_LOADER_FEATURE_CONFIG_TIMEOUT |
EFI_LOADER_FEATURE_CONFIG_TIMEOUT_ONE_SHOT |
@ -2404,15 +2445,21 @@ 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;
UINT64 osind = 0;
EFI_LOADED_IMAGE *loaded_image;
EFI_FILE *root_dir;
CHAR16 *loaded_image_path;
EFI_STATUS err;
Config config;
UINT64 init_usec;
BOOLEAN menu = FALSE;
CHAR16 uuid[37];
assert(loaded_image);
assert(loaded_image_path);
InitializeLib(image, sys_table);
init_usec = time_usec();
efivar_set_time_usec(LOADER_GUID, L"LoaderTimeInitUSec", init_usec);
efivar_set(LOADER_GUID, L"LoaderInfo", L"systemd-boot " GIT_VERSION, 0);
@ -2424,82 +2471,14 @@ static VOID export_variables(
(void) efivar_set_uint64_le(LOADER_GUID, L"LoaderFeatures", loader_features, 0);
/* the filesystem path to this image, to prevent adding ourselves to the menu */
efivar_set(LOADER_GUID, L"LoaderImageIdentifier", loaded_image_path, 0);
err = uefi_call_wrapper(BS->OpenProtocol, 6, image, &LoadedImageProtocol, (VOID **)&loaded_image,
image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Error getting a LoadedImageProtocol handle: %r", err);
/* export the device path this image is started from */
if (disk_get_part_uuid(loaded_image->DeviceHandle, uuid) == EFI_SUCCESS)
efivar_set(LOADER_GUID, L"LoaderDevicePartUUID", uuid, 0);
}
static VOID config_load_all_entries(
Config *config,
EFI_LOADED_IMAGE *loaded_image,
const CHAR16 *loaded_image_path,
EFI_FILE *root_dir) {
assert(config);
assert(loaded_image);
assert(loaded_image_path);
assert(root_dir);
config_load_defaults(config, root_dir);
/* scan /EFI/Linux/ directory */
config_entry_add_linux(config, loaded_image->DeviceHandle, root_dir);
/* scan /loader/entries/\*.conf files */
config_load_entries(config, loaded_image->DeviceHandle, root_dir, loaded_image_path);
/* Similar, but on any XBOOTLDR partition */
config_load_xbootldr(config, loaded_image->DeviceHandle);
/* sort entries after version number */
config_sort_entries(config);
/* if we find some well-known loaders, add them to the end of the list */
config_entry_add_osx(config);
config_entry_add_windows(config, loaded_image->DeviceHandle, root_dir);
config_entry_add_loader_auto(config, loaded_image->DeviceHandle, root_dir, NULL,
L"auto-efi-shell", 's', L"EFI Shell", L"\\shell" EFI_MACHINE_TYPE_NAME ".efi");
config_entry_add_loader_auto(config, loaded_image->DeviceHandle, root_dir, loaded_image_path,
L"auto-efi-default", '\0', L"EFI Default Loader", NULL);
if (config->auto_firmware && (get_os_indications_supported() & EFI_OS_INDICATIONS_BOOT_TO_FW_UI))
config_entry_add_call(config,
L"auto-reboot-to-firmware-setup",
L"Reboot Into Firmware Interface",
reboot_into_firmware);
}
EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
_cleanup_freepool_ EFI_LOADED_IMAGE *loaded_image = NULL;
_cleanup_(FileHandleClosep) EFI_FILE *root_dir = NULL;
CHAR16 *loaded_image_path;
EFI_STATUS err;
Config config;
UINT64 init_usec;
BOOLEAN menu = FALSE;
InitializeLib(image, sys_table);
init_usec = time_usec();
err = uefi_call_wrapper(
BS->OpenProtocol, 6,
image,
&LoadedImageProtocol,
(VOID **)&loaded_image,
image,
NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Error getting a LoadedImageProtocol handle: %r", err);
loaded_image_path = DevicePathToStr(loaded_image->FilePath);
if (!loaded_image_path)
return log_oom();
export_variables(loaded_image, loaded_image_path, init_usec);
root_dir = LibOpenRoot(loaded_image->DeviceHandle);
if (!root_dir)
@ -2511,9 +2490,39 @@ 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);
/* the filesystem path to this image, to prevent adding ourselves to the menu */
loaded_image_path = DevicePathToStr(loaded_image->FilePath);
efivar_set(LOADER_GUID, L"LoaderImageIdentifier", loaded_image_path, 0);
config_load_all_entries(&config, loaded_image, loaded_image_path, root_dir);
config_load_defaults(&config, root_dir);
/* scan /EFI/Linux/ directory */
config_entry_add_linux(&config, loaded_image->DeviceHandle, root_dir);
/* scan /loader/entries/\*.conf files */
config_load_entries(&config, loaded_image->DeviceHandle, root_dir, loaded_image_path);
/* Similar, but on any XBOOTLDR partition */
config_load_xbootldr(&config, loaded_image->DeviceHandle);
/* sort entries after version number */
config_sort_entries(&config);
/* if we find some well-known loaders, add them to the end of the list */
config_entry_add_osx(&config);
config_entry_add_windows(&config, loaded_image->DeviceHandle, root_dir);
config_entry_add_loader_auto(&config, loaded_image->DeviceHandle, root_dir, NULL,
L"auto-efi-shell", 's', L"EFI Shell", L"\\shell" EFI_MACHINE_TYPE_NAME ".efi");
config_entry_add_loader_auto(&config, loaded_image->DeviceHandle, root_dir, loaded_image_path,
L"auto-efi-default", '\0', L"EFI Default Loader", NULL);
if (config.auto_firmware && efivar_get_uint64_le(EFI_GLOBAL_GUID, L"OsIndicationsSupported", &osind) == EFI_SUCCESS) {
if (osind & EFI_OS_INDICATIONS_BOOT_TO_FW_UI)
config_entry_add_call(&config,
L"auto-reboot-to-firmware-setup",
L"Reboot Into Firmware Interface",
reboot_into_firmware);
}
if (config.entry_count == 0) {
log_error_stall(L"No loader found. Configuration files in \\loader\\entries\\*.conf are needed.");
@ -2592,7 +2601,9 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
}
err = EFI_SUCCESS;
out:
FreePool(loaded_image_path);
config_free(&config);
uefi_call_wrapper(root_dir->Close, 1, root_dir);
uefi_call_wrapper(BS->CloseProtocol, 4, image, &LoadedImageProtocol, image, NULL);
return err;
}

View File

@ -1,466 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "cpio.h"
#include "measure.h"
#include "util.h"
#define EXTRA_DIR_SUFFIX L".extra.d"
static CHAR8* write_cpio_word(CHAR8 *p, UINT32 v) {
static const char hex[] = "0123456789abcdef";
assert(p);
/* Writes a CPIO header 8 character hex value */
for (UINTN i = 0; i < 8; i++)
p[7-i] = hex[(v >> (4 * i)) & 0xF];
return p + 8;
}
static CHAR8* mangle_filename(CHAR8 *p, const CHAR16 *f) {
CHAR8* w;
assert(p);
assert(f);
/* Basically converts UTF-16 to plain ASCII (note that we filtered non-ASCII filenames beforehand, so
* this operation is always safe) */
for (w = p; *f != 0; f++) {
assert(*f <= 0x7fu);
*(w++) = *f;
}
*w = 0;
return w;
}
static CHAR8* pad4(CHAR8 *p, const CHAR8* start) {
assert(p);
assert(start);
assert(p >= start);
/* Appends NUL bytes to 'p', until the address is divisable by 4, when taken relative to 'start' */
while ((p - start) % 4 != 0)
*(p++) = 0;
return p;
}
static EFI_STATUS pack_cpio_one(
const CHAR16 *fname,
const VOID *contents,
UINTN contents_size,
const CHAR8 *target_dir_prefix,
UINT32 access_mode,
UINT32 *inode_counter,
VOID **cpio_buffer,
UINTN *cpio_buffer_size) {
UINTN l, target_dir_prefix_size, fname_size, q;
CHAR8 *a;
assert(fname);
assert(contents_size || contents_size == 0);
assert(target_dir_prefix);
assert(inode_counter);
assert(cpio_buffer);
assert(cpio_buffer_size);
/* Serializes one file in the cpio format understood by the kernel initrd logic.
*
* See: https://www.kernel.org/doc/Documentation/early-userspace/buffer-format.txt */
if (contents_size > UINT32_MAX) /* cpio cannot deal with > 32bit file sizes */
return EFI_LOAD_ERROR;
if (*inode_counter == UINT32_MAX) /* more than 2^32-1 inodes? yikes. cpio doesn't support that either */
return EFI_OUT_OF_RESOURCES;
l = 6 + 13*8 + 1 + 1; /* Fixed CPIO header size, slash separator, and NUL byte after the file name*/
target_dir_prefix_size = strlena(target_dir_prefix);
if (l > UINTN_MAX - target_dir_prefix_size)
return EFI_OUT_OF_RESOURCES;
l += target_dir_prefix_size;
fname_size = StrLen(fname);
if (l > UINTN_MAX - fname_size)
return EFI_OUT_OF_RESOURCES;
l += fname_size; /* append space for file name */
/* CPIO can't deal with fnames longer than 2^32-1 */
if (target_dir_prefix_size + fname_size >= UINT32_MAX)
return EFI_OUT_OF_RESOURCES;
/* Align the whole header to 4 byte size */
l = ALIGN_TO(l, 4);
if (l == UINTN_MAX) /* overflow check */
return EFI_OUT_OF_RESOURCES;
/* Align the contents to 4 byte size */
q = ALIGN_TO(contents_size, 4);
if (q == UINTN_MAX) /* overflow check */
return EFI_OUT_OF_RESOURCES;
if (l > UINTN_MAX - q) /* overflow check */
return EFI_OUT_OF_RESOURCES;
l += q; /* Add contents to header */
if (*cpio_buffer_size > UINTN_MAX - l) /* overflow check */
return EFI_OUT_OF_RESOURCES;
a = ReallocatePool(*cpio_buffer, *cpio_buffer_size, *cpio_buffer_size + l);
if (!a)
return EFI_OUT_OF_RESOURCES;
*cpio_buffer = a;
a = (CHAR8*) *cpio_buffer + *cpio_buffer_size;
CopyMem(a, "070701", 6); /* magic ID */
a += 6;
a = write_cpio_word(a, (*inode_counter)++); /* inode */
a = write_cpio_word(a, access_mode | 0100000 /* = S_IFREG */); /* mode */
a = write_cpio_word(a, 0); /* uid */
a = write_cpio_word(a, 0); /* gid */
a = write_cpio_word(a, 1); /* nlink */
/* Note: we don't make any attempt to propagate the mtime here, for two reasons: it's a mess given
* that FAT usually is assumed to operate with timezoned timestamps, while UNIX does not. More
* importantly though: the modifications times would hamper our goals of providing stable
* measurements for the same boots. After all we extend the initrds we generate here into TPM2
* PCRs. */
a = write_cpio_word(a, 0); /* mtime */
a = write_cpio_word(a, contents_size); /* size */
a = write_cpio_word(a, 0); /* major(dev) */
a = write_cpio_word(a, 0); /* minor(dev) */
a = write_cpio_word(a, 0); /* major(rdev) */
a = write_cpio_word(a, 0); /* minor(rdev) */
a = write_cpio_word(a, target_dir_prefix_size + fname_size + 1); /* fname size */
a = write_cpio_word(a, 0); /* "crc" */
CopyMem(a, target_dir_prefix, target_dir_prefix_size);
a += target_dir_prefix_size;
*(a++) = '/';
a = mangle_filename(a, fname);
/* Pad to next multiple of 4 */
a = pad4(a, *cpio_buffer);
CopyMem(a, contents, contents_size);
a += contents_size;
/* Pad to next multiple of 4 */
a = pad4(a, *cpio_buffer);
assert(a == (CHAR8*) *cpio_buffer + *cpio_buffer_size + l);
*cpio_buffer_size += l;
return EFI_SUCCESS;
}
static EFI_STATUS pack_cpio_dir(
const CHAR8 *path,
UINT32 access_mode,
UINT32 *inode_counter,
VOID **cpio_buffer,
UINTN *cpio_buffer_size) {
UINTN l, path_size;
CHAR8 *a;
assert(path);
assert(inode_counter);
assert(cpio_buffer);
assert(cpio_buffer_size);
/* Serializes one directory inode in cpio format. Note that cpio archives must first create the dirs
* they want to place files in. */
if (*inode_counter == UINT32_MAX)
return EFI_OUT_OF_RESOURCES;
l = 6 + 13*8 + 1; /* Fixed CPIO header size, and NUL byte after the file name*/
path_size = strlena(path);
if (l > UINTN_MAX - path_size)
return EFI_OUT_OF_RESOURCES;
l += path_size;
/* Align the whole header to 4 byte size */
l = ALIGN_TO(l, 4);
if (l == UINTN_MAX) /* overflow check */
return EFI_OUT_OF_RESOURCES;
if (*cpio_buffer_size > UINTN_MAX - l) /* overflow check */
return EFI_OUT_OF_RESOURCES;
a = ReallocatePool(*cpio_buffer, *cpio_buffer_size, *cpio_buffer_size + l);
if (!a)
return EFI_OUT_OF_RESOURCES;
*cpio_buffer = a;
a = (CHAR8*) *cpio_buffer + *cpio_buffer_size;
CopyMem(a, "070701", 6); /* magic ID */
a += 6;
a = write_cpio_word(a, (*inode_counter)++); /* inode */
a = write_cpio_word(a, access_mode | 0040000 /* = S_IFDIR */); /* mode */
a = write_cpio_word(a, 0); /* uid */
a = write_cpio_word(a, 0); /* gid */
a = write_cpio_word(a, 1); /* nlink */
a = write_cpio_word(a, 0); /* mtime */
a = write_cpio_word(a, 0); /* size */
a = write_cpio_word(a, 0); /* major(dev) */
a = write_cpio_word(a, 0); /* minor(dev) */
a = write_cpio_word(a, 0); /* major(rdev) */
a = write_cpio_word(a, 0); /* minor(rdev) */
a = write_cpio_word(a, path_size + 1); /* fname size */
a = write_cpio_word(a, 0); /* "crc" */
CopyMem(a, path, path_size + 1);
a += path_size + 1;
/* Pad to next multiple of 4 */
a = pad4(a, *cpio_buffer);
assert(a == (CHAR8*) *cpio_buffer + *cpio_buffer_size + l);
*cpio_buffer_size += l;
return EFI_SUCCESS;
}
static EFI_STATUS pack_cpio_prefix(
const CHAR8 *path,
UINT32 dir_mode,
UINT32 *inode_counter,
VOID **cpio_buffer,
UINTN *cpio_buffer_size) {
EFI_STATUS err;
assert(path);
assert(inode_counter);
assert(cpio_buffer);
assert(cpio_buffer_size);
/* Serializes directory inodes of all prefix paths of the specified path in cpio format. Note that
* (similar to mkdir -p behaviour) all leading paths are created with 0555 access mode, only the
* final dir is created with the specified directory access mode. */
for (const CHAR8 *p = path;;) {
const CHAR8 *e;
e = strchra(p, '/');
if (!e)
break;
if (e > p) {
_cleanup_freepool_ CHAR8 *t = NULL;
t = strndup8(path, e - path);
if (!t)
return EFI_OUT_OF_RESOURCES;
err = pack_cpio_dir(t, 0555, inode_counter, cpio_buffer, cpio_buffer_size);
if (EFI_ERROR(err))
return err;
}
p = e + 1;
}
return pack_cpio_dir(path, dir_mode, inode_counter, cpio_buffer, cpio_buffer_size);
}
static EFI_STATUS pack_cpio_trailer(
VOID **cpio_buffer,
UINTN *cpio_buffer_size) {
static const char trailer[] =
"070701"
"00000000"
"00000000"
"00000000"
"00000000"
"00000001"
"00000000"
"00000000"
"00000000"
"00000000"
"00000000"
"00000000"
"0000000B"
"00000000"
"TRAILER!!!\0\0\0"; /* There's a fourth NUL byte appended here, because this is a string */
VOID *a;
/* Generates the cpio trailer record that indicates the end of our initrd cpio archive */
assert(cpio_buffer);
assert(cpio_buffer_size);
assert_cc(sizeof(trailer) % 4 == 0);
a = ReallocatePool(*cpio_buffer, *cpio_buffer_size, *cpio_buffer_size + sizeof(trailer));
if (!a)
return EFI_OUT_OF_RESOURCES;
*cpio_buffer = a;
CopyMem((UINT8*) *cpio_buffer + *cpio_buffer_size, trailer, sizeof(trailer));
*cpio_buffer_size += sizeof(trailer);
return EFI_SUCCESS;
}
EFI_STATUS pack_cpio(
EFI_LOADED_IMAGE *loaded_image,
const CHAR16 *match_suffix,
const CHAR8 *target_dir_prefix,
UINT32 dir_mode,
UINT32 access_mode,
UINTN tpm_pcr,
const CHAR16 *tpm_description,
VOID **ret_buffer,
UINTN *ret_buffer_size) {
_cleanup_(FileHandleClosep) EFI_FILE_HANDLE root = NULL, extra_dir = NULL;
UINTN dirent_size = 0, buffer_size = 0, n_items = 0, n_allocated = 0;
_cleanup_freepool_ CHAR16 *loaded_image_path = NULL, *j = NULL;
_cleanup_freepool_ EFI_FILE_INFO *dirent = NULL;
_cleanup_(strv_freep) CHAR16 **items = NULL;
_cleanup_freepool_ VOID *buffer = NULL;
UINT32 inode = 1; /* inode counter, so that each item gets a new inode */
EFI_STATUS err;
assert(loaded_image);
assert(target_dir_prefix);
assert(ret_buffer);
assert(ret_buffer_size);
root = LibOpenRoot(loaded_image->DeviceHandle);
if (!root)
return log_error_status_stall(EFI_LOAD_ERROR, L"Unable to open root directory.");
loaded_image_path = DevicePathToStr(loaded_image->FilePath);
if (!loaded_image_path)
return log_oom();
j = PoolPrint(L"%s" EXTRA_DIR_SUFFIX, loaded_image_path);
if (!j)
return log_oom();
err = open_directory(root, j, &extra_dir);
if (err == EFI_NOT_FOUND) {
/* No extra subdir, that's totally OK */
*ret_buffer = NULL;
*ret_buffer_size = 0;
return EFI_SUCCESS;
}
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Failed to open extra directory of loaded image: %r", err);
for (;;) {
_cleanup_freepool_ CHAR16 *d = NULL;
err = readdir_harder(extra_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 (match_suffix && !endswith_no_case(dirent->FileName, match_suffix))
continue;
if (!is_ascii(dirent->FileName))
continue;
if (StrLen(dirent->FileName) > 255) /* Max filename size on Linux */
continue;
d = StrDuplicate(dirent->FileName);
if (!d)
return log_oom();
if (n_items+2 > n_allocated) {
UINTN m;
/* We allocate 16 entries at a time, as a matter of optimization */
if (n_items > (UINTN_MAX / sizeof(UINT16)) - 16) /* Overflow check, just in case */
return log_oom();
m = n_items + 16;
items = ReallocatePool(items, n_allocated * sizeof(UINT16*), m * sizeof(UINT16*));
if (!items)
return log_oom();
n_allocated = m;
}
items[n_items++] = TAKE_PTR(d);
items[n_items] = NULL; /* Let's always NUL terminate, to make freeing via strv_free() easy */
}
if (n_items == 0) {
/* Empty directory */
*ret_buffer = NULL;
*ret_buffer_size = 0;
return EFI_SUCCESS;
}
/* Now, sort the files we found, to make this uniform and stable (and to ensure the TPM measurements
* are not dependent on read order) */
sort_pointer_array((VOID**) items, n_items, (compare_pointer_func_t) StrCmp);
/* Generate the leading directory inodes right before adding the first files, to the
* archive. Otherwise the cpio archive cannot be unpacked, since the leading dirs won't exist. */
err = pack_cpio_prefix(target_dir_prefix, dir_mode, &inode, &buffer, &buffer_size);
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Failed to pack cpio prefix: %r", err);
for (UINTN i = 0; i < n_items; i++) {
_cleanup_freepool_ CHAR8 *content = NULL;
UINTN contentsize;
err = file_read(extra_dir, items[i], 0, 0, &content, &contentsize);
if (EFI_ERROR(err)) {
log_error_status_stall(err, L"Failed to read %s, ignoring: %r", items[i], err);
continue;
}
err = pack_cpio_one(
items[i],
content, contentsize,
target_dir_prefix,
access_mode,
&inode,
&buffer, &buffer_size);
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Failed to pack cpio file %s: %r", dirent->FileName, err);
}
err = pack_cpio_trailer(&buffer, &buffer_size);
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Failed to pack cpio trailer: %r");
#if ENABLE_TPM
err = tpm_log_event(
tpm_pcr,
POINTER_TO_PHYSICAL_ADDRESS(buffer),
buffer_size,
tpm_description);
if (EFI_ERROR(err))
log_error_stall(L"Unable to add initrd TPM measurement for PCR %u (%s), ignoring: %r", tpm_pcr, tpm_description, err);
#endif
*ret_buffer = TAKE_PTR(buffer);
*ret_buffer_size = buffer_size;
return EFI_SUCCESS;
}

View File

@ -1,15 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <efi.h>
EFI_STATUS pack_cpio(
EFI_LOADED_IMAGE *loaded_image,
const CHAR16 *match_suffix,
const CHAR8 *target_dir_prefix,
UINT32 dir_mode,
UINT32 access_mode,
UINTN pcr,
const CHAR16 *tpm_description,
VOID **ret_buffer,
UINTN *ret_buffer_size);

View File

@ -28,6 +28,12 @@ static UINTN devicetree_allocated(const struct devicetree_state *state) {
return state->pages * EFI_PAGE_SIZE;
}
static VOID *devicetree_ptr(const struct devicetree_state *state) {
assert(state);
assert(state->addr <= UINTN_MAX);
return (VOID *)(UINTN)state->addr;
}
static EFI_STATUS devicetree_fixup(struct devicetree_state *state, UINTN len) {
EFI_DT_FIXUP_PROTOCOL *fixup;
UINTN size;
@ -41,24 +47,24 @@ static EFI_STATUS devicetree_fixup(struct devicetree_state *state, UINTN len) {
L"Could not locate device tree fixup protocol, skipping.");
size = devicetree_allocated(state);
err = uefi_call_wrapper(fixup->Fixup, 4, fixup, PHYSICAL_ADDRESS_TO_POINTER(state->addr), &size,
err = uefi_call_wrapper(fixup->Fixup, 4, fixup, devicetree_ptr(state), &size,
EFI_DT_APPLY_FIXUPS | EFI_DT_RESERVE_MEMORY);
if (err == EFI_BUFFER_TOO_SMALL) {
EFI_PHYSICAL_ADDRESS oldaddr = state->addr;
UINTN oldpages = state->pages;
VOID *oldptr = PHYSICAL_ADDRESS_TO_POINTER(state->addr);
VOID *oldptr = devicetree_ptr(state);
err = devicetree_allocate(state, size);
if (EFI_ERROR(err))
return err;
CopyMem(PHYSICAL_ADDRESS_TO_POINTER(state->addr), oldptr, len);
CopyMem(devicetree_ptr(state), oldptr, len);
err = uefi_call_wrapper(BS->FreePages, 2, oldaddr, oldpages);
if (EFI_ERROR(err))
return err;
size = devicetree_allocated(state);
err = uefi_call_wrapper(fixup->Fixup, 4, fixup, PHYSICAL_ADDRESS_TO_POINTER(state->addr), &size,
err = uefi_call_wrapper(fixup->Fixup, 4, fixup, devicetree_ptr(state), &size,
EFI_DT_APPLY_FIXUPS | EFI_DT_RESERVE_MEMORY);
}
@ -85,9 +91,9 @@ EFI_STATUS devicetree_install(struct devicetree_state *state,
if (EFI_ERROR(err))
return err;
err = get_file_info_harder(handle, &info, NULL);
if (EFI_ERROR(err))
return err;
info = LibFileInfo(handle);
if (!info)
return EFI_OUT_OF_RESOURCES;
if (info->FileSize < FDT_V1_SIZE || info->FileSize > 32 * 1024 * 1024)
/* 32MB device tree blob doesn't seem right */
return EFI_INVALID_PARAMETER;
@ -98,7 +104,7 @@ EFI_STATUS devicetree_install(struct devicetree_state *state,
if (EFI_ERROR(err))
return err;
err = uefi_call_wrapper(handle->Read, 3, handle, &len, PHYSICAL_ADDRESS_TO_POINTER(state->addr));
err = uefi_call_wrapper(handle->Read, 3, handle, &len, devicetree_ptr(state));
if (EFI_ERROR(err))
return err;
@ -106,7 +112,7 @@ EFI_STATUS devicetree_install(struct devicetree_state *state,
if (EFI_ERROR(err))
return err;
return uefi_call_wrapper(BS->InstallConfigurationTable, 2, &EfiDtbTableGuid, PHYSICAL_ADDRESS_TO_POINTER(state->addr));
return uefi_call_wrapper(BS->InstallConfigurationTable, 2, &EfiDtbTableGuid, devicetree_ptr(state));
}
void devicetree_cleanup(struct devicetree_state *state) {

View File

@ -1,150 +0,0 @@
/* 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;
}

View File

@ -1,9 +0,0 @@
/* 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);

View File

@ -13,7 +13,6 @@
#endif
typedef VOID(*handover_f)(VOID *image, EFI_SYSTEM_TABLE *table, struct boot_params *params) __regparm0__;
static VOID linux_efi_handover(EFI_HANDLE image, struct boot_params *params) {
handover_f handover;
UINTN start = (UINTN)params->hdr.code32_start;
@ -32,17 +31,16 @@ EFI_STATUS linux_exec(EFI_HANDLE image,
CHAR8 *cmdline, UINTN cmdline_len,
UINTN linux_addr,
UINTN initrd_addr, UINTN initrd_size) {
const struct boot_params *image_params;
struct boot_params *image_params;
struct boot_params *boot_params;
EFI_PHYSICAL_ADDRESS addr;
UINT8 setup_sectors;
EFI_PHYSICAL_ADDRESS addr;
EFI_STATUS err;
assert(image);
assert(cmdline);
image_params = (const struct boot_params *) linux_addr;
image_params = (struct boot_params *) linux_addr;
if (image_params->hdr.boot_flag != 0xAA55 ||
image_params->hdr.header != SETUP_MAGIC ||
@ -50,42 +48,31 @@ EFI_STATUS linux_exec(EFI_HANDLE image,
!image_params->hdr.relocatable_kernel)
return EFI_LOAD_ERROR;
addr = UINT32_MAX; /* Below the 32bit boundary */
err = uefi_call_wrapper(
BS->AllocatePages, 4,
AllocateMaxAddress,
EfiLoaderData,
EFI_SIZE_TO_PAGES(0x4000),
&addr);
boot_params = (struct boot_params *) 0xFFFFFFFF;
err = uefi_call_wrapper(BS->AllocatePages, 4, AllocateMaxAddress, EfiLoaderData,
EFI_SIZE_TO_PAGES(0x4000), (EFI_PHYSICAL_ADDRESS*) &boot_params);
if (EFI_ERROR(err))
return err;
boot_params = (struct boot_params *) PHYSICAL_ADDRESS_TO_POINTER(addr);
ZeroMem(boot_params, 0x4000);
boot_params->hdr = image_params->hdr;
CopyMem(&boot_params->hdr, &image_params->hdr, sizeof(struct setup_header));
boot_params->hdr.type_of_loader = 0xff;
setup_sectors = image_params->hdr.setup_sects > 0 ? image_params->hdr.setup_sects : 4;
boot_params->hdr.code32_start = (UINT32)linux_addr + (setup_sectors + 1) * 512;
if (cmdline) {
addr = 0xA0000;
err = uefi_call_wrapper(
BS->AllocatePages, 4,
AllocateMaxAddress,
EfiLoaderData,
EFI_SIZE_TO_PAGES(cmdline_len + 1),
&addr);
err = uefi_call_wrapper(BS->AllocatePages, 4, AllocateMaxAddress, EfiLoaderData,
EFI_SIZE_TO_PAGES(cmdline_len + 1), &addr);
if (EFI_ERROR(err))
return err;
CopyMem(PHYSICAL_ADDRESS_TO_POINTER(addr), cmdline, cmdline_len);
((CHAR8 *) PHYSICAL_ADDRESS_TO_POINTER(addr))[cmdline_len] = 0;
boot_params->hdr.cmd_line_ptr = (UINT32) addr;
CopyMem((VOID *)(UINTN)addr, cmdline, cmdline_len);
((CHAR8 *)(UINTN)addr)[cmdline_len] = 0;
boot_params->hdr.cmd_line_ptr = (UINT32)addr;
}
boot_params->hdr.ramdisk_image = (UINT32) initrd_addr;
boot_params->hdr.ramdisk_size = (UINT32) initrd_size;
boot_params->hdr.ramdisk_image = (UINT32)initrd_addr;
boot_params->hdr.ramdisk_size = (UINT32)initrd_size;
linux_efi_handover(image, boot_params);
return EFI_LOAD_ERROR;

View File

@ -162,18 +162,4 @@ EFI_STATUS tpm_log_event(UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer, UIN
return EFI_SUCCESS;
}
EFI_STATUS tpm_log_load_options(const CHAR16 *load_options) {
EFI_STATUS err;
/* Measures a load options string into the TPM2, i.e. the kernel command line */
err = tpm_log_event(TPM_PCR_INDEX_KERNEL_PARAMETERS,
POINTER_TO_PHYSICAL_ADDRESS(load_options),
StrSize(load_options), load_options);
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Unable to add load options (i.e. kernel command) line measurement: %r", err);
return EFI_SUCCESS;
}
#endif

View File

@ -3,18 +3,4 @@
#include <efi.h>
#if ENABLE_TPM
EFI_STATUS tpm_log_event(UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description);
EFI_STATUS tpm_log_load_options(const CHAR16 *cmdline);
#else
static inline EFI_STATUS tpm_log_event(UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description) {
return EFI_SUCCESS;
}
static inline EFI_STATUS tpm_log_load_options(const CHAR16 *cmdline) {
return EFI_SUCCESS;
}
#endif

View File

@ -2,10 +2,8 @@
efi_headers = files('''
console.h
cpio.h
devicetree.h
disk.h
drivers.h
graphics.h
linux.h
measure.h
@ -32,7 +30,6 @@ systemd_boot_sources = '''
boot.c
console.c
devicetree.c
drivers.c
random-seed.c
sha256.c
shim.c
@ -42,7 +39,6 @@ stub_sources = '''
linux.c
splash.c
stub.c
cpio.c
'''.split()
if conf.get('ENABLE_EFI') == 1 and get_option('gnu-efi') != 'false'
@ -105,6 +101,7 @@ if have_gnu_efi
efi_conf = configuration_data()
efi_conf.set_quoted('EFI_MACHINE_TYPE_NAME', EFI_MACHINE_TYPE_NAME)
efi_conf.set10('ENABLE_TPM', get_option('tpm'))
efi_conf.set('SD_TPM_PCR', get_option('tpm-pcrindex'))
foreach ctype : ['color-normal', 'color-entry', 'color-highlight', 'color-edit']
c = get_option('efi-' + ctype).split(',')

View File

@ -263,9 +263,9 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir, RandomSeedMode mode) {
return err;
}
err = get_file_info_harder(handle, &info, NULL);
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Failed to get file info for random seed: %r");
info = LibFileInfo(handle);
if (!info)
return log_oom();
size = info->FileSize;
if (size < RANDOM_MAX_SIZE_MIN)

View File

@ -37,13 +37,8 @@ struct bmp_map {
UINT8 reserved;
} _packed_;
static EFI_STATUS bmp_parse_header(
const UINT8 *bmp,
UINTN size,
struct bmp_dib **ret_dib,
struct bmp_map **ret_map,
const UINT8 **pixmap) {
static EFI_STATUS bmp_parse_header(UINT8 *bmp, UINTN size, struct bmp_dib **ret_dib,
struct bmp_map **ret_map, UINT8 **pixmap) {
struct bmp_file *file;
struct bmp_dib *dib;
struct bmp_map *map;
@ -159,13 +154,10 @@ static VOID pixel_blend(UINT32 *dst, const UINT32 source) {
*dst = (rb | g);
}
static EFI_STATUS bmp_to_blt(
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *buf,
struct bmp_dib *dib,
struct bmp_map *map,
const UINT8 *pixmap) {
const UINT8 *in;
static EFI_STATUS bmp_to_blt(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *buf,
struct bmp_dib *dib, struct bmp_map *map,
UINT8 *pixmap) {
UINT8 *in;
assert(buf);
assert(dib);
@ -254,22 +246,19 @@ static EFI_STATUS bmp_to_blt(
return EFI_SUCCESS;
}
EFI_STATUS graphics_splash(const UINT8 *content, UINTN len, const EFI_GRAPHICS_OUTPUT_BLT_PIXEL *background) {
EFI_STATUS graphics_splash(UINT8 *content, UINTN len, const EFI_GRAPHICS_OUTPUT_BLT_PIXEL *background) {
EFI_GRAPHICS_OUTPUT_BLT_PIXEL pixel = {};
static const EFI_GUID GraphicsOutputProtocolGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput = NULL;
struct bmp_dib *dib;
struct bmp_map *map;
const UINT8 *pixmap;
UINT8 *pixmap;
UINT64 blt_size;
_cleanup_freepool_ VOID *blt = NULL;
UINTN x_pos = 0;
UINTN y_pos = 0;
EFI_STATUS err;
if (len == 0)
return EFI_SUCCESS;
assert(content);
if (!background) {

View File

@ -3,4 +3,4 @@
#include <efi.h>
EFI_STATUS graphics_splash(const UINT8 *content, UINTN len, const EFI_GRAPHICS_OUTPUT_BLT_PIXEL *background);
EFI_STATUS graphics_splash(UINT8 *content, UINTN len, const EFI_GRAPHICS_OUTPUT_BLT_PIXEL *background);

View File

@ -3,7 +3,6 @@
#include <efi.h>
#include <efilib.h>
#include "cpio.h"
#include "disk.h"
#include "graphics.h"
#include "linux.h"
@ -16,83 +15,71 @@
/* magic string to find in the binary image */
static const char __attribute__((used)) magic[] = "#### LoaderInfo: systemd-stub " GIT_VERSION " ####";
static EFI_STATUS combine_initrd(
EFI_PHYSICAL_ADDRESS initrd_base, UINTN initrd_size,
const VOID *credential_initrd, UINTN credential_initrd_size,
const VOID *sysext_initrd, UINTN sysext_initrd_size,
EFI_PHYSICAL_ADDRESS *ret_initrd_base, UINTN *ret_initrd_size) {
EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
EFI_LOADED_IMAGE *loaded_image;
EFI_PHYSICAL_ADDRESS base = UINT32_MAX; /* allocate an area below the 32bit boundary for this */
EFI_STATUS err;
UINT8 *p;
UINTN n;
enum {
SECTION_CMDLINE,
SECTION_LINUX,
SECTION_INITRD,
SECTION_SPLASH,
_SECTION_MAX,
};
assert(ret_initrd_base);
assert(ret_initrd_size);
const CHAR8* const sections[] = {
[SECTION_CMDLINE] = (const CHAR8*) ".cmdline",
[SECTION_LINUX] = (const CHAR8*) ".linux",
[SECTION_INITRD] = (const CHAR8*) ".initrd",
[SECTION_SPLASH] = (const CHAR8*) ".splash",
NULL,
};
/* Combines three initrds into one, by simple concatenation in memory */
n = ALIGN_TO(initrd_size, 4); /* main initrd might not be padded yet */
if (credential_initrd) {
if (n > UINTN_MAX - credential_initrd_size)
return EFI_OUT_OF_RESOURCES;
n += credential_initrd_size;
}
if (sysext_initrd) {
if (n > UINTN_MAX - sysext_initrd_size)
return EFI_OUT_OF_RESOURCES;
n += sysext_initrd_size;
}
err = uefi_call_wrapper(
BS->AllocatePages, 4,
AllocateMaxAddress,
EfiLoaderData,
EFI_SIZE_TO_PAGES(n),
&base);
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Failed to allocate space for combined initrd: %r", err);
p = PHYSICAL_ADDRESS_TO_POINTER(base);
if (initrd_base != 0) {
UINTN pad;
/* Order matters, the real initrd must come first, since it might include microcode updates
* which the kernel only looks for in the first cpio archive */
CopyMem(p, PHYSICAL_ADDRESS_TO_POINTER(initrd_base), initrd_size);
p += initrd_size;
pad = ALIGN_TO(initrd_size, 4) - initrd_size;
if (pad > 0) {
ZeroMem(p, pad);
p += pad;
}
}
if (credential_initrd) {
CopyMem(p, credential_initrd, credential_initrd_size);
p += credential_initrd_size;
}
if (sysext_initrd) {
CopyMem(p, sysext_initrd, sysext_initrd_size);
p += sysext_initrd_size;
}
assert((UINT8*) PHYSICAL_ADDRESS_TO_POINTER(base) + n == p);
*ret_initrd_base = base;
*ret_initrd_size = n;
return EFI_SUCCESS;
}
static VOID export_variables(EFI_LOADED_IMAGE *loaded_image) {
EFI_PHYSICAL_ADDRESS linux_base, initrd_base;
UINTN cmdline_len = 0, initrd_size;
UINTN addrs[_SECTION_MAX] = {};
UINTN szs[_SECTION_MAX] = {};
CHAR8 *cmdline = NULL;
CHAR16 uuid[37];
EFI_STATUS err;
assert(loaded_image);
InitializeLib(image, sys_table);
err = uefi_call_wrapper(BS->OpenProtocol, 6, image, &LoadedImageProtocol, (VOID **)&loaded_image,
image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Error getting a LoadedImageProtocol handle: %r", err);
err = pe_memory_locate_sections(loaded_image->ImageBase, (const CHAR8**) sections, addrs, szs);
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Unable to locate embedded .linux section: %r", err);
if (szs[SECTION_CMDLINE] > 0) {
cmdline = (CHAR8*) loaded_image->ImageBase + addrs[SECTION_CMDLINE];
cmdline_len = szs[SECTION_CMDLINE];
}
/* if we are not in secure boot mode, or none was provided, accept a custom command line and replace the built-in one */
if ((!secure_boot_enabled() || cmdline_len == 0) && loaded_image->LoadOptionsSize > 0 &&
*(CHAR16 *) loaded_image->LoadOptions > 0x1F) {
CHAR16 *options;
CHAR8 *line;
options = (CHAR16 *)loaded_image->LoadOptions;
cmdline_len = (loaded_image->LoadOptionsSize / sizeof(CHAR16)) * sizeof(CHAR8);
line = AllocatePool(cmdline_len);
for (UINTN i = 0; i < cmdline_len; i++)
line[i] = options[i];
cmdline = line;
#if ENABLE_TPM
/* Try to log any options to the TPM, especially manually edited options */
err = tpm_log_event(SD_TPM_PCR,
(EFI_PHYSICAL_ADDRESS) (UINTN) loaded_image->LoadOptions,
loaded_image->LoadOptionsSize, loaded_image->LoadOptions);
if (EFI_ERROR(err))
log_error_stall(L"Unable to add image options measurement: %r", err);
#endif
}
/* Export the device path this image is started from, if it's not set yet */
if (efivar_get_raw(LOADER_GUID, L"LoaderDevicePartUUID", NULL, NULL) != EFI_SUCCESS)
@ -132,124 +119,17 @@ static VOID export_variables(EFI_LOADED_IMAGE *loaded_image) {
/* add StubInfo */
if (efivar_get_raw(LOADER_GUID, L"StubInfo", NULL, NULL) != EFI_SUCCESS)
efivar_set(LOADER_GUID, L"StubInfo", L"systemd-stub " GIT_VERSION, 0);
}
EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
if (szs[SECTION_SPLASH] > 0)
graphics_splash((UINT8*) (UINTN) loaded_image->ImageBase + addrs[SECTION_SPLASH], szs[SECTION_SPLASH], NULL);
enum {
SECTION_CMDLINE,
SECTION_LINUX,
SECTION_INITRD,
SECTION_SPLASH,
_SECTION_MAX,
};
const CHAR8* const sections[] = {
[SECTION_CMDLINE] = (const CHAR8*) ".cmdline",
[SECTION_LINUX] = (const CHAR8*) ".linux",
[SECTION_INITRD] = (const CHAR8*) ".initrd",
[SECTION_SPLASH] = (const CHAR8*) ".splash",
NULL,
};
UINTN cmdline_len = 0, initrd_size, credential_initrd_size = 0, sysext_initrd_size = 0;
_cleanup_freepool_ VOID *credential_initrd = NULL, *sysext_initrd = NULL;
EFI_PHYSICAL_ADDRESS linux_base, initrd_base;
EFI_LOADED_IMAGE *loaded_image;
UINTN addrs[_SECTION_MAX] = {};
UINTN szs[_SECTION_MAX] = {};
CHAR8 *cmdline = NULL;
EFI_STATUS err;
InitializeLib(image, sys_table);
err = uefi_call_wrapper(BS->OpenProtocol, 6, image, &LoadedImageProtocol, (VOID **)&loaded_image,
image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Error getting a LoadedImageProtocol handle: %r", err);
err = pe_memory_locate_sections(loaded_image->ImageBase, (const CHAR8**) sections, addrs, szs);
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Unable to locate embedded .linux section: %r", err);
/* Show splash screen as early as possible */
graphics_splash((const UINT8*) loaded_image->ImageBase + addrs[SECTION_SPLASH], szs[SECTION_SPLASH], NULL);
if (szs[SECTION_CMDLINE] > 0) {
cmdline = (CHAR8*) loaded_image->ImageBase + addrs[SECTION_CMDLINE];
cmdline_len = szs[SECTION_CMDLINE];
}
/* if we are not in secure boot mode, or none was provided, accept a custom command line and replace the built-in one */
if ((!secure_boot_enabled() || cmdline_len == 0) && loaded_image->LoadOptionsSize > 0 &&
*(CHAR16 *) loaded_image->LoadOptions > 0x1F) {
CHAR16 *options;
CHAR8 *line;
options = (CHAR16 *)loaded_image->LoadOptions;
cmdline_len = (loaded_image->LoadOptionsSize / sizeof(CHAR16)) * sizeof(CHAR8);
line = AllocatePool(cmdline_len);
for (UINTN i = 0; i < cmdline_len; i++)
line[i] = options[i];
cmdline = line;
/* Let's measure the passed kernel command line into the TPM. Note that this possibly
* duplicates what we already did in the boot menu, if that was already used. However, since
* we want the boot menu to support an EFI binary, and want to this stub to be usable from
* any boot menu, let's measure things anyway. */
(VOID) tpm_log_load_options(loaded_image->LoadOptions);
}
export_variables(loaded_image);
(VOID) pack_cpio(loaded_image,
L".cred",
(const CHAR8*) ".extra/credentials",
/* dir_mode= */ 0500,
/* access_mode= */ 0400,
/* tpm_pcr= */ TPM_PCR_INDEX_KERNEL_PARAMETERS,
L"Credentials initrd",
&credential_initrd,
&credential_initrd_size);
(VOID) pack_cpio(loaded_image,
L".raw",
(const CHAR8*) ".extra/sysext",
/* dir_mode= */ 0555,
/* access_mode= */ 0444,
/* tpm_pcr= */ TPM_PCR_INDEX_INITRD,
L"System extension initrd",
&sysext_initrd,
&sysext_initrd_size);
linux_base = POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[SECTION_LINUX];
linux_base = (EFI_PHYSICAL_ADDRESS) (UINTN) loaded_image->ImageBase + addrs[SECTION_LINUX];
initrd_size = szs[SECTION_INITRD];
initrd_base = initrd_size != 0 ? POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[SECTION_INITRD] : 0;
if (credential_initrd || sysext_initrd) {
/* If we have generated initrds dynamically, let's combine them with the built-in initrd. */
err = combine_initrd(
initrd_base, initrd_size,
credential_initrd, credential_initrd_size,
sysext_initrd, sysext_initrd_size,
&initrd_base, &initrd_size);
if (EFI_ERROR(err))
return err;
/* Given these might be large let's free them explicitly, quickly. */
if (credential_initrd) {
FreePool(credential_initrd);
credential_initrd = NULL;
}
if (sysext_initrd) {
FreePool(sysext_initrd);
sysext_initrd = NULL;
}
}
initrd_base = initrd_size != 0 ? (EFI_PHYSICAL_ADDRESS) (UINTN) loaded_image->ImageBase + addrs[SECTION_INITRD] : 0;
err = linux_exec(image, cmdline, cmdline_len, linux_base, initrd_base, initrd_size);
graphics_mode(FALSE);
return log_error_status_stall(err, L"Execution of embedded linux image failed: %r", err);
}

View File

@ -428,14 +428,11 @@ CHAR16 *stra_to_path(const CHAR8 *stra) {
}
CHAR8 *strchra(const CHAR8 *s, CHAR8 c) {
if (!s)
return NULL;
assert(s);
do {
if (*s == c)
return (CHAR8*) s;
} while (*s++);
return NULL;
}
@ -454,9 +451,9 @@ EFI_STATUS file_read(EFI_FILE_HANDLE dir, const CHAR16 *name, UINTN off, UINTN s
if (size == 0) {
_cleanup_freepool_ EFI_FILE_INFO *info = NULL;
err = get_file_info_harder(handle, &info, NULL);
if (EFI_ERROR(err))
return err;
info = LibFileInfo(handle);
if (!info)
return EFI_OUT_OF_RESOURCES;
size = info->FileSize+1;
}
@ -530,230 +527,3 @@ VOID clear_screen(UINTN attr) {
uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, attr);
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
}
void sort_pointer_array(
VOID **array,
UINTN n_members,
compare_pointer_func_t compare) {
assert(array || n_members == 0);
assert(compare);
if (n_members <= 1)
return;
for (UINTN i = 1; i < n_members; i++) {
BOOLEAN more = FALSE;
for (UINTN k = 0; k < n_members - i; k++) {
void *entry;
if (compare(array[k], array[k+1]) <= 0)
continue;
entry = array[k];
array[k] = array[k+1];
array[k+1] = entry;
more = TRUE;
}
if (!more)
break;
}
}
EFI_STATUS get_file_info_harder(
EFI_FILE_HANDLE handle,
EFI_FILE_INFO **ret,
UINTN *ret_size) {
static const EFI_GUID EfiFileInfoGuid = EFI_FILE_INFO_ID;
UINTN size = OFFSETOF(EFI_FILE_INFO, FileName) + 256;
_cleanup_freepool_ EFI_FILE_INFO *fi = NULL;
EFI_STATUS err;
assert(handle);
assert(ret);
/* A lot like LibFileInfo() but with useful error propagation */
fi = AllocatePool(size);
if (!fi)
return EFI_OUT_OF_RESOURCES;
err = uefi_call_wrapper(handle->GetInfo, 4, handle, (EFI_GUID*) &EfiFileInfoGuid, &size, fi);
if (err == EFI_BUFFER_TOO_SMALL) {
FreePool(fi);
fi = AllocatePool(size); /* GetInfo tells us the required size, let's use that now */
if (!fi)
return EFI_OUT_OF_RESOURCES;
err = uefi_call_wrapper(handle->GetInfo, 4, handle, (EFI_GUID*) &EfiFileInfoGuid, &size, fi);
}
if (EFI_ERROR(err))
return err;
*ret = TAKE_PTR(fi);
if (ret_size)
*ret_size = size;
return EFI_SUCCESS;
}
EFI_STATUS readdir_harder(
EFI_FILE_HANDLE handle,
EFI_FILE_INFO **buffer,
UINTN *buffer_size) {
EFI_STATUS err;
UINTN sz;
assert(handle);
assert(buffer);
assert(buffer_size);
/* buffer/buffer_size are both in and output parameters. Should be zero-initialized initially, and
* the specified buffer needs to be freed by caller, after final use. */
if (!*buffer) {
sz = OFFSETOF(EFI_FILE_INFO, FileName) /* + 256 */;
*buffer = AllocatePool(sz);
if (!*buffer)
return EFI_OUT_OF_RESOURCES;
*buffer_size = sz;
} else
sz = *buffer_size;
err = uefi_call_wrapper(handle->Read, 3, handle, &sz, *buffer);
if (err == EFI_BUFFER_TOO_SMALL) {
FreePool(*buffer);
*buffer = AllocatePool(sz);
if (!*buffer) {
*buffer_size = 0;
return EFI_OUT_OF_RESOURCES;
}
*buffer_size = sz;
err = uefi_call_wrapper(handle->Read, 3, handle, &sz, *buffer);
}
if (EFI_ERROR(err))
return err;
if (sz == 0) {
/* End of directory */
FreePool(*buffer);
*buffer = NULL;
*buffer_size = 0;
}
return EFI_SUCCESS;
}
UINTN strnlena(const CHAR8 *p, UINTN maxlen) {
UINTN c;
if (!p)
return 0;
for (c = 0; c < maxlen; c++)
if (p[c] == 0)
break;
return c;
}
CHAR8 *strndup8(const CHAR8 *p, UINTN sz) {
CHAR8 *n;
/* Following efilib's naming scheme this function would be called strndupa(), but we already have a
* function named like this in userspace, and it does something different there, hence to minimize
* confusion, let's pick a different name here */
assert(p || sz == 0);
sz = strnlena(p, sz);
n = AllocatePool(sz + 1);
if (!n)
return NULL;
if (sz > 0)
CopyMem(n, p, sz);
n[sz] = 0;
return n;
}
BOOLEAN is_ascii(const CHAR16 *f) {
if (!f)
return FALSE;
for (; *f != 0; f++)
if (*f > 127)
return FALSE;
return TRUE;
}
CHAR16 **strv_free(CHAR16 **v) {
if (!v)
return NULL;
for (CHAR16 **i = v; *i; i++)
FreePool(*i);
FreePool(v);
return NULL;
}
EFI_STATUS open_directory(
EFI_FILE_HANDLE root,
const CHAR16 *path,
EFI_FILE_HANDLE *ret) {
_cleanup_(FileHandleClosep) EFI_FILE_HANDLE dir = NULL;
_cleanup_freepool_ EFI_FILE_INFO *file_info = NULL;
EFI_STATUS err;
assert(root);
/* Opens a file, and then verifies it is actually a directory */
err = uefi_call_wrapper(
root->Open, 5,
root,
&dir,
(CHAR16*) path,
EFI_FILE_MODE_READ,
0ULL);
if (EFI_ERROR(err))
return err;
err = get_file_info_harder(dir, &file_info, NULL);
if (EFI_ERROR(err))
return err;
if (!(file_info->Attribute & EFI_FILE_DIRECTORY))
return EFI_LOAD_ERROR;
*ret = TAKE_PTR(dir);
return EFI_SUCCESS;
}
UINT64 get_os_indications_supported(VOID) {
UINT64 osind;
EFI_STATUS err;
/* Returns the supported OS indications. If we can't acquire it, returns a zeroed out mask, i.e. no
* supported features. */
err = efivar_get_uint64_le(EFI_GLOBAL_GUID, L"OsIndicationsSupported", &osind);
if (EFI_ERROR(err))
return 0;
return osind;
}

View File

@ -6,29 +6,10 @@
#include "string-util-fundamental.h"
/* This TPM PCR is where most Linux infrastructure extends the kernel command line into, and so do we. We also extend
* any passed credentials here. */
#define TPM_PCR_INDEX_KERNEL_PARAMETERS 8
/* This TPM PCR is where most Linux infrastructure extends the initrd binary images into, and so do we. */
#define TPM_PCR_INDEX_INITRD 4
#define OFFSETOF(x,y) __builtin_offsetof(x,y)
#define UINTN_MAX (~(UINTN)0)
#define INTN_MAX ((INTN)(UINTN_MAX>>1))
#ifndef UINT32_MAX
#define UINT32_MAX ((UINT32) -1)
#endif
#ifndef UINT64_MAX
#define UINT64_MAX ((UINT64) -1)
#endif
static inline UINTN ALIGN_TO(UINTN l, UINTN ali) {
if (l > UINTN_MAX - (ali - 1)) /* Overflow? */
return UINTN_MAX;
return ((l + (ali - 1)) & ~(ali - 1));
return ((l + ali - 1) & ~(ali - 1));
}
EFI_STATUS parse_boolean(const CHAR8 *v, BOOLEAN *b);
@ -84,6 +65,15 @@ static inline void FileHandleClosep(EFI_FILE_HANDLE *handle) {
&(const EFI_GUID) { 0x4a67b082, 0x0a4c, 0x41cf, { 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f } }
#define EFI_GLOBAL_GUID &(const EFI_GUID) EFI_GLOBAL_VARIABLE
#define UINTN_MAX (~(UINTN)0)
#define INTN_MAX ((INTN)(UINTN_MAX>>1))
#ifndef UINT32_MAX
#define UINT32_MAX ((UINT32) -1)
#endif
#ifndef UINT64_MAX
#define UINT64_MAX ((UINT64) -1)
#endif
VOID log_error_stall(const CHAR16 *fmt, ...);
EFI_STATUS log_oom(void);
@ -104,45 +94,3 @@ static inline VOID *mempmem_safe(const VOID *haystack, UINTN haystack_len, const
VOID print_at(UINTN x, UINTN y, UINTN attr, const CHAR16 *str);
VOID clear_screen(UINTN attr);
typedef INTN (*compare_pointer_func_t)(const VOID *a, const VOID *b);
void sort_pointer_array(VOID **array, UINTN n_members, compare_pointer_func_t compare);
EFI_STATUS get_file_info_harder(EFI_FILE_HANDLE handle, EFI_FILE_INFO **ret, UINTN *ret_size);
EFI_STATUS readdir_harder(EFI_FILE_HANDLE handle, EFI_FILE_INFO **buffer, UINTN *buffer_size);
UINTN strnlena(const CHAR8 *p, UINTN maxlen);
CHAR8 *strndup8(const CHAR8 *p, UINTN sz);
BOOLEAN is_ascii(const CHAR16 *f);
CHAR16 **strv_free(CHAR16 **l);
static inline void strv_freep(CHAR16 ***p) {
strv_free(*p);
}
EFI_STATUS open_directory(EFI_FILE_HANDLE root_dir, const CHAR16 *path, EFI_FILE_HANDLE *ret);
/* Conversion between EFI_PHYSICAL_ADDRESS and pointers is not obvious. The former is always 64bit, even on
* 32bit archs. And gcc complains if we cast a pointer to an integer of a different size. Hence let's do the
* conversion indirectly: first into UINTN (which is defined by UEFI to have the same size as a pointer), and
* then extended to EFI_PHYSICAL_ADDRESS. */
static inline EFI_PHYSICAL_ADDRESS POINTER_TO_PHYSICAL_ADDRESS(const void *p) {
return (EFI_PHYSICAL_ADDRESS) (UINTN) p;
}
static inline void *PHYSICAL_ADDRESS_TO_POINTER(EFI_PHYSICAL_ADDRESS addr) {
#if __SIZEOF_POINTER__ == 4
/* On 32bit systems the address might not be convertible (as pointers are 32bit but
* EFI_PHYSICAL_ADDRESS 64bit) */
assert(addr <= UINT32_MAX);
#elif __SIZEOF_POINTER__ != 8
#error "Unexpected pointer size"
#endif
return (void*) (UINTN) addr;
}
UINT64 get_os_indications_supported(VOID);

View File

@ -12,4 +12,3 @@
#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)

View File

@ -286,13 +286,14 @@ int mac_smack_copy(const char *dest, const char *src) {
#endif
int rename_and_apply_smack_floor_label(const char *from, const char *to) {
int r = 0;
if (rename(from, to) < 0)
return -errno;
#if HAVE_SMACK_RUN_LABEL
return mac_smack_apply(to, SMACK_ATTR_ACCESS, SMACK_FLOOR_LABEL);
#else
return 0;
r = mac_smack_apply(to, SMACK_ATTR_ACCESS, SMACK_FLOOR_LABEL);
if (r < 0)
return r;
#endif
return r;
}