Compare commits

...

2 Commits

Author SHA1 Message Date
Ani Sinha 6721056ff4
Merge 360aced7de into c946b13575 2024-11-23 06:28:52 +00:00
Ani Sinha 360aced7de uki: introduce support for a .efifwauto section
UKIs can be used to bundle firmware blobs that can be measured and
used on a confidential computing environment. There can be more than one
firmware blob bundle, each one for a specific platform. Also firmware images
can themselves be containers like IGVM files that can in turn bundle the
actual firmware blob.

Add support to introduce a .efifwauto section in UKI that can be used for
firmware blobs/images. There can be multiple such sections and each section
can contain a single firmware image.

The matching .hwids entry for a specific platform can be used to select the
most appropriate firmware blob. Subsequent patches will add full support
for this selection mechanism.

ukify tool has been also changed to support addition of a firmware image
in UKI. For example:

ukify.py build \
        --stub ./build/src/boot/efi/linuxx64.efi.stub \
        --linux bzImage \
        --cmdline='blah blah debug' \
        --firmware ~/OVMF.fd \
        --output=root/efi/boot/bootx64.efi

Co-authored-by: harald.hoyer@gmail.com
2024-11-23 11:36:38 +05:30
5 changed files with 67 additions and 39 deletions

View File

@ -91,6 +91,15 @@
the same matching procedure. If a match is found, that <literal>.dtbauto</literal> section will be the same matching procedure. If a match is found, that <literal>.dtbauto</literal> section will be
loaded and will override <varname>.dtb</varname> if present.</para></listitem> loaded and will override <varname>.dtb</varname> if present.</para></listitem>
<listitem><para>Zero or more <literal>.efifwauto</literal> sections for the firmware image. It works
in many ways similar to <varname>.dtbauto</varname> sections. <filename>systemd-stub</filename>
will always use the first matching one. The match is performed by first selecting the most appropriate
entry in the <varname>.hwids</varname> section based on the hardware IDs supplied by SMBIOS (see below).
If a suitable entry is found, the <varname>compatible</varname> string from that entry will be used to
perform the matching procedure for firmware blobs in <varname>.efifwauto</varname> section. The first
matching firmware will be loaded.
</para></listitem>
<listitem><para>Zero or more <literal>.hwids</literal> sections with hardware IDs of the machines to <listitem><para>Zero or more <literal>.hwids</literal> sections with hardware IDs of the machines to
match DeviceTrees. <filename>systemd-stub</filename> will use the SMBIOS data to calculate hardware IDs match DeviceTrees. <filename>systemd-stub</filename> will use the SMBIOS data to calculate hardware IDs
of the machine (as per <ulink of the machine (as per <ulink

View File

@ -9,19 +9,20 @@ const char* const unified_sections[_UNIFIED_SECTION_MAX + 1] = {
* https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#section-table-section-headers * https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#section-table-section-headers
* (Note that PE *object* files may have longer section names (via indirection in the string table) but * (Note that PE *object* files may have longer section names (via indirection in the string table) but
* this is not allowed for PE *executables*, which UKIs are.) */ * this is not allowed for PE *executables*, which UKIs are.) */
[UNIFIED_SECTION_LINUX] = ".linux", [UNIFIED_SECTION_LINUX] = ".linux",
[UNIFIED_SECTION_OSREL] = ".osrel", [UNIFIED_SECTION_OSREL] = ".osrel",
[UNIFIED_SECTION_CMDLINE] = ".cmdline", [UNIFIED_SECTION_CMDLINE] = ".cmdline",
[UNIFIED_SECTION_INITRD] = ".initrd", [UNIFIED_SECTION_INITRD] = ".initrd",
[UNIFIED_SECTION_UCODE] = ".ucode", [UNIFIED_SECTION_UCODE] = ".ucode",
[UNIFIED_SECTION_SPLASH] = ".splash", [UNIFIED_SECTION_SPLASH] = ".splash",
[UNIFIED_SECTION_DTB] = ".dtb", [UNIFIED_SECTION_DTB] = ".dtb",
[UNIFIED_SECTION_UNAME] = ".uname", [UNIFIED_SECTION_UNAME] = ".uname",
[UNIFIED_SECTION_SBAT] = ".sbat", [UNIFIED_SECTION_SBAT] = ".sbat",
[UNIFIED_SECTION_PCRSIG] = ".pcrsig", [UNIFIED_SECTION_PCRSIG] = ".pcrsig",
[UNIFIED_SECTION_PCRPKEY] = ".pcrpkey", [UNIFIED_SECTION_PCRPKEY] = ".pcrpkey",
[UNIFIED_SECTION_PROFILE] = ".profile", [UNIFIED_SECTION_PROFILE] = ".profile",
[UNIFIED_SECTION_DTBAUTO] = ".dtbauto", [UNIFIED_SECTION_DTBAUTO] = ".dtbauto",
[UNIFIED_SECTION_HWIDS] = ".hwids", [UNIFIED_SECTION_HWIDS] = ".hwids",
[UNIFIED_SECTION_FIRMWARE] = ".efifwauto",
NULL, NULL,
}; };

View File

@ -20,6 +20,7 @@ typedef enum UnifiedSection {
UNIFIED_SECTION_PROFILE, UNIFIED_SECTION_PROFILE,
UNIFIED_SECTION_DTBAUTO, UNIFIED_SECTION_DTBAUTO,
UNIFIED_SECTION_HWIDS, UNIFIED_SECTION_HWIDS,
UNIFIED_SECTION_FIRMWARE,
_UNIFIED_SECTION_MAX, _UNIFIED_SECTION_MAX,
} UnifiedSection; } UnifiedSection;

View File

@ -104,6 +104,7 @@ static int help(int argc, char *argv[], void *userdata) {
" --linux=PATH Path to Linux kernel image file %7$s .linux\n" " --linux=PATH Path to Linux kernel image file %7$s .linux\n"
" --osrel=PATH Path to os-release file %7$s .osrel\n" " --osrel=PATH Path to os-release file %7$s .osrel\n"
" --cmdline=PATH Path to file with kernel command line %7$s .cmdline\n" " --cmdline=PATH Path to file with kernel command line %7$s .cmdline\n"
" --firmware=PATH Path to firmware image file %7$s .efifwauto\n"
" --initrd=PATH Path to initrd image file %7$s .initrd\n" " --initrd=PATH Path to initrd image file %7$s .initrd\n"
" --ucode=PATH Path to microcode image file %7$s .ucode\n" " --ucode=PATH Path to microcode image file %7$s .ucode\n"
" --splash=PATH Path to splash bitmap file %7$s .splash\n" " --splash=PATH Path to splash bitmap file %7$s .splash\n"
@ -158,8 +159,9 @@ static int parse_argv(int argc, char *argv[]) {
ARG_PCRPKEY, ARG_PCRPKEY,
ARG_PROFILE, ARG_PROFILE,
ARG_HWIDS, ARG_HWIDS,
ARG_DTBAUTO,
_ARG_SECTION_LAST, _ARG_SECTION_LAST,
ARG_DTBAUTO = _ARG_SECTION_LAST, ARG_FIRMWARE = _ARG_SECTION_LAST,
ARG_BANK, ARG_BANK,
ARG_PRIVATE_KEY, ARG_PRIVATE_KEY,
ARG_PRIVATE_KEY_SOURCE, ARG_PRIVATE_KEY_SOURCE,
@ -180,6 +182,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "osrel", required_argument, NULL, ARG_OSREL }, { "osrel", required_argument, NULL, ARG_OSREL },
{ "cmdline", required_argument, NULL, ARG_CMDLINE }, { "cmdline", required_argument, NULL, ARG_CMDLINE },
{ "initrd", required_argument, NULL, ARG_INITRD }, { "initrd", required_argument, NULL, ARG_INITRD },
{ "firmware", required_argument, NULL, ARG_FIRMWARE },
{ "ucode", required_argument, NULL, ARG_UCODE }, { "ucode", required_argument, NULL, ARG_UCODE },
{ "splash", required_argument, NULL, ARG_SPLASH }, { "splash", required_argument, NULL, ARG_SPLASH },
{ "dtb", required_argument, NULL, ARG_DTB }, { "dtb", required_argument, NULL, ARG_DTB },

View File

@ -242,6 +242,7 @@ class UkifyConfig:
efi_arch: str efi_arch: str
hwids: Path hwids: Path
initrd: list[Path] initrd: list[Path]
firmware: list[Path]
join_profiles: list[Path] join_profiles: list[Path]
json: Union[Literal['pretty'], Literal['short'], Literal['off']] json: Union[Literal['pretty'], Literal['short'], Literal['off']]
linux: Optional[Path] linux: Optional[Path]
@ -362,21 +363,22 @@ class Uname:
DEFAULT_SECTIONS_TO_SHOW = { DEFAULT_SECTIONS_TO_SHOW = {
'.linux': 'binary', '.linux': 'binary',
'.initrd': 'binary', '.initrd': 'binary',
'.ucode': 'binary', '.ucode': 'binary',
'.splash': 'binary', '.splash': 'binary',
'.dtb': 'binary', '.dtb': 'binary',
'.dtbauto': 'binary', '.dtbauto': 'binary',
'.hwids': 'binary', '.hwids': 'binary',
'.cmdline': 'text', '.efifwauto': 'binary',
'.osrel': 'text', '.cmdline': 'text',
'.uname': 'text', '.osrel': 'text',
'.pcrpkey': 'text', '.uname': 'text',
'.pcrsig': 'text', '.pcrpkey': 'text',
'.sbat': 'text', '.pcrsig': 'text',
'.sbom': 'binary', '.sbat': 'text',
'.profile': 'text', '.sbom': 'binary',
'.profile': 'text',
} # fmt: skip } # fmt: skip
@ -1204,16 +1206,17 @@ def make_uki(opts: UkifyConfig) -> None:
sections = [ sections = [
# name, content, measure? # name, content, measure?
('.osrel', opts.os_release, True), ('.osrel', opts.os_release, True),
('.cmdline', opts.cmdline, True), ('.cmdline', opts.cmdline, True),
('.dtb', opts.devicetree, True), ('.dtb', opts.devicetree, True),
*(('.dtbauto', dtb, True) for dtb in opts.devicetree_auto), *(('.dtbauto', dtb, True) for dtb in opts.devicetree_auto),
('.hwids', hwids, True), ('.hwids', hwids, True),
('.uname', opts.uname, True), ('.uname', opts.uname, True),
('.splash', opts.splash, True), ('.splash', opts.splash, True),
('.pcrpkey', pcrpkey, True), ('.pcrpkey', pcrpkey, True),
('.initrd', initrd, True), ('.initrd', initrd, True),
('.ucode', opts.microcode, True), *(('.efifwauto', fw, True) for fw in opts.firmware),
('.ucode', opts.microcode, True),
] # fmt: skip ] # fmt: skip
# If we're building a PE profile binary, the ".profile" section has to be the first one. # If we're building a PE profile binary, the ".profile" section has to be the first one.
@ -1269,6 +1272,7 @@ def make_uki(opts: UkifyConfig) -> None:
'.osrel', '.osrel',
'.cmdline', '.cmdline',
'.initrd', '.initrd',
'.efifwauto',
'.ucode', '.ucode',
'.splash', '.splash',
'.dtb', '.dtb',
@ -1729,6 +1733,16 @@ CONFIG_ITEMS = [
config_key='UKI/Initrd', config_key='UKI/Initrd',
config_push=ConfigItem.config_list_prepend, config_push=ConfigItem.config_list_prepend,
), ),
ConfigItem(
'--firmware',
metavar='PATH',
type=Path,
action='append',
default=[],
help='firmware file [.efifwauto section]',
config_key='UKI/Firmware',
config_push=ConfigItem.config_list_prepend,
),
ConfigItem( ConfigItem(
'--microcode', '--microcode',
metavar='UCODE', metavar='UCODE',