mirror of
https://github.com/systemd/systemd
synced 2026-03-28 17:54:51 +01:00
Compare commits
30 Commits
cf7c7512f5
...
37eb7108fb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
37eb7108fb | ||
|
|
f7c9ade22f | ||
|
|
8e8415e0d5 | ||
|
|
99d51ed939 | ||
|
|
b8cdb66279 | ||
|
|
3f9a615dcf | ||
|
|
3a6249127e | ||
|
|
0d43ce5266 | ||
|
|
a0a644be70 | ||
|
|
61b6249552 | ||
|
|
ef6ff81a53 | ||
|
|
19c896e99c | ||
|
|
4cbecde937 | ||
|
|
77c015820c | ||
|
|
2553a5482c | ||
|
|
d72f81be74 | ||
|
|
0be2a06ac7 | ||
|
|
6e161dc860 | ||
|
|
94b81afb08 | ||
|
|
5a186322a1 | ||
|
|
e6e24af507 | ||
|
|
faacf1807e | ||
|
|
845707aae2 | ||
|
|
80b2f4d92c | ||
|
|
c6dfe36044 | ||
|
|
88657f7575 | ||
|
|
3fc0688d42 | ||
|
|
a02c1239cc | ||
|
|
26d54e1263 | ||
|
|
4db9e01f7f |
8
TODO
8
TODO
@ -83,6 +83,14 @@ 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.
|
||||
|
||||
@ -309,10 +309,12 @@ 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 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.
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
@ -954,6 +954,10 @@ 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',
|
||||
|
||||
@ -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 graphical menu to select the entry to boot and an editor for the kernel command
|
||||
manager. It provides a textual 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,6 +102,12 @@
|
||||
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>
|
||||
@ -274,25 +280,37 @@
|
||||
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. <command>systemd-boot</command> reads runtime configuration such as the boot timeout and default
|
||||
exists.</para>
|
||||
|
||||
<para><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>. 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
|
||||
<citerefentry><refentrytitle>loader.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
|
||||
|
||||
<para>Boot entry description files 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. Optionally, a random
|
||||
seed for early boot entropy pool provisioning is stored in <filename>/loader/random-seed</filename> in
|
||||
the ESP.</para>
|
||||
<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>
|
||||
</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 OS and the boot
|
||||
loader:</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 boot
|
||||
loader and the OS:</para>
|
||||
|
||||
<variablelist class='efi-variables'>
|
||||
<varlistentry>
|
||||
@ -493,6 +511,7 @@
|
||||
<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>
|
||||
|
||||
204
man/systemd-stub.xml
Normal file
204
man/systemd-stub.xml
Normal file
@ -0,0 +1,204 @@
|
||||
<?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>
|
||||
@ -1636,8 +1636,6 @@ 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
|
||||
|
||||
@ -416,8 +416,6 @@ 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,
|
||||
|
||||
@ -14,7 +14,7 @@ InstallDirectory=mkosi.installdir
|
||||
SourceFileTransferFinal=copy-git-others
|
||||
|
||||
[Host]
|
||||
QemuHeadless=yes
|
||||
QemuHeadless=no
|
||||
NetworkVeth=yes
|
||||
|
||||
[Validation]
|
||||
|
||||
@ -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 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* use the next one */
|
||||
@ -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;
|
||||
|
||||
@ -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"
|
||||
@ -366,7 +367,7 @@ static UINTN entry_lookup_key(Config *config, UINTN start, CHAR16 key) {
|
||||
}
|
||||
|
||||
static VOID print_status(Config *config, CHAR16 *loaded_image_path) {
|
||||
UINT64 key, indvar;
|
||||
UINT64 key;
|
||||
UINTN timeout;
|
||||
BOOLEAN modevar;
|
||||
_cleanup_freepool_ CHAR16 *partstr = NULL, *defaultstr = NULL;
|
||||
@ -394,8 +395,7 @@ static VOID print_status(Config *config, CHAR16 *loaded_image_path) {
|
||||
if (shim_loaded())
|
||||
Print(L"Shim: present\n");
|
||||
|
||||
if (efivar_get_uint64_le(EFI_GLOBAL_GUID, L"OsIndicationsSupported", &indvar) == EFI_SUCCESS)
|
||||
Print(L"OsIndicationsSupported: %d\n", indvar);
|
||||
Print(L"OsIndicationsSupported: %d\n", get_os_indications_supported());
|
||||
|
||||
Print(L"\n--- press key ---\n\n");
|
||||
console_key_read(&key, 0);
|
||||
@ -517,7 +517,8 @@ 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, *status = NULL, *clearline = NULL;
|
||||
CHAR16 **lines = NULL;
|
||||
_cleanup_freepool_ CHAR16 *clearline = NULL, *status = NULL;
|
||||
UINTN timeout_remain = config->timeout_sec;
|
||||
INT16 idx;
|
||||
BOOLEAN exit = FALSE, run = TRUE;
|
||||
@ -901,7 +902,6 @@ 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, a, b;
|
||||
UINTN file_info_size;
|
||||
EFI_STATUS r;
|
||||
|
||||
assert(entry);
|
||||
@ -1243,26 +1243,9 @@ static VOID config_entry_bump_counters(
|
||||
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);
|
||||
}
|
||||
r = get_file_info_harder(handle, &file_info, &file_info_size);
|
||||
if (EFI_ERROR(r))
|
||||
return;
|
||||
|
||||
/* And rename the file */
|
||||
StrCpy(file_info->FileName, entry->next_name);
|
||||
@ -1487,9 +1470,11 @@ static VOID config_load_entries(
|
||||
Config *config,
|
||||
EFI_HANDLE *device,
|
||||
EFI_FILE *root_dir,
|
||||
CHAR16 *loaded_image_path) {
|
||||
const 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);
|
||||
@ -1497,22 +1482,17 @@ static VOID config_load_entries(
|
||||
assert(root_dir);
|
||||
assert(loaded_image_path);
|
||||
|
||||
err = uefi_call_wrapper(root_dir->Open, 5, root_dir, &entries_dir, (CHAR16*) L"\\loader\\entries", EFI_FILE_MODE_READ, 0ULL);
|
||||
err = open_directory(root_dir, L"\\loader\\entries", &entries_dir);
|
||||
if (EFI_ERROR(err))
|
||||
return;
|
||||
|
||||
for (;;) {
|
||||
CHAR16 buf[256];
|
||||
UINTN bufsize;
|
||||
EFI_FILE_INFO *f;
|
||||
_cleanup_freepool_ CHAR8 *content = NULL;
|
||||
|
||||
bufsize = sizeof(buf);
|
||||
err = uefi_call_wrapper(entries_dir->Read, 3, entries_dir, &bufsize, buf);
|
||||
if (bufsize == 0 || EFI_ERROR(err))
|
||||
err = readdir_harder(entries_dir, &f, &f_size);
|
||||
if (f_size == 0 || EFI_ERROR(err))
|
||||
break;
|
||||
|
||||
f = (EFI_FILE_INFO *) buf;
|
||||
if (f->FileName[0] == '.')
|
||||
continue;
|
||||
if (f->Attribute & EFI_FILE_DIRECTORY)
|
||||
@ -1529,7 +1509,7 @@ static VOID config_load_entries(
|
||||
}
|
||||
}
|
||||
|
||||
static INTN config_entry_compare(ConfigEntry *a, ConfigEntry *b) {
|
||||
static INTN config_entry_compare(const ConfigEntry *a, const ConfigEntry *b) {
|
||||
INTN r;
|
||||
|
||||
assert(a);
|
||||
@ -1567,24 +1547,7 @@ static INTN config_entry_compare(ConfigEntry *a, ConfigEntry *b) {
|
||||
static VOID config_sort_entries(Config *config) {
|
||||
assert(config);
|
||||
|
||||
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;
|
||||
}
|
||||
sort_pointer_array((void**) config->entries, config->entry_count, (compare_pointer_func_t) config_entry_compare);
|
||||
}
|
||||
|
||||
static INTN config_entry_find(Config *config, CHAR16 *id) {
|
||||
@ -1978,21 +1941,23 @@ static VOID config_entry_add_linux(
|
||||
EFI_FILE *root_dir) {
|
||||
|
||||
_cleanup_(FileHandleClosep) EFI_FILE_HANDLE linux_dir = NULL;
|
||||
EFI_STATUS err;
|
||||
_cleanup_freepool_ EFI_FILE_INFO *f = NULL;
|
||||
ConfigEntry *entry;
|
||||
UINTN f_size = 0;
|
||||
EFI_STATUS err;
|
||||
|
||||
assert(config);
|
||||
assert(device);
|
||||
assert(root_dir);
|
||||
|
||||
err = uefi_call_wrapper(root_dir->Open, 5, root_dir, &linux_dir, (CHAR16*) L"\\EFI\\Linux", EFI_FILE_MODE_READ, 0ULL);
|
||||
err = open_directory(root_dir, L"\\EFI\\Linux", &linux_dir);
|
||||
if (EFI_ERROR(err))
|
||||
return;
|
||||
|
||||
for (;;) {
|
||||
CHAR16 buf[256];
|
||||
UINTN bufsize = sizeof buf;
|
||||
EFI_FILE_INFO *f;
|
||||
_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;
|
||||
const CHAR8 *sections[] = {
|
||||
(CHAR8 *)".osrel",
|
||||
(CHAR8 *)".cmdline",
|
||||
@ -2000,22 +1965,14 @@ 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 = uefi_call_wrapper(linux_dir->Read, 3, linux_dir, &bufsize, buf);
|
||||
if (bufsize == 0 || EFI_ERROR(err))
|
||||
err = readdir_harder(linux_dir, &f, &f_size);
|
||||
if (f_size == 0 || EFI_ERROR(err))
|
||||
break;
|
||||
|
||||
f = (EFI_FILE_INFO *) buf;
|
||||
if (f->FileName[0] == '.')
|
||||
continue;
|
||||
if (f->Attribute & EFI_FILE_DIRECTORY)
|
||||
@ -2071,16 +2028,28 @@ 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_version || os_version_id || os_build_id)) {
|
||||
if ((os_name_pretty || os_name) && os_id && (os_image_version || 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, 'l',
|
||||
os_name_pretty ?: os_name, path,
|
||||
os_version ?: (os_version_id ? : os_build_id));
|
||||
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)));
|
||||
|
||||
FreePool(content);
|
||||
content = NULL;
|
||||
@ -2098,14 +2067,6 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2364,14 +2325,8 @@ 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 */
|
||||
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
|
||||
(VOID) tpm_log_load_options(options);
|
||||
}
|
||||
|
||||
efivar_set_time_usec(LOADER_GUID, L"LoaderTimeExecUSec", 0);
|
||||
@ -2436,7 +2391,11 @@ static VOID config_write_entries_to_variable(Config *config) {
|
||||
(void) efivar_set_raw(LOADER_GUID, L"LoaderEntries", buffer, sz, 0);
|
||||
}
|
||||
|
||||
EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
static VOID export_variables(
|
||||
EFI_LOADED_IMAGE *loaded_image,
|
||||
const CHAR16 *loaded_image_path,
|
||||
UINT64 init_usec) {
|
||||
|
||||
static const UINT64 loader_features =
|
||||
EFI_LOADER_FEATURE_CONFIG_TIMEOUT |
|
||||
EFI_LOADER_FEATURE_CONFIG_TIMEOUT_ONE_SHOT |
|
||||
@ -2445,21 +2404,15 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
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];
|
||||
|
||||
InitializeLib(image, sys_table);
|
||||
init_usec = time_usec();
|
||||
assert(loaded_image);
|
||||
assert(loaded_image_path);
|
||||
|
||||
efivar_set_time_usec(LOADER_GUID, L"LoaderTimeInitUSec", init_usec);
|
||||
efivar_set(LOADER_GUID, L"LoaderInfo", L"systemd-boot " GIT_VERSION, 0);
|
||||
|
||||
@ -2471,14 +2424,82 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
|
||||
(void) efivar_set_uint64_le(LOADER_GUID, L"LoaderFeatures", loader_features, 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);
|
||||
/* the filesystem path to this image, to prevent adding ourselves to the menu */
|
||||
efivar_set(LOADER_GUID, L"LoaderImageIdentifier", loaded_image_path, 0);
|
||||
|
||||
/* 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)
|
||||
@ -2490,39 +2511,9 @@ 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);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
(VOID) load_drivers(image, loaded_image, 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);
|
||||
}
|
||||
config_load_all_entries(&config, loaded_image, loaded_image_path, root_dir);
|
||||
|
||||
if (config.entry_count == 0) {
|
||||
log_error_stall(L"No loader found. Configuration files in \\loader\\entries\\*.conf are needed.");
|
||||
@ -2601,9 +2592,7 @@ 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;
|
||||
}
|
||||
|
||||
466
src/boot/efi/cpio.c
Normal file
466
src/boot/efi/cpio.c
Normal file
@ -0,0 +1,466 @@
|
||||
/* 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;
|
||||
}
|
||||
15
src/boot/efi/cpio.h
Normal file
15
src/boot/efi/cpio.h
Normal file
@ -0,0 +1,15 @@
|
||||
/* 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);
|
||||
@ -28,12 +28,6 @@ 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;
|
||||
@ -47,24 +41,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, devicetree_ptr(state), &size,
|
||||
err = uefi_call_wrapper(fixup->Fixup, 4, fixup, PHYSICAL_ADDRESS_TO_POINTER(state->addr), &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 = devicetree_ptr(state);
|
||||
VOID *oldptr = PHYSICAL_ADDRESS_TO_POINTER(state->addr);
|
||||
|
||||
err = devicetree_allocate(state, size);
|
||||
if (EFI_ERROR(err))
|
||||
return err;
|
||||
|
||||
CopyMem(devicetree_ptr(state), oldptr, len);
|
||||
CopyMem(PHYSICAL_ADDRESS_TO_POINTER(state->addr), 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, devicetree_ptr(state), &size,
|
||||
err = uefi_call_wrapper(fixup->Fixup, 4, fixup, PHYSICAL_ADDRESS_TO_POINTER(state->addr), &size,
|
||||
EFI_DT_APPLY_FIXUPS | EFI_DT_RESERVE_MEMORY);
|
||||
}
|
||||
|
||||
@ -91,9 +85,9 @@ EFI_STATUS devicetree_install(struct devicetree_state *state,
|
||||
if (EFI_ERROR(err))
|
||||
return err;
|
||||
|
||||
info = LibFileInfo(handle);
|
||||
if (!info)
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
err = get_file_info_harder(handle, &info, NULL);
|
||||
if (EFI_ERROR(err))
|
||||
return err;
|
||||
if (info->FileSize < FDT_V1_SIZE || info->FileSize > 32 * 1024 * 1024)
|
||||
/* 32MB device tree blob doesn't seem right */
|
||||
return EFI_INVALID_PARAMETER;
|
||||
@ -104,7 +98,7 @@ EFI_STATUS devicetree_install(struct devicetree_state *state,
|
||||
if (EFI_ERROR(err))
|
||||
return err;
|
||||
|
||||
err = uefi_call_wrapper(handle->Read, 3, handle, &len, devicetree_ptr(state));
|
||||
err = uefi_call_wrapper(handle->Read, 3, handle, &len, PHYSICAL_ADDRESS_TO_POINTER(state->addr));
|
||||
if (EFI_ERROR(err))
|
||||
return err;
|
||||
|
||||
@ -112,7 +106,7 @@ EFI_STATUS devicetree_install(struct devicetree_state *state,
|
||||
if (EFI_ERROR(err))
|
||||
return err;
|
||||
|
||||
return uefi_call_wrapper(BS->InstallConfigurationTable, 2, &EfiDtbTableGuid, devicetree_ptr(state));
|
||||
return uefi_call_wrapper(BS->InstallConfigurationTable, 2, &EfiDtbTableGuid, PHYSICAL_ADDRESS_TO_POINTER(state->addr));
|
||||
}
|
||||
|
||||
void devicetree_cleanup(struct devicetree_state *state) {
|
||||
|
||||
150
src/boot/efi/drivers.c
Normal file
150
src/boot/efi/drivers.c
Normal 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
src/boot/efi/drivers.h
Normal file
9
src/boot/efi/drivers.h
Normal 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);
|
||||
@ -13,6 +13,7 @@
|
||||
#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;
|
||||
@ -31,16 +32,17 @@ EFI_STATUS linux_exec(EFI_HANDLE image,
|
||||
CHAR8 *cmdline, UINTN cmdline_len,
|
||||
UINTN linux_addr,
|
||||
UINTN initrd_addr, UINTN initrd_size) {
|
||||
struct boot_params *image_params;
|
||||
|
||||
const struct boot_params *image_params;
|
||||
struct boot_params *boot_params;
|
||||
UINT8 setup_sectors;
|
||||
EFI_PHYSICAL_ADDRESS addr;
|
||||
UINT8 setup_sectors;
|
||||
EFI_STATUS err;
|
||||
|
||||
assert(image);
|
||||
assert(cmdline);
|
||||
|
||||
image_params = (struct boot_params *) linux_addr;
|
||||
image_params = (const struct boot_params *) linux_addr;
|
||||
|
||||
if (image_params->hdr.boot_flag != 0xAA55 ||
|
||||
image_params->hdr.header != SETUP_MAGIC ||
|
||||
@ -48,31 +50,42 @@ EFI_STATUS linux_exec(EFI_HANDLE image,
|
||||
!image_params->hdr.relocatable_kernel)
|
||||
return EFI_LOAD_ERROR;
|
||||
|
||||
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);
|
||||
addr = UINT32_MAX; /* Below the 32bit boundary */
|
||||
err = uefi_call_wrapper(
|
||||
BS->AllocatePages, 4,
|
||||
AllocateMaxAddress,
|
||||
EfiLoaderData,
|
||||
EFI_SIZE_TO_PAGES(0x4000),
|
||||
&addr);
|
||||
if (EFI_ERROR(err))
|
||||
return err;
|
||||
|
||||
boot_params = (struct boot_params *) PHYSICAL_ADDRESS_TO_POINTER(addr);
|
||||
ZeroMem(boot_params, 0x4000);
|
||||
CopyMem(&boot_params->hdr, &image_params->hdr, sizeof(struct setup_header));
|
||||
boot_params->hdr = image_params->hdr;
|
||||
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((VOID *)(UINTN)addr, cmdline, cmdline_len);
|
||||
((CHAR8 *)(UINTN)addr)[cmdline_len] = 0;
|
||||
boot_params->hdr.cmd_line_ptr = (UINT32)addr;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@ -162,4 +162,18 @@ 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
|
||||
|
||||
@ -3,4 +3,18 @@
|
||||
|
||||
#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
|
||||
|
||||
@ -2,8 +2,10 @@
|
||||
|
||||
efi_headers = files('''
|
||||
console.h
|
||||
cpio.h
|
||||
devicetree.h
|
||||
disk.h
|
||||
drivers.h
|
||||
graphics.h
|
||||
linux.h
|
||||
measure.h
|
||||
@ -30,6 +32,7 @@ systemd_boot_sources = '''
|
||||
boot.c
|
||||
console.c
|
||||
devicetree.c
|
||||
drivers.c
|
||||
random-seed.c
|
||||
sha256.c
|
||||
shim.c
|
||||
@ -39,6 +42,7 @@ stub_sources = '''
|
||||
linux.c
|
||||
splash.c
|
||||
stub.c
|
||||
cpio.c
|
||||
'''.split()
|
||||
|
||||
if conf.get('ENABLE_EFI') == 1 and get_option('gnu-efi') != 'false'
|
||||
@ -101,7 +105,6 @@ 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(',')
|
||||
|
||||
@ -263,9 +263,9 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir, RandomSeedMode mode) {
|
||||
return err;
|
||||
}
|
||||
|
||||
info = LibFileInfo(handle);
|
||||
if (!info)
|
||||
return log_oom();
|
||||
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");
|
||||
|
||||
size = info->FileSize;
|
||||
if (size < RANDOM_MAX_SIZE_MIN)
|
||||
|
||||
@ -37,8 +37,13 @@ struct bmp_map {
|
||||
UINT8 reserved;
|
||||
} _packed_;
|
||||
|
||||
static EFI_STATUS bmp_parse_header(UINT8 *bmp, UINTN size, struct bmp_dib **ret_dib,
|
||||
struct bmp_map **ret_map, UINT8 **pixmap) {
|
||||
static EFI_STATUS bmp_parse_header(
|
||||
const UINT8 *bmp,
|
||||
UINTN size,
|
||||
struct bmp_dib **ret_dib,
|
||||
struct bmp_map **ret_map,
|
||||
const UINT8 **pixmap) {
|
||||
|
||||
struct bmp_file *file;
|
||||
struct bmp_dib *dib;
|
||||
struct bmp_map *map;
|
||||
@ -154,10 +159,13 @@ 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,
|
||||
UINT8 *pixmap) {
|
||||
UINT8 *in;
|
||||
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;
|
||||
|
||||
assert(buf);
|
||||
assert(dib);
|
||||
@ -246,19 +254,22 @@ static EFI_STATUS bmp_to_blt(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *buf,
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS graphics_splash(UINT8 *content, UINTN len, const EFI_GRAPHICS_OUTPUT_BLT_PIXEL *background) {
|
||||
EFI_STATUS graphics_splash(const 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;
|
||||
UINT8 *pixmap;
|
||||
const 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) {
|
||||
|
||||
@ -3,4 +3,4 @@
|
||||
|
||||
#include <efi.h>
|
||||
|
||||
EFI_STATUS graphics_splash(UINT8 *content, UINTN len, const EFI_GRAPHICS_OUTPUT_BLT_PIXEL *background);
|
||||
EFI_STATUS graphics_splash(const UINT8 *content, UINTN len, const EFI_GRAPHICS_OUTPUT_BLT_PIXEL *background);
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
#include <efi.h>
|
||||
#include <efilib.h>
|
||||
|
||||
#include "cpio.h"
|
||||
#include "disk.h"
|
||||
#include "graphics.h"
|
||||
#include "linux.h"
|
||||
@ -15,72 +16,84 @@
|
||||
/* magic string to find in the binary image */
|
||||
static const char __attribute__((used)) magic[] = "#### LoaderInfo: systemd-stub " GIT_VERSION " ####";
|
||||
|
||||
EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
EFI_LOADED_IMAGE *loaded_image;
|
||||
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) {
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
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_PHYSICAL_ADDRESS base = UINT32_MAX; /* allocate an area below the 32bit boundary for this */
|
||||
EFI_STATUS err;
|
||||
UINT8 *p;
|
||||
UINTN n;
|
||||
|
||||
InitializeLib(image, sys_table);
|
||||
assert(ret_initrd_base);
|
||||
assert(ret_initrd_size);
|
||||
|
||||
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);
|
||||
/* Combines three initrds into one, by simple concatenation in memory */
|
||||
|
||||
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);
|
||||
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;
|
||||
|
||||
if (szs[SECTION_CMDLINE] > 0) {
|
||||
cmdline = (CHAR8*) loaded_image->ImageBase + addrs[SECTION_CMDLINE];
|
||||
cmdline_len = szs[SECTION_CMDLINE];
|
||||
n += credential_initrd_size;
|
||||
}
|
||||
if (sysext_initrd) {
|
||||
if (n > UINTN_MAX - sysext_initrd_size)
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
|
||||
n += sysext_initrd_size;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
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);
|
||||
|
||||
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;
|
||||
p = PHYSICAL_ADDRESS_TO_POINTER(base);
|
||||
if (initrd_base != 0) {
|
||||
UINTN pad;
|
||||
|
||||
#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
|
||||
/* 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) {
|
||||
CHAR16 uuid[37];
|
||||
|
||||
assert(loaded_image);
|
||||
|
||||
/* 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)
|
||||
if (disk_get_part_uuid(loaded_image->DeviceHandle, uuid) == EFI_SUCCESS)
|
||||
@ -119,17 +132,124 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
/* 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);
|
||||
}
|
||||
|
||||
if (szs[SECTION_SPLASH] > 0)
|
||||
graphics_splash((UINT8*) (UINTN) loaded_image->ImageBase + addrs[SECTION_SPLASH], szs[SECTION_SPLASH], NULL);
|
||||
EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
|
||||
linux_base = (EFI_PHYSICAL_ADDRESS) (UINTN) loaded_image->ImageBase + addrs[SECTION_LINUX];
|
||||
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];
|
||||
|
||||
initrd_size = szs[SECTION_INITRD];
|
||||
initrd_base = initrd_size != 0 ? (EFI_PHYSICAL_ADDRESS) (UINTN) loaded_image->ImageBase + addrs[SECTION_INITRD] : 0;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -428,11 +428,14 @@ CHAR16 *stra_to_path(const CHAR8 *stra) {
|
||||
}
|
||||
|
||||
CHAR8 *strchra(const CHAR8 *s, CHAR8 c) {
|
||||
assert(s);
|
||||
if (!s)
|
||||
return NULL;
|
||||
|
||||
do {
|
||||
if (*s == c)
|
||||
return (CHAR8*) s;
|
||||
} while (*s++);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -451,9 +454,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;
|
||||
|
||||
info = LibFileInfo(handle);
|
||||
if (!info)
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
err = get_file_info_harder(handle, &info, NULL);
|
||||
if (EFI_ERROR(err))
|
||||
return err;
|
||||
|
||||
size = info->FileSize+1;
|
||||
}
|
||||
@ -527,3 +530,230 @@ 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;
|
||||
}
|
||||
|
||||
@ -6,10 +6,29 @@
|
||||
|
||||
#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) {
|
||||
return ((l + ali - 1) & ~(ali - 1));
|
||||
if (l > UINTN_MAX - (ali - 1)) /* Overflow? */
|
||||
return UINTN_MAX;
|
||||
|
||||
return ((l + (ali - 1)) & ~(ali - 1));
|
||||
}
|
||||
|
||||
EFI_STATUS parse_boolean(const CHAR8 *v, BOOLEAN *b);
|
||||
@ -65,15 +84,6 @@ 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);
|
||||
|
||||
@ -94,3 +104,45 @@ 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);
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -286,14 +286,13 @@ 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
|
||||
r = mac_smack_apply(to, SMACK_ATTR_ACCESS, SMACK_FLOOR_LABEL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return mac_smack_apply(to, SMACK_ATTR_ACCESS, SMACK_FLOOR_LABEL);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user