mirror of
https://github.com/systemd/systemd
synced 2026-03-29 03:04:52 +02: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:
|
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 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
|
in EFI var. then use this when enrolling TPM2 in cryptsetup to verify that
|
||||||
the selected PCRs actually are used by firmware.
|
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
|
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,
|
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
|
as you start your first managed process (a container, for example) you would
|
||||||
unit would have `Delegate=` turned on, and then you place all your
|
register a new scope unit with systemd, and that scope unit would have
|
||||||
containers underneath it. From systemd's PoV there'd be two units: your
|
`Delegate=` turned on, and it would contain the PID of this process; all
|
||||||
manager service and the big scope that contains all your containers in one.
|
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
|
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
|
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-sleep.conf', '5', ['sleep.conf.d'], ''],
|
||||||
['systemd-socket-activate', '1', [], ''],
|
['systemd-socket-activate', '1', [], ''],
|
||||||
['systemd-socket-proxyd', '8', [], ''],
|
['systemd-socket-proxyd', '8', [], ''],
|
||||||
|
['systemd-stub',
|
||||||
|
'7',
|
||||||
|
['linuxaa64.efi.stub', 'linuxia32.efi.stub', 'linuxx64.efi.stub'],
|
||||||
|
'ENABLE_EFI'],
|
||||||
['systemd-suspend.service',
|
['systemd-suspend.service',
|
||||||
'8',
|
'8',
|
||||||
['systemd-hibernate.service',
|
['systemd-hibernate.service',
|
||||||
|
|||||||
@ -25,7 +25,7 @@
|
|||||||
<title>Description</title>
|
<title>Description</title>
|
||||||
|
|
||||||
<para><command>systemd-boot</command> (short: <command>sd-boot</command>) is a simple UEFI boot
|
<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>
|
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),
|
<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
|
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
|
description files compliant with the Boot Loader
|
||||||
Specification.</para>
|
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>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
@ -274,25 +280,37 @@
|
|||||||
usually mounted to <filename>/efi/</filename>, <filename>/boot/</filename> or
|
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
|
<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
|
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
|
entry from <filename>/loader/loader.conf</filename> on the ESP (in combination with data read from EFI
|
||||||
variables). See
|
variables). See
|
||||||
<citerefentry><refentrytitle>loader.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>. Boot
|
<citerefentry><refentrytitle>loader.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
|
||||||
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
|
<para>Boot entry description files following the <ulink
|
||||||
Extended Boot Loader partition. Unified kernel boot entries following the <ulink
|
|
||||||
url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink> are read from
|
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
|
<filename>/loader/entries/</filename> on the ESP and the Extended Boot Loader partition.</para>
|
||||||
seed for early boot entropy pool provisioning is stored in <filename>/loader/random-seed</filename> in
|
|
||||||
the ESP.</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>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
<title>EFI Variables</title>
|
<title>EFI Variables</title>
|
||||||
|
|
||||||
<para>The following EFI variables are defined, set and read by <command>systemd-boot</command>, under the vendor
|
<para>The following EFI variables are defined, set and read by <command>systemd-boot</command>, under the
|
||||||
UUID <literal>4a67b082-0a4c-41cf-b6c7-440b29bb8c4f</literal>, for communication between the OS and the boot
|
vendor UUID <literal>4a67b082-0a4c-41cf-b6c7-440b29bb8c4f</literal>, for communication between the boot
|
||||||
loader:</para>
|
loader and the OS:</para>
|
||||||
|
|
||||||
<variablelist class='efi-variables'>
|
<variablelist class='efi-variables'>
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
@ -493,6 +511,7 @@
|
|||||||
<citerefentry><refentrytitle>systemd-bless-boot.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
<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>systemd-boot-system-token.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||||
<citerefentry><refentrytitle>kernel-install</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_SPECIFICATION">Boot Loader Specification</ulink>,
|
||||||
<ulink url="https://systemd.io/BOOT_LOADER_INTERFACE">Boot Loader Interface</ulink>
|
<ulink url="https://systemd.io/BOOT_LOADER_INTERFACE">Boot Loader Interface</ulink>
|
||||||
</para>
|
</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
|
have = true
|
||||||
conf.set_quoted('EFI_MACHINE_TYPE_NAME', EFI_MACHINE_TYPE_NAME)
|
conf.set_quoted('EFI_MACHINE_TYPE_NAME', EFI_MACHINE_TYPE_NAME)
|
||||||
|
|
||||||
conf.set('SD_TPM_PCR', get_option('tpm-pcrindex'))
|
|
||||||
else
|
else
|
||||||
have = false
|
have = false
|
||||||
endif
|
endif
|
||||||
|
|||||||
@ -416,8 +416,6 @@ option('efi-libdir', type : 'string',
|
|||||||
description : 'path to the EFI lib directory')
|
description : 'path to the EFI lib directory')
|
||||||
option('efi-includedir', type : 'string', value : '/usr/include/efi',
|
option('efi-includedir', type : 'string', value : '/usr/include/efi',
|
||||||
description : 'path to the EFI header directory')
|
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',
|
option('sbat-distro', type : 'string',
|
||||||
description : 'SBAT distribution ID, e.g. fedora, or auto for autodetection')
|
description : 'SBAT distribution ID, e.g. fedora, or auto for autodetection')
|
||||||
option('sbat-distro-generation', type : 'integer', value : 1,
|
option('sbat-distro-generation', type : 'integer', value : 1,
|
||||||
|
|||||||
@ -14,7 +14,7 @@ InstallDirectory=mkosi.installdir
|
|||||||
SourceFileTransferFinal=copy-git-others
|
SourceFileTransferFinal=copy-git-others
|
||||||
|
|
||||||
[Host]
|
[Host]
|
||||||
QemuHeadless=yes
|
QemuHeadless=no
|
||||||
NetworkVeth=yes
|
NetworkVeth=yes
|
||||||
|
|
||||||
[Validation]
|
[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++)
|
for (i = 0; i < n; i++)
|
||||||
if (i != options[i]) {
|
if (i != options[i]) {
|
||||||
*id = i;
|
*id = i;
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* use the next one */
|
/* 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_ENTRY_ONESHOT, "One-shot entry control" },
|
||||||
{ EFI_LOADER_FEATURE_XBOOTLDR, "Support for XBOOTLDR partition" },
|
{ EFI_LOADER_FEATURE_XBOOTLDR, "Support for XBOOTLDR partition" },
|
||||||
{ EFI_LOADER_FEATURE_RANDOM_SEED, "Support for passing random seed to OS" },
|
{ 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;
|
_cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL, *stub = NULL;
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
#include "console.h"
|
#include "console.h"
|
||||||
#include "devicetree.h"
|
#include "devicetree.h"
|
||||||
#include "disk.h"
|
#include "disk.h"
|
||||||
|
#include "drivers.h"
|
||||||
#include "efi-loader-features.h"
|
#include "efi-loader-features.h"
|
||||||
#include "graphics.h"
|
#include "graphics.h"
|
||||||
#include "linux.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) {
|
static VOID print_status(Config *config, CHAR16 *loaded_image_path) {
|
||||||
UINT64 key, indvar;
|
UINT64 key;
|
||||||
UINTN timeout;
|
UINTN timeout;
|
||||||
BOOLEAN modevar;
|
BOOLEAN modevar;
|
||||||
_cleanup_freepool_ CHAR16 *partstr = NULL, *defaultstr = NULL;
|
_cleanup_freepool_ CHAR16 *partstr = NULL, *defaultstr = NULL;
|
||||||
@ -394,8 +395,7 @@ static VOID print_status(Config *config, CHAR16 *loaded_image_path) {
|
|||||||
if (shim_loaded())
|
if (shim_loaded())
|
||||||
Print(L"Shim: present\n");
|
Print(L"Shim: present\n");
|
||||||
|
|
||||||
if (efivar_get_uint64_le(EFI_GLOBAL_GUID, L"OsIndicationsSupported", &indvar) == EFI_SUCCESS)
|
Print(L"OsIndicationsSupported: %d\n", get_os_indications_supported());
|
||||||
Print(L"OsIndicationsSupported: %d\n", indvar);
|
|
||||||
|
|
||||||
Print(L"\n--- press key ---\n\n");
|
Print(L"\n--- press key ---\n\n");
|
||||||
console_key_read(&key, 0);
|
console_key_read(&key, 0);
|
||||||
@ -517,7 +517,8 @@ static BOOLEAN menu_run(
|
|||||||
BOOLEAN refresh = TRUE, highlight = FALSE;
|
BOOLEAN refresh = TRUE, highlight = FALSE;
|
||||||
UINTN x_start = 0, y_start = 0, y_status = 0;
|
UINTN x_start = 0, y_start = 0, y_status = 0;
|
||||||
UINTN x_max, y_max;
|
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;
|
UINTN timeout_remain = config->timeout_sec;
|
||||||
INT16 idx;
|
INT16 idx;
|
||||||
BOOLEAN exit = FALSE, run = TRUE;
|
BOOLEAN exit = FALSE, run = TRUE;
|
||||||
@ -901,7 +902,6 @@ static BOOLEAN menu_run(
|
|||||||
for (UINTN i = 0; i < config->entry_count; i++)
|
for (UINTN i = 0; i < config->entry_count; i++)
|
||||||
FreePool(lines[i]);
|
FreePool(lines[i]);
|
||||||
FreePool(lines);
|
FreePool(lines);
|
||||||
FreePool(clearline);
|
|
||||||
|
|
||||||
clear_screen(COLOR_NORMAL);
|
clear_screen(COLOR_NORMAL);
|
||||||
return run;
|
return run;
|
||||||
@ -1225,7 +1225,7 @@ static VOID config_entry_bump_counters(
|
|||||||
_cleanup_(FileHandleClosep) EFI_FILE_HANDLE handle = NULL;
|
_cleanup_(FileHandleClosep) EFI_FILE_HANDLE handle = NULL;
|
||||||
static const EFI_GUID EfiFileInfoGuid = EFI_FILE_INFO_ID;
|
static const EFI_GUID EfiFileInfoGuid = EFI_FILE_INFO_ID;
|
||||||
_cleanup_freepool_ EFI_FILE_INFO *file_info = NULL;
|
_cleanup_freepool_ EFI_FILE_INFO *file_info = NULL;
|
||||||
UINTN file_info_size, a, b;
|
UINTN file_info_size;
|
||||||
EFI_STATUS r;
|
EFI_STATUS r;
|
||||||
|
|
||||||
assert(entry);
|
assert(entry);
|
||||||
@ -1243,26 +1243,9 @@ static VOID config_entry_bump_counters(
|
|||||||
if (EFI_ERROR(r))
|
if (EFI_ERROR(r))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
a = StrLen(entry->current_name);
|
r = get_file_info_harder(handle, &file_info, &file_info_size);
|
||||||
b = StrLen(entry->next_name);
|
if (EFI_ERROR(r))
|
||||||
|
|
||||||
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;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
file_info_size *= 2;
|
|
||||||
FreePool(file_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* And rename the file */
|
/* And rename the file */
|
||||||
StrCpy(file_info->FileName, entry->next_name);
|
StrCpy(file_info->FileName, entry->next_name);
|
||||||
@ -1487,9 +1470,11 @@ static VOID config_load_entries(
|
|||||||
Config *config,
|
Config *config,
|
||||||
EFI_HANDLE *device,
|
EFI_HANDLE *device,
|
||||||
EFI_FILE *root_dir,
|
EFI_FILE *root_dir,
|
||||||
CHAR16 *loaded_image_path) {
|
const CHAR16 *loaded_image_path) {
|
||||||
|
|
||||||
_cleanup_(FileHandleClosep) EFI_FILE_HANDLE entries_dir = NULL;
|
_cleanup_(FileHandleClosep) EFI_FILE_HANDLE entries_dir = NULL;
|
||||||
|
_cleanup_freepool_ EFI_FILE_INFO *f = NULL;
|
||||||
|
UINTN f_size = 0;
|
||||||
EFI_STATUS err;
|
EFI_STATUS err;
|
||||||
|
|
||||||
assert(config);
|
assert(config);
|
||||||
@ -1497,22 +1482,17 @@ static VOID config_load_entries(
|
|||||||
assert(root_dir);
|
assert(root_dir);
|
||||||
assert(loaded_image_path);
|
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))
|
if (EFI_ERROR(err))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
CHAR16 buf[256];
|
|
||||||
UINTN bufsize;
|
|
||||||
EFI_FILE_INFO *f;
|
|
||||||
_cleanup_freepool_ CHAR8 *content = NULL;
|
_cleanup_freepool_ CHAR8 *content = NULL;
|
||||||
|
|
||||||
bufsize = sizeof(buf);
|
err = readdir_harder(entries_dir, &f, &f_size);
|
||||||
err = uefi_call_wrapper(entries_dir->Read, 3, entries_dir, &bufsize, buf);
|
if (f_size == 0 || EFI_ERROR(err))
|
||||||
if (bufsize == 0 || EFI_ERROR(err))
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
f = (EFI_FILE_INFO *) buf;
|
|
||||||
if (f->FileName[0] == '.')
|
if (f->FileName[0] == '.')
|
||||||
continue;
|
continue;
|
||||||
if (f->Attribute & EFI_FILE_DIRECTORY)
|
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;
|
INTN r;
|
||||||
|
|
||||||
assert(a);
|
assert(a);
|
||||||
@ -1567,24 +1547,7 @@ static INTN config_entry_compare(ConfigEntry *a, ConfigEntry *b) {
|
|||||||
static VOID config_sort_entries(Config *config) {
|
static VOID config_sort_entries(Config *config) {
|
||||||
assert(config);
|
assert(config);
|
||||||
|
|
||||||
for (UINTN i = 1; i < config->entry_count; i++) {
|
sort_pointer_array((void**) config->entries, config->entry_count, (compare_pointer_func_t) config_entry_compare);
|
||||||
BOOLEAN more;
|
|
||||||
|
|
||||||
more = FALSE;
|
|
||||||
for (UINTN k = 0; k < config->entry_count - i; k++) {
|
|
||||||
ConfigEntry *entry;
|
|
||||||
|
|
||||||
if (config_entry_compare(config->entries[k], config->entries[k+1]) <= 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
entry = config->entries[k];
|
|
||||||
config->entries[k] = config->entries[k+1];
|
|
||||||
config->entries[k+1] = entry;
|
|
||||||
more = TRUE;
|
|
||||||
}
|
|
||||||
if (!more)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static INTN config_entry_find(Config *config, CHAR16 *id) {
|
static INTN config_entry_find(Config *config, CHAR16 *id) {
|
||||||
@ -1978,21 +1941,23 @@ static VOID config_entry_add_linux(
|
|||||||
EFI_FILE *root_dir) {
|
EFI_FILE *root_dir) {
|
||||||
|
|
||||||
_cleanup_(FileHandleClosep) EFI_FILE_HANDLE linux_dir = NULL;
|
_cleanup_(FileHandleClosep) EFI_FILE_HANDLE linux_dir = NULL;
|
||||||
EFI_STATUS err;
|
_cleanup_freepool_ EFI_FILE_INFO *f = NULL;
|
||||||
ConfigEntry *entry;
|
ConfigEntry *entry;
|
||||||
|
UINTN f_size = 0;
|
||||||
|
EFI_STATUS err;
|
||||||
|
|
||||||
assert(config);
|
assert(config);
|
||||||
assert(device);
|
assert(device);
|
||||||
assert(root_dir);
|
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))
|
if (EFI_ERROR(err))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
CHAR16 buf[256];
|
_cleanup_freepool_ CHAR16 *os_name_pretty = NULL, *os_name = NULL, *os_id = NULL,
|
||||||
UINTN bufsize = sizeof buf;
|
*os_version = NULL, *os_version_id = NULL, *os_build_id = NULL, *os_image_version = NULL;
|
||||||
EFI_FILE_INFO *f;
|
_cleanup_freepool_ CHAR8 *content = NULL;
|
||||||
const CHAR8 *sections[] = {
|
const CHAR8 *sections[] = {
|
||||||
(CHAR8 *)".osrel",
|
(CHAR8 *)".osrel",
|
||||||
(CHAR8 *)".cmdline",
|
(CHAR8 *)".cmdline",
|
||||||
@ -2000,22 +1965,14 @@ static VOID config_entry_add_linux(
|
|||||||
};
|
};
|
||||||
UINTN offs[ELEMENTSOF(sections)-1] = {};
|
UINTN offs[ELEMENTSOF(sections)-1] = {};
|
||||||
UINTN szs[ELEMENTSOF(sections)-1] = {};
|
UINTN szs[ELEMENTSOF(sections)-1] = {};
|
||||||
CHAR8 *content = NULL;
|
|
||||||
CHAR8 *line;
|
CHAR8 *line;
|
||||||
UINTN pos = 0;
|
UINTN pos = 0;
|
||||||
CHAR8 *key, *value;
|
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);
|
err = readdir_harder(linux_dir, &f, &f_size);
|
||||||
if (bufsize == 0 || EFI_ERROR(err))
|
if (f_size == 0 || EFI_ERROR(err))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
f = (EFI_FILE_INFO *) buf;
|
|
||||||
if (f->FileName[0] == '.')
|
if (f->FileName[0] == '.')
|
||||||
continue;
|
continue;
|
||||||
if (f->Attribute & EFI_FILE_DIRECTORY)
|
if (f->Attribute & EFI_FILE_DIRECTORY)
|
||||||
@ -2071,16 +2028,28 @@ static VOID config_entry_add_linux(
|
|||||||
os_build_id = stra_to_str(value);
|
os_build_id = stra_to_str(value);
|
||||||
continue;
|
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;
|
_cleanup_freepool_ CHAR16 *path = NULL;
|
||||||
|
|
||||||
path = PoolPrint(L"\\EFI\\Linux\\%s", f->FileName);
|
path = PoolPrint(L"\\EFI\\Linux\\%s", f->FileName);
|
||||||
|
|
||||||
entry = config_entry_add_loader(config, device, LOADER_LINUX, f->FileName, 'l',
|
entry = config_entry_add_loader(
|
||||||
os_name_pretty ?: os_name, path,
|
config,
|
||||||
os_version ?: (os_version_id ? : os_build_id));
|
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);
|
FreePool(content);
|
||||||
content = NULL;
|
content = NULL;
|
||||||
@ -2098,14 +2067,6 @@ static VOID config_entry_add_linux(
|
|||||||
|
|
||||||
config_entry_parse_tries(entry, L"\\EFI\\Linux", f->FileName, L".efi");
|
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->LoadOptions = options;
|
||||||
loaded_image->LoadOptionsSize = StrSize(loaded_image->LoadOptions);
|
loaded_image->LoadOptionsSize = StrSize(loaded_image->LoadOptions);
|
||||||
|
|
||||||
#if ENABLE_TPM
|
|
||||||
/* Try to log any options to the TPM, especially to catch manually edited options */
|
/* Try to log any options to the TPM, especially to catch manually edited options */
|
||||||
err = tpm_log_event(SD_TPM_PCR,
|
(VOID) tpm_log_load_options(options);
|
||||||
(EFI_PHYSICAL_ADDRESS) (UINTN) loaded_image->LoadOptions,
|
|
||||||
loaded_image->LoadOptionsSize, loaded_image->LoadOptions);
|
|
||||||
if (EFI_ERROR(err))
|
|
||||||
log_error_stall(L"Unable to add image options measurement: %r", err);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
efivar_set_time_usec(LOADER_GUID, L"LoaderTimeExecUSec", 0);
|
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);
|
(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 =
|
static const UINT64 loader_features =
|
||||||
EFI_LOADER_FEATURE_CONFIG_TIMEOUT |
|
EFI_LOADER_FEATURE_CONFIG_TIMEOUT |
|
||||||
EFI_LOADER_FEATURE_CONFIG_TIMEOUT_ONE_SHOT |
|
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_BOOT_COUNTING |
|
||||||
EFI_LOADER_FEATURE_XBOOTLDR |
|
EFI_LOADER_FEATURE_XBOOTLDR |
|
||||||
EFI_LOADER_FEATURE_RANDOM_SEED |
|
EFI_LOADER_FEATURE_RANDOM_SEED |
|
||||||
|
EFI_LOADER_FEATURE_LOAD_DRIVER |
|
||||||
0;
|
0;
|
||||||
|
|
||||||
_cleanup_freepool_ CHAR16 *infostr = NULL, *typestr = NULL;
|
_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];
|
CHAR16 uuid[37];
|
||||||
|
|
||||||
InitializeLib(image, sys_table);
|
assert(loaded_image);
|
||||||
init_usec = time_usec();
|
assert(loaded_image_path);
|
||||||
|
|
||||||
efivar_set_time_usec(LOADER_GUID, L"LoaderTimeInitUSec", init_usec);
|
efivar_set_time_usec(LOADER_GUID, L"LoaderTimeInitUSec", init_usec);
|
||||||
efivar_set(LOADER_GUID, L"LoaderInfo", L"systemd-boot " GIT_VERSION, 0);
|
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);
|
(void) efivar_set_uint64_le(LOADER_GUID, L"LoaderFeatures", loader_features, 0);
|
||||||
|
|
||||||
err = uefi_call_wrapper(BS->OpenProtocol, 6, image, &LoadedImageProtocol, (VOID **)&loaded_image,
|
/* the filesystem path to this image, to prevent adding ourselves to the menu */
|
||||||
image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
efivar_set(LOADER_GUID, L"LoaderImageIdentifier", loaded_image_path, 0);
|
||||||
if (EFI_ERROR(err))
|
|
||||||
return log_error_status_stall(err, L"Error getting a LoadedImageProtocol handle: %r", err);
|
|
||||||
|
|
||||||
/* export the device path this image is started from */
|
/* export the device path this image is started from */
|
||||||
if (disk_get_part_uuid(loaded_image->DeviceHandle, uuid) == EFI_SUCCESS)
|
if (disk_get_part_uuid(loaded_image->DeviceHandle, uuid) == EFI_SUCCESS)
|
||||||
efivar_set(LOADER_GUID, L"LoaderDevicePartUUID", uuid, 0);
|
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);
|
root_dir = LibOpenRoot(loaded_image->DeviceHandle);
|
||||||
if (!root_dir)
|
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);
|
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 */
|
(VOID) load_drivers(image, loaded_image, root_dir);
|
||||||
loaded_image_path = DevicePathToStr(loaded_image->FilePath);
|
|
||||||
efivar_set(LOADER_GUID, L"LoaderImageIdentifier", loaded_image_path, 0);
|
|
||||||
|
|
||||||
config_load_defaults(&config, root_dir);
|
config_load_all_entries(&config, loaded_image, loaded_image_path, root_dir);
|
||||||
|
|
||||||
/* scan /EFI/Linux/ directory */
|
|
||||||
config_entry_add_linux(&config, loaded_image->DeviceHandle, root_dir);
|
|
||||||
|
|
||||||
/* scan /loader/entries/\*.conf files */
|
|
||||||
config_load_entries(&config, loaded_image->DeviceHandle, root_dir, loaded_image_path);
|
|
||||||
|
|
||||||
/* Similar, but on any XBOOTLDR partition */
|
|
||||||
config_load_xbootldr(&config, loaded_image->DeviceHandle);
|
|
||||||
|
|
||||||
/* sort entries after version number */
|
|
||||||
config_sort_entries(&config);
|
|
||||||
|
|
||||||
/* if we find some well-known loaders, add them to the end of the list */
|
|
||||||
config_entry_add_osx(&config);
|
|
||||||
config_entry_add_windows(&config, loaded_image->DeviceHandle, root_dir);
|
|
||||||
config_entry_add_loader_auto(&config, loaded_image->DeviceHandle, root_dir, NULL,
|
|
||||||
L"auto-efi-shell", 's', L"EFI Shell", L"\\shell" EFI_MACHINE_TYPE_NAME ".efi");
|
|
||||||
config_entry_add_loader_auto(&config, loaded_image->DeviceHandle, root_dir, loaded_image_path,
|
|
||||||
L"auto-efi-default", '\0', L"EFI Default Loader", NULL);
|
|
||||||
|
|
||||||
if (config.auto_firmware && efivar_get_uint64_le(EFI_GLOBAL_GUID, L"OsIndicationsSupported", &osind) == EFI_SUCCESS) {
|
|
||||||
if (osind & EFI_OS_INDICATIONS_BOOT_TO_FW_UI)
|
|
||||||
config_entry_add_call(&config,
|
|
||||||
L"auto-reboot-to-firmware-setup",
|
|
||||||
L"Reboot Into Firmware Interface",
|
|
||||||
reboot_into_firmware);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.entry_count == 0) {
|
if (config.entry_count == 0) {
|
||||||
log_error_stall(L"No loader found. Configuration files in \\loader\\entries\\*.conf are needed.");
|
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;
|
err = EFI_SUCCESS;
|
||||||
out:
|
out:
|
||||||
FreePool(loaded_image_path);
|
|
||||||
config_free(&config);
|
config_free(&config);
|
||||||
uefi_call_wrapper(root_dir->Close, 1, root_dir);
|
|
||||||
uefi_call_wrapper(BS->CloseProtocol, 4, image, &LoadedImageProtocol, image, NULL);
|
uefi_call_wrapper(BS->CloseProtocol, 4, image, &LoadedImageProtocol, image, NULL);
|
||||||
return err;
|
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;
|
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) {
|
static EFI_STATUS devicetree_fixup(struct devicetree_state *state, UINTN len) {
|
||||||
EFI_DT_FIXUP_PROTOCOL *fixup;
|
EFI_DT_FIXUP_PROTOCOL *fixup;
|
||||||
UINTN size;
|
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.");
|
L"Could not locate device tree fixup protocol, skipping.");
|
||||||
|
|
||||||
size = devicetree_allocated(state);
|
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);
|
EFI_DT_APPLY_FIXUPS | EFI_DT_RESERVE_MEMORY);
|
||||||
if (err == EFI_BUFFER_TOO_SMALL) {
|
if (err == EFI_BUFFER_TOO_SMALL) {
|
||||||
EFI_PHYSICAL_ADDRESS oldaddr = state->addr;
|
EFI_PHYSICAL_ADDRESS oldaddr = state->addr;
|
||||||
UINTN oldpages = state->pages;
|
UINTN oldpages = state->pages;
|
||||||
VOID *oldptr = devicetree_ptr(state);
|
VOID *oldptr = PHYSICAL_ADDRESS_TO_POINTER(state->addr);
|
||||||
|
|
||||||
err = devicetree_allocate(state, size);
|
err = devicetree_allocate(state, size);
|
||||||
if (EFI_ERROR(err))
|
if (EFI_ERROR(err))
|
||||||
return 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);
|
err = uefi_call_wrapper(BS->FreePages, 2, oldaddr, oldpages);
|
||||||
if (EFI_ERROR(err))
|
if (EFI_ERROR(err))
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
size = devicetree_allocated(state);
|
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);
|
EFI_DT_APPLY_FIXUPS | EFI_DT_RESERVE_MEMORY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,9 +85,9 @@ EFI_STATUS devicetree_install(struct devicetree_state *state,
|
|||||||
if (EFI_ERROR(err))
|
if (EFI_ERROR(err))
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
info = LibFileInfo(handle);
|
err = get_file_info_harder(handle, &info, NULL);
|
||||||
if (!info)
|
if (EFI_ERROR(err))
|
||||||
return EFI_OUT_OF_RESOURCES;
|
return err;
|
||||||
if (info->FileSize < FDT_V1_SIZE || info->FileSize > 32 * 1024 * 1024)
|
if (info->FileSize < FDT_V1_SIZE || info->FileSize > 32 * 1024 * 1024)
|
||||||
/* 32MB device tree blob doesn't seem right */
|
/* 32MB device tree blob doesn't seem right */
|
||||||
return EFI_INVALID_PARAMETER;
|
return EFI_INVALID_PARAMETER;
|
||||||
@ -104,7 +98,7 @@ EFI_STATUS devicetree_install(struct devicetree_state *state,
|
|||||||
if (EFI_ERROR(err))
|
if (EFI_ERROR(err))
|
||||||
return 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))
|
if (EFI_ERROR(err))
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@ -112,7 +106,7 @@ EFI_STATUS devicetree_install(struct devicetree_state *state,
|
|||||||
if (EFI_ERROR(err))
|
if (EFI_ERROR(err))
|
||||||
return 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) {
|
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
|
#endif
|
||||||
|
|
||||||
typedef VOID(*handover_f)(VOID *image, EFI_SYSTEM_TABLE *table, struct boot_params *params) __regparm0__;
|
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) {
|
static VOID linux_efi_handover(EFI_HANDLE image, struct boot_params *params) {
|
||||||
handover_f handover;
|
handover_f handover;
|
||||||
UINTN start = (UINTN)params->hdr.code32_start;
|
UINTN start = (UINTN)params->hdr.code32_start;
|
||||||
@ -31,16 +32,17 @@ EFI_STATUS linux_exec(EFI_HANDLE image,
|
|||||||
CHAR8 *cmdline, UINTN cmdline_len,
|
CHAR8 *cmdline, UINTN cmdline_len,
|
||||||
UINTN linux_addr,
|
UINTN linux_addr,
|
||||||
UINTN initrd_addr, UINTN initrd_size) {
|
UINTN initrd_addr, UINTN initrd_size) {
|
||||||
struct boot_params *image_params;
|
|
||||||
|
const struct boot_params *image_params;
|
||||||
struct boot_params *boot_params;
|
struct boot_params *boot_params;
|
||||||
UINT8 setup_sectors;
|
|
||||||
EFI_PHYSICAL_ADDRESS addr;
|
EFI_PHYSICAL_ADDRESS addr;
|
||||||
|
UINT8 setup_sectors;
|
||||||
EFI_STATUS err;
|
EFI_STATUS err;
|
||||||
|
|
||||||
assert(image);
|
assert(image);
|
||||||
assert(cmdline);
|
assert(cmdline);
|
||||||
|
|
||||||
image_params = (struct boot_params *) linux_addr;
|
image_params = (const struct boot_params *) linux_addr;
|
||||||
|
|
||||||
if (image_params->hdr.boot_flag != 0xAA55 ||
|
if (image_params->hdr.boot_flag != 0xAA55 ||
|
||||||
image_params->hdr.header != SETUP_MAGIC ||
|
image_params->hdr.header != SETUP_MAGIC ||
|
||||||
@ -48,31 +50,42 @@ EFI_STATUS linux_exec(EFI_HANDLE image,
|
|||||||
!image_params->hdr.relocatable_kernel)
|
!image_params->hdr.relocatable_kernel)
|
||||||
return EFI_LOAD_ERROR;
|
return EFI_LOAD_ERROR;
|
||||||
|
|
||||||
boot_params = (struct boot_params *) 0xFFFFFFFF;
|
addr = UINT32_MAX; /* Below the 32bit boundary */
|
||||||
err = uefi_call_wrapper(BS->AllocatePages, 4, AllocateMaxAddress, EfiLoaderData,
|
err = uefi_call_wrapper(
|
||||||
EFI_SIZE_TO_PAGES(0x4000), (EFI_PHYSICAL_ADDRESS*) &boot_params);
|
BS->AllocatePages, 4,
|
||||||
|
AllocateMaxAddress,
|
||||||
|
EfiLoaderData,
|
||||||
|
EFI_SIZE_TO_PAGES(0x4000),
|
||||||
|
&addr);
|
||||||
if (EFI_ERROR(err))
|
if (EFI_ERROR(err))
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
boot_params = (struct boot_params *) PHYSICAL_ADDRESS_TO_POINTER(addr);
|
||||||
ZeroMem(boot_params, 0x4000);
|
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;
|
boot_params->hdr.type_of_loader = 0xff;
|
||||||
setup_sectors = image_params->hdr.setup_sects > 0 ? image_params->hdr.setup_sects : 4;
|
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;
|
boot_params->hdr.code32_start = (UINT32)linux_addr + (setup_sectors + 1) * 512;
|
||||||
|
|
||||||
if (cmdline) {
|
if (cmdline) {
|
||||||
addr = 0xA0000;
|
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))
|
if (EFI_ERROR(err))
|
||||||
return err;
|
return err;
|
||||||
CopyMem((VOID *)(UINTN)addr, cmdline, cmdline_len);
|
|
||||||
((CHAR8 *)(UINTN)addr)[cmdline_len] = 0;
|
CopyMem(PHYSICAL_ADDRESS_TO_POINTER(addr), cmdline, cmdline_len);
|
||||||
boot_params->hdr.cmd_line_ptr = (UINT32)addr;
|
((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_image = (UINT32) initrd_addr;
|
||||||
boot_params->hdr.ramdisk_size = (UINT32)initrd_size;
|
boot_params->hdr.ramdisk_size = (UINT32) initrd_size;
|
||||||
|
|
||||||
linux_efi_handover(image, boot_params);
|
linux_efi_handover(image, boot_params);
|
||||||
return EFI_LOAD_ERROR;
|
return EFI_LOAD_ERROR;
|
||||||
|
|||||||
@ -162,4 +162,18 @@ EFI_STATUS tpm_log_event(UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer, UIN
|
|||||||
return EFI_SUCCESS;
|
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
|
#endif
|
||||||
|
|||||||
@ -3,4 +3,18 @@
|
|||||||
|
|
||||||
#include <efi.h>
|
#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_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('''
|
efi_headers = files('''
|
||||||
console.h
|
console.h
|
||||||
|
cpio.h
|
||||||
devicetree.h
|
devicetree.h
|
||||||
disk.h
|
disk.h
|
||||||
|
drivers.h
|
||||||
graphics.h
|
graphics.h
|
||||||
linux.h
|
linux.h
|
||||||
measure.h
|
measure.h
|
||||||
@ -30,6 +32,7 @@ systemd_boot_sources = '''
|
|||||||
boot.c
|
boot.c
|
||||||
console.c
|
console.c
|
||||||
devicetree.c
|
devicetree.c
|
||||||
|
drivers.c
|
||||||
random-seed.c
|
random-seed.c
|
||||||
sha256.c
|
sha256.c
|
||||||
shim.c
|
shim.c
|
||||||
@ -39,6 +42,7 @@ stub_sources = '''
|
|||||||
linux.c
|
linux.c
|
||||||
splash.c
|
splash.c
|
||||||
stub.c
|
stub.c
|
||||||
|
cpio.c
|
||||||
'''.split()
|
'''.split()
|
||||||
|
|
||||||
if conf.get('ENABLE_EFI') == 1 and get_option('gnu-efi') != 'false'
|
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 = configuration_data()
|
||||||
efi_conf.set_quoted('EFI_MACHINE_TYPE_NAME', EFI_MACHINE_TYPE_NAME)
|
efi_conf.set_quoted('EFI_MACHINE_TYPE_NAME', EFI_MACHINE_TYPE_NAME)
|
||||||
efi_conf.set10('ENABLE_TPM', get_option('tpm'))
|
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']
|
foreach ctype : ['color-normal', 'color-entry', 'color-highlight', 'color-edit']
|
||||||
c = get_option('efi-' + ctype).split(',')
|
c = get_option('efi-' + ctype).split(',')
|
||||||
|
|||||||
@ -263,9 +263,9 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir, RandomSeedMode mode) {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
info = LibFileInfo(handle);
|
err = get_file_info_harder(handle, &info, NULL);
|
||||||
if (!info)
|
if (EFI_ERROR(err))
|
||||||
return log_oom();
|
return log_error_status_stall(err, L"Failed to get file info for random seed: %r");
|
||||||
|
|
||||||
size = info->FileSize;
|
size = info->FileSize;
|
||||||
if (size < RANDOM_MAX_SIZE_MIN)
|
if (size < RANDOM_MAX_SIZE_MIN)
|
||||||
|
|||||||
@ -37,8 +37,13 @@ struct bmp_map {
|
|||||||
UINT8 reserved;
|
UINT8 reserved;
|
||||||
} _packed_;
|
} _packed_;
|
||||||
|
|
||||||
static EFI_STATUS bmp_parse_header(UINT8 *bmp, UINTN size, struct bmp_dib **ret_dib,
|
static EFI_STATUS bmp_parse_header(
|
||||||
struct bmp_map **ret_map, UINT8 **pixmap) {
|
const UINT8 *bmp,
|
||||||
|
UINTN size,
|
||||||
|
struct bmp_dib **ret_dib,
|
||||||
|
struct bmp_map **ret_map,
|
||||||
|
const UINT8 **pixmap) {
|
||||||
|
|
||||||
struct bmp_file *file;
|
struct bmp_file *file;
|
||||||
struct bmp_dib *dib;
|
struct bmp_dib *dib;
|
||||||
struct bmp_map *map;
|
struct bmp_map *map;
|
||||||
@ -154,10 +159,13 @@ static VOID pixel_blend(UINT32 *dst, const UINT32 source) {
|
|||||||
*dst = (rb | g);
|
*dst = (rb | g);
|
||||||
}
|
}
|
||||||
|
|
||||||
static EFI_STATUS bmp_to_blt(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *buf,
|
static EFI_STATUS bmp_to_blt(
|
||||||
struct bmp_dib *dib, struct bmp_map *map,
|
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *buf,
|
||||||
UINT8 *pixmap) {
|
struct bmp_dib *dib,
|
||||||
UINT8 *in;
|
struct bmp_map *map,
|
||||||
|
const UINT8 *pixmap) {
|
||||||
|
|
||||||
|
const UINT8 *in;
|
||||||
|
|
||||||
assert(buf);
|
assert(buf);
|
||||||
assert(dib);
|
assert(dib);
|
||||||
@ -246,19 +254,22 @@ static EFI_STATUS bmp_to_blt(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *buf,
|
|||||||
return EFI_SUCCESS;
|
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 = {};
|
EFI_GRAPHICS_OUTPUT_BLT_PIXEL pixel = {};
|
||||||
static const EFI_GUID GraphicsOutputProtocolGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
|
static const EFI_GUID GraphicsOutputProtocolGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
|
||||||
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput = NULL;
|
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput = NULL;
|
||||||
struct bmp_dib *dib;
|
struct bmp_dib *dib;
|
||||||
struct bmp_map *map;
|
struct bmp_map *map;
|
||||||
UINT8 *pixmap;
|
const UINT8 *pixmap;
|
||||||
UINT64 blt_size;
|
UINT64 blt_size;
|
||||||
_cleanup_freepool_ VOID *blt = NULL;
|
_cleanup_freepool_ VOID *blt = NULL;
|
||||||
UINTN x_pos = 0;
|
UINTN x_pos = 0;
|
||||||
UINTN y_pos = 0;
|
UINTN y_pos = 0;
|
||||||
EFI_STATUS err;
|
EFI_STATUS err;
|
||||||
|
|
||||||
|
if (len == 0)
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
|
||||||
assert(content);
|
assert(content);
|
||||||
|
|
||||||
if (!background) {
|
if (!background) {
|
||||||
|
|||||||
@ -3,4 +3,4 @@
|
|||||||
|
|
||||||
#include <efi.h>
|
#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 <efi.h>
|
||||||
#include <efilib.h>
|
#include <efilib.h>
|
||||||
|
|
||||||
|
#include "cpio.h"
|
||||||
#include "disk.h"
|
#include "disk.h"
|
||||||
#include "graphics.h"
|
#include "graphics.h"
|
||||||
#include "linux.h"
|
#include "linux.h"
|
||||||
@ -15,71 +16,83 @@
|
|||||||
/* magic string to find in the binary image */
|
/* magic string to find in the binary image */
|
||||||
static const char __attribute__((used)) magic[] = "#### LoaderInfo: systemd-stub " GIT_VERSION " ####";
|
static const char __attribute__((used)) magic[] = "#### LoaderInfo: systemd-stub " GIT_VERSION " ####";
|
||||||
|
|
||||||
EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
static EFI_STATUS combine_initrd(
|
||||||
EFI_LOADED_IMAGE *loaded_image;
|
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 {
|
EFI_PHYSICAL_ADDRESS base = UINT32_MAX; /* allocate an area below the 32bit boundary for this */
|
||||||
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_STATUS err;
|
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,
|
/* Combines three initrds into one, by simple concatenation in memory */
|
||||||
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);
|
n = ALIGN_TO(initrd_size, 4); /* main initrd might not be padded yet */
|
||||||
if (EFI_ERROR(err))
|
if (credential_initrd) {
|
||||||
return log_error_status_stall(err, L"Unable to locate embedded .linux section: %r", err);
|
if (n > UINTN_MAX - credential_initrd_size)
|
||||||
|
return EFI_OUT_OF_RESOURCES;
|
||||||
|
|
||||||
if (szs[SECTION_CMDLINE] > 0) {
|
n += credential_initrd_size;
|
||||||
cmdline = (CHAR8*) loaded_image->ImageBase + addrs[SECTION_CMDLINE];
|
}
|
||||||
cmdline_len = szs[SECTION_CMDLINE];
|
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 */
|
err = uefi_call_wrapper(
|
||||||
if ((!secure_boot_enabled() || cmdline_len == 0) && loaded_image->LoadOptionsSize > 0 &&
|
BS->AllocatePages, 4,
|
||||||
*(CHAR16 *) loaded_image->LoadOptions > 0x1F) {
|
AllocateMaxAddress,
|
||||||
CHAR16 *options;
|
EfiLoaderData,
|
||||||
CHAR8 *line;
|
EFI_SIZE_TO_PAGES(n),
|
||||||
|
&base);
|
||||||
options = (CHAR16 *)loaded_image->LoadOptions;
|
|
||||||
cmdline_len = (loaded_image->LoadOptionsSize / sizeof(CHAR16)) * sizeof(CHAR8);
|
|
||||||
line = AllocatePool(cmdline_len);
|
|
||||||
for (UINTN i = 0; i < cmdline_len; i++)
|
|
||||||
line[i] = options[i];
|
|
||||||
cmdline = line;
|
|
||||||
|
|
||||||
#if ENABLE_TPM
|
|
||||||
/* Try to log any options to the TPM, especially manually edited options */
|
|
||||||
err = tpm_log_event(SD_TPM_PCR,
|
|
||||||
(EFI_PHYSICAL_ADDRESS) (UINTN) loaded_image->LoadOptions,
|
|
||||||
loaded_image->LoadOptionsSize, loaded_image->LoadOptions);
|
|
||||||
if (EFI_ERROR(err))
|
if (EFI_ERROR(err))
|
||||||
log_error_stall(L"Unable to add image options measurement: %r", err);
|
return log_error_status_stall(err, L"Failed to allocate space for combined initrd: %r", err);
|
||||||
#endif
|
|
||||||
|
p = PHYSICAL_ADDRESS_TO_POINTER(base);
|
||||||
|
if (initrd_base != 0) {
|
||||||
|
UINTN pad;
|
||||||
|
|
||||||
|
/* Order matters, the real initrd must come first, since it might include microcode updates
|
||||||
|
* which the kernel only looks for in the first cpio archive */
|
||||||
|
CopyMem(p, PHYSICAL_ADDRESS_TO_POINTER(initrd_base), initrd_size);
|
||||||
|
p += initrd_size;
|
||||||
|
|
||||||
|
pad = ALIGN_TO(initrd_size, 4) - initrd_size;
|
||||||
|
if (pad > 0) {
|
||||||
|
ZeroMem(p, pad);
|
||||||
|
p += pad;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (credential_initrd) {
|
||||||
|
CopyMem(p, credential_initrd, credential_initrd_size);
|
||||||
|
p += credential_initrd_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sysext_initrd) {
|
||||||
|
CopyMem(p, sysext_initrd, sysext_initrd_size);
|
||||||
|
p += sysext_initrd_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert((UINT8*) PHYSICAL_ADDRESS_TO_POINTER(base) + n == p);
|
||||||
|
|
||||||
|
*ret_initrd_base = base;
|
||||||
|
*ret_initrd_size = n;
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID export_variables(EFI_LOADED_IMAGE *loaded_image) {
|
||||||
|
CHAR16 uuid[37];
|
||||||
|
|
||||||
|
assert(loaded_image);
|
||||||
|
|
||||||
/* Export the device path this image is started from, if it's not set yet */
|
/* 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 (efivar_get_raw(LOADER_GUID, L"LoaderDevicePartUUID", NULL, NULL) != EFI_SUCCESS)
|
||||||
@ -119,17 +132,124 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
|||||||
/* add StubInfo */
|
/* add StubInfo */
|
||||||
if (efivar_get_raw(LOADER_GUID, L"StubInfo", NULL, NULL) != EFI_SUCCESS)
|
if (efivar_get_raw(LOADER_GUID, L"StubInfo", NULL, NULL) != EFI_SUCCESS)
|
||||||
efivar_set(LOADER_GUID, L"StubInfo", L"systemd-stub " GIT_VERSION, 0);
|
efivar_set(LOADER_GUID, L"StubInfo", L"systemd-stub " GIT_VERSION, 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (szs[SECTION_SPLASH] > 0)
|
EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||||
graphics_splash((UINT8*) (UINTN) loaded_image->ImageBase + addrs[SECTION_SPLASH], szs[SECTION_SPLASH], NULL);
|
|
||||||
|
|
||||||
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_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);
|
err = linux_exec(image, cmdline, cmdline_len, linux_base, initrd_base, initrd_size);
|
||||||
|
|
||||||
graphics_mode(FALSE);
|
graphics_mode(FALSE);
|
||||||
return log_error_status_stall(err, L"Execution of embedded linux image failed: %r", err);
|
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) {
|
CHAR8 *strchra(const CHAR8 *s, CHAR8 c) {
|
||||||
assert(s);
|
if (!s)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (*s == c)
|
if (*s == c)
|
||||||
return (CHAR8*) s;
|
return (CHAR8*) s;
|
||||||
} while (*s++);
|
} while (*s++);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -451,9 +454,9 @@ EFI_STATUS file_read(EFI_FILE_HANDLE dir, const CHAR16 *name, UINTN off, UINTN s
|
|||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
_cleanup_freepool_ EFI_FILE_INFO *info = NULL;
|
_cleanup_freepool_ EFI_FILE_INFO *info = NULL;
|
||||||
|
|
||||||
info = LibFileInfo(handle);
|
err = get_file_info_harder(handle, &info, NULL);
|
||||||
if (!info)
|
if (EFI_ERROR(err))
|
||||||
return EFI_OUT_OF_RESOURCES;
|
return err;
|
||||||
|
|
||||||
size = info->FileSize+1;
|
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->SetAttribute, 2, ST->ConOut, attr);
|
||||||
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
|
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"
|
#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 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) {
|
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);
|
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 } }
|
&(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 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, ...);
|
VOID log_error_stall(const CHAR16 *fmt, ...);
|
||||||
EFI_STATUS log_oom(void);
|
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 print_at(UINTN x, UINTN y, UINTN attr, const CHAR16 *str);
|
||||||
VOID clear_screen(UINTN attr);
|
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_BOOT_COUNTING (UINT64_C(1) << 4)
|
||||||
#define EFI_LOADER_FEATURE_XBOOTLDR (UINT64_C(1) << 5)
|
#define EFI_LOADER_FEATURE_XBOOTLDR (UINT64_C(1) << 5)
|
||||||
#define EFI_LOADER_FEATURE_RANDOM_SEED (UINT64_C(1) << 6)
|
#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
|
#endif
|
||||||
|
|
||||||
int rename_and_apply_smack_floor_label(const char *from, const char *to) {
|
int rename_and_apply_smack_floor_label(const char *from, const char *to) {
|
||||||
int r = 0;
|
|
||||||
if (rename(from, to) < 0)
|
if (rename(from, to) < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
#if HAVE_SMACK_RUN_LABEL
|
#if HAVE_SMACK_RUN_LABEL
|
||||||
r = mac_smack_apply(to, SMACK_ATTR_ACCESS, SMACK_FLOOR_LABEL);
|
return mac_smack_apply(to, SMACK_ATTR_ACCESS, SMACK_FLOOR_LABEL);
|
||||||
if (r < 0)
|
#else
|
||||||
return r;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user