Commit Graph
85 Commits
Author SHA1 Message Date
Zbigniew Jędrzejewski-Szmek d9c8f075af ukify: add missing header
This file is installed, so it should have the long header.
2023-05-03 12:29:41 +02:00
Zbigniew Jędrzejewski-Szmek 50f4add445 ukify: use UPPERCASE for parameter names
We generally nowadays use UPPERCASE for parameters in variuos help text.
Let's be consistent here too, and also drop duplicated 'usage:':
$ ukify -h
usage: ukify [options…] LINUX INITRD…
       ukify -h | --help

Build and sign Unified Kernel Images

positional arguments:
  LINUX                 vmlinuz file [.linux section]
  INITRD…               initrd files [.initrd section]
...
2023-05-03 12:29:41 +02:00
Luca Boccassi 00e5933f57 ukify: allow building PE addon
Make the kernel optional too, so that we can easily build and sign a PE addon,
that can be used to carry extra command line options.
2023-04-26 16:55:26 +02:00
Jan Janssen 7f72dca762 ukify: Strip symbol/string table for old stubs 2023-04-01 14:31:22 +02:00
Daan De Meyer ac3412c379 ukify: Add workarounds for older stubs
Older stubs are either not stripped, causing their total size to be
unaligned because of an unaligned symbol table at the end, or stripped,
causing the raw data pointers and sizes to be unaligned because strip
does not follow the PE spec correctly when stripping. Let's add
workarounds for both issues, so that we can use ukify with older stubs
as well.
2023-03-28 18:17:59 +02:00
Daan De Meyer 61648c6976 Revert "ukify: Weaken file alignment assertions"
This reverts commit 23428bb19e.
2023-03-28 13:31:38 +02:00
Daan De Meyer 23428bb19e ukify: Weaken file alignment assertions
Older versions of the stub are not aligned to the PE file alignment
size. If we remove the assertions, the UKI still boots without issues,
so let's drop the assertions and print a message about it instead.
2023-03-27 19:33:16 +02:00
Jan Janssen 52abd56915 ukify: Add riscv32 and loongarch support 2023-03-24 13:01:53 +01:00
Jan Janssen 3fc5eed470 ukify: Use pefile to add sections to EFI stub 2023-03-24 13:01:45 +01:00
Tobias Powalowski bf9f07a629 ukify: allow uncompressed kernel images for UNAME detection on aarch64 and riscv64 (#26929)
Uncompressed aarch64 and riscv64 kernels have a different startpoint than x86.
Example output from ukify:
aarch64: NotImplementedError: unknown file format (starts with b'MZ@\xfa')
riscv64: NotImplementedError: unknown file format (starts with b'MZo\x10')
Add check for (b'MZ') to catch both in one call.

Fix:
https://github.com/systemd/systemd/issues/26923
2023-03-22 12:24:57 +00:00
Jan Janssen eb81a60c73 tree-wide: Use correct SPDX license identifier 2023-02-24 18:53:17 +00:00
Daan De Meyer c87ff62210 ukify: Set fast_load option when parsing PE files
Let's skip parsing of some irrelevant information that we don't use
to speed up building UKIs with large initrds from +-15s to less than
1s.
2023-02-20 20:02:22 +01:00
Yu Watanabe c126c8ac81 ukify: fix padding length 2023-02-15 18:01:02 +00:00
Dmitry V. Levin 30fd9a2dab treewide: fix a few typos in NEWS, docs and comments 2023-02-15 10:41:03 +00:00
Yu Watanabe 0b75493da0 tree-wide: fix typo and comment style update 2023-02-15 10:08:16 +09:00
Zbigniew Jędrzejewski-Szmek 667578bb11 ukify: add explanatory message when import fails 2023-02-08 19:35:42 +00:00
Daan De Meyer c811aba082 ukify: python 3.9 compat followup 2023-01-27 22:16:07 +01:00
Daan De Meyer 09595fd5f2 ukify: Downgrade required python version to 3.9 2023-01-20 13:55:11 +01:00
Daan De Meyer 67b65ac62d ukify: Fix version string
Let's make sure we mimick the version of our other CLI tooling.
2023-01-15 22:17:37 +00:00
Jan Janssen c8add4c2e8 ukify: Fix tools detection if --tools was not passed
In 789a642738 llvm-objcopy was given
higher priority over objcopy, but this would only work if --tools was
also passed.
2023-01-11 09:29:41 +01:00
Daan De Meyer 35fdc097f4 Merge pull request #25912 from DaanDeMeyer/ukify
ukify fixes
2023-01-02 16:07:58 +01:00
Jan Janssen 599c930e48 ukify: Fix section offset calculation
objcopy seems to expect that the offset passed to --change-section-vma
is absolute instead of relative to ImageBase. If this is not accounted
for an invalid image is created that cannot be loaded:

  0 .osrel        0000016b  0000000200016000  0000000200016000  00000400  2**2
  …
  6 .text         0000d242  0000000140001000  0000000140001000  00c6e800  2**4

This isn't an issue with gnu-efi based PE images, but natively created
ones will have a non-zero ImageBase.
2023-01-02 15:59:17 +01:00
Daan De Meyer 4f312ba07b ukify: Require specifying --tools for each tools directory
Instead of consuming N arguments as tools directories, let's always
only consume one argument per specification of --tools. This avoids
issues where the linux image and initrd are interpreted as tools
directories.
2023-01-02 14:53:47 +01:00
Daan De Meyer 737dab1a8d ukify: Handle directories in path_is_readable() 2023-01-02 14:52:49 +01:00
Luca Boccassi 21c8d750cd Merge pull request #25814 from DaanDeMeyer/ukify
ukify: Prefer using llvm-objcopy instead of objcopy
2022-12-22 22:19:05 +01:00
Daan De Meyer 3fc1ae89e7 ukify: Validate that there are no overlapping sections
Let's make sure that after calling objcopy we have no overlapping
sections in the UKI
2022-12-22 12:21:11 +01:00
Daan De Meyer 789a642738 ukify: Prefer using llvm-objcopy instead of objcopy
llvm-objcopy works on stubs built for foreign architectures whereas
objcopy doesn't so let's prefer using llvm-objcopy instead of objcopy.

llvm-objcopy automatically sets the virtual address and doesn't provide
an option to set it manually so we only add --change-section-vma when
using objcopy

The default section flags differ between llvm-objcopy and objcopy
so we add a default for the section flags so we make sure all sections
are read-only data unless specified otherwise.
2022-12-22 12:20:24 +01:00
Daan De Meyer 22ad038ac6 ukify: Allow passing multiple directories to --tools 2022-12-22 12:19:55 +01:00
Zbigniew Jędrzejewski-Szmek 095ff238d0 ukify: check early if inputs exist and are readable
It's much nicer for the user if we fail early instead of doing partial
processing if we cannot read some input. We can't do those checks immediately
from argparse.Parser.parse_args(), because we want to fully process the
commandline first. In particular, even with invalid args, if --help is
specified somewhere, we want to handle that. Thus, we need to delay the checks
after argparse.Parser.parse_args() returns.

Ukify didn't have type annotations on functions, but it probably should.
Jörg's suggested correction included them and we might just as well start here.
2022-12-20 16:10:36 +01:00
Zbigniew Jędrzejewski-Szmek 33bdec184f ukify: catch error when loading foreign pe file
The autodetection code is supposed to throw ValueError when it
cannot figure out the version so that we fall back to the next method.
With the patch:
  Kernel version not specified, starting autodetection 😖.
  Real-Mode Kernel Header magic not found
  + readelf --notes vmlinuz/arm64/vmlinuz-6.0.9-300.fc37.aarch64
  readelf: vmlinuz/arm64/vmlinuz-6.0.9-300.fc37.aarch64: Error: Not an ELF file - it has the wrong magic bytes at the start
  Found uname version: 6.0.9-300.fc37.aarch64
2022-12-20 10:39:10 +01:00
Zbigniew Jędrzejewski-Szmek 54c84c8a7a ukify: allow multiple initrds
If given, multiple initrds are concatenated into a temporary file which then
becomes the .initrd section.

It is also possible to give no initrd. After all, some machines boot without an
initrd, and it should be possible to use the stub without requiring an initrd.
(The stub might not like this, but this is something to fix there.)
2022-12-07 17:22:05 +01:00
Zbigniew Jędrzejewski-Szmek 1f6da5d902 ci: install pefile 2022-12-07 15:53:47 +01:00
Zbigniew Jędrzejewski-Szmek 483c9c1b8a ukify: try to find the uname string in the linux image if not specified
The approach is based on mkinicpio's autodetection.

This is hacky as hell. Some cases are actually fairly nice: ppc64el images have
a note that contains 'uname -r'. (The note is not uniquely labeled at all, and
only contains the release part instead of the full version-hostname-release
string, and we don't actually care about ppc, and it's very hard to read the
note from Python, but in general that'd be the approach I'd like.)

I opted to simply read and decompress the full linux binary in some cases.
Python doesn't make it easy to do streaming decompression with regexp matching,
and it doesn't seem to matter much: the image decompresses in a fraction of a
second.
2022-12-07 15:53:45 +01:00
Zbigniew Jędrzejewski-Szmek 30ec2eaef5 meson,ukify: hook up ukify, add --version option
The option is added because we have a similar one for kernel-install. This
program requires python, and some people might want to skip it because of this.

The tool is installed in /usr/lib/systemd for now, since the interface might
change.

A template file is used, but there is no .in suffix.
The problem is that we'll later want to import the file as a module
for tests, but recent Python versions make it annoyingly hard to import
a module from a file without a .py suffix. imp.load_sources() works, but it
is deprecated and throws warnings.
importlib.machinery.SourceFileLoader().load_module() works, but is also
deprecated. And the documented replacements are a maze of twisted little
callbacks that result in an empty module.
So let's take the easy way out, and skip the suffix which makes it easy
to import the template as a module after adding the directory to sys.path.
2022-12-07 15:32:13 +01:00
Zbigniew Jędrzejewski-Szmek f4780cbe30 ukify: add helper to create UKIs
Features:
- adds sections .linux, .initrd, .uname, .osrel, .pcrpkey, .pcrsig, .cmdline, .splash
- multiple initrds can be concatenated
- section flags are set properly (READONLY, DATA or CODE)
- uses systemd-measure to precalculate pcr measurements and create a signed json policy
- the inner linux image will be signed automatically with sbsign if unsigned
- uses sbsign to sign the output image
- offsets are calculated so that sections are placed adjacent, with .linux last
- custom sections are possible
- multiple pcr signing keys can be specified and different boot phase paths can be
  signed with different keys
- most things can be overriden (path to tools, stub file, signing keys, pcr banks,
  boot phase paths, whether to sign things)
- superficial verification of slash bmp is done
- kernel uname "scraping" from the kernel if not specified (in a later patch)

TODO:
- change systemd-measure to not require a functional TPM2. W/o this, we'd need
  to support all banks in the build machine, which is hard to guarantee.
- load signing keys from /etc/kernel/
- supress exceptions, so if something external fails, the user will not see a traceback
- conversion to BMP from other formats

$ sudo /usr/lib/systemd/ukify \
  --tools=build/ \
  --measure \
  /lib/modules/6.0.5-300.fc37.x86_64/vmlinuz \
  /boot/08a5690a2eed47cf92ac0a5d2e3cf6b0/6.0.5-300.fc37.x86_64/initrd \
  --secureboot-private-key=server.key --secureboot-certificate=server.crt \
  --pcr-private-key=tpm2-pcr-private.pem --pcr-public-key=tpm2-pcr-public.pem \
  --cmdline='rw quiet' \
  --section test:TESTTESTTEST \
  --section test2:TESTTESTTEST2 \
  --pcr-banks=sha1 \
  --uname="$(uname -rv)"

Host arch 'x86_64', efi arch 'x64'
+ sbverify --list /lib/modules/6.0.5-300.fc37.x86_64/vmlinuz
+ build/systemd-measure calculate --linux=/lib/modules/6.0.5-300.fc37.x86_64/vmlinuz --osrel=/etc/os-release --cmdline=/tmp/tmpcmdline_5aufjir --pcrpkey=tpm2-pcr-public.pem --initrd=/boot/08a5690a2eed47cf92ac0a5d2e3cf6b0/6.0.5-300.fc37.x86_64/initrd --bank=sha1
11:sha1=03df5e5243bc002b959d52359fe04e266d0b5ebf
11:sha1=54949b82bae32e80343ff0f01eeeeb75f4c07d3f
11:sha1=0fc62be88aa9c5ad7282aa8adb504f451bcec9df
11:sha1=b71155e7fcd467f7c1696f675e37887032e2eafa
+ build/systemd-measure sign --linux=/lib/modules/6.0.5-300.fc37.x86_64/vmlinuz --osrel=/etc/os-release --cmdline=/tmp/tmpcmdline_5aufjir --pcrpkey=tpm2-pcr-public.pem --initrd=/boot/08a5690a2eed47cf92ac0a5d2e3cf6b0/6.0.5-300.fc37.x86_64/initrd --bank=sha1 --private-key=tpm2-pcr-private.pem --public-key=tpm2-pcr-public.pem
+ objcopy /usr/lib/systemd/boot/efi/linuxx64.efi.stub --add-section .osrel=/etc/os-release --change-section-vma .osrel=0x22000 --add-section .cmdline=/tmp/tmpcmdline_5aufjir --change-section-vma .cmdline=0x23000 --add-section .pcrpkey=tpm2-pcr-public.pem --change-section-vma .pcrpkey=0x24000 --add-section .initrd=/boot/08a5690a2eed47cf92ac0a5d2e3cf6b0/6.0.5-300.fc37.x86_64/initrd --change-section-vma .initrd=0x25000 --add-section .uname=/tmp/tmpuname0v3uzh5r --change-section-vma .uname=0x4009000 --add-section .test=/tmp/tmptestuxve59c8 --change-section-vma .test=0x400a000 --add-section .test2=/tmp/tmptest2_i143p9i --change-section-vma .test2=0x400b000 --add-section .pcrsig=/tmp/tmppcrsigdtcqxz_w --change-section-vma .pcrsig=0x400c000 --add-section .linux=/lib/modules/6.0.5-300.fc37.x86_64/vmlinuz --change-section-vma .linux=0x400d000 /tmp/uki4vsbf7y8
+ sbsign --key server.key --cert server.crt /tmp/uki4vsbf7y8 --output vmlinuz.efi
warning: data remaining[79849520 vs 79866644]: gaps between PE/COFF sections?
warning: data remaining[79849520 vs 79866648]: gaps between PE/COFF sections?
Signing Unsigned original image
Wrote signed vmlinuz.efi
2022-12-07 15:32:13 +01:00