Commit Graph

135 Commits

Author SHA1 Message Date
renovate[bot] 853c81eef2
chore(deps): lock file maintenance 2023-10-19 20:29:32 +00:00
renovate[bot] eabbae0e0c
fix(deps): update all dependencies 2023-10-16 01:54:44 +00:00
Alois Wohlschlager 90a1adac54
tool: fix atomic write
Atomic write works by first writing a temporary file, then syncing that
temporary file to ensure it is fully on disk before the program can
continue, and in the last step renaming the temporary file to the
target. The middle step was missing, which is likely to lead to a
truncated target file being present after power loss. Add this step.

Furthermore, even with this fix, atomicity is not fully guaranteed,
because FAT32 can become corrupted after power loss due to its design
shortcomings. Even though we cannot really do anything about this case,
adjust the comment to at least acknowledge the situation.
2023-10-04 07:29:35 +02:00
Alois Wohlschlager 4fd37670e2
tool: stop most overwriting in the ESP
Since most files (stubs, kernels and initrds) on the ESP are properly
input-addressed or content-addressed now, there is no point in
overwriting them any more. Hence we detect what generations are already
properly installed, and don't reinstall them any more.

This approach leads to two distinct improvements:
* Rollbacks are more reliable, because initrd secrets and stubs do not
  change any more for existing generations (with the necessary exception
  of stubs in case of signature key rotation). In particular, the risk
  of a newer stub breaking (for example, because of bad interactions
  with certain firmware) old and previously working generations is
  avoided.
* Kernels and initrds that are not going to be (re)installed anyway are
  not read and hashed any more. This significantly reduces the I/O and
  CPU time required for the installation process, particularly when
  there is a large number of generations.

The following drawbacks are noted:
* The first time installation is performed after these changes, most of
  the ESP is re-written at a different path; as a result, the disk usage
  increases to roughly the double until the GC is performed.
* If multiple generations share a bare initrd, but have different
  secrets scripts, the final initrds will now be separated, leading to
  increased disk usage. However, this situation should be rare, and the
  previous behavior was arguably incorrect anyway.
* If the files on the ESP are corrupted, running the installation again
  will not overwrite them with the correct versions. Since the files are
  written atomically, this situation should not happen except in case of
  file system corruption, and it is questionable whether overwriting
  really fixes the problem in this case.
2023-10-04 07:29:21 +02:00
Alois Wohlschlager ca070a9eec
tool: make stubs input-addressed
The stubs on the ESP are now input-addressed, where the inputs are the
system toplevel and the public key used for signature. This way, it is
guaranteed that any stub at a given path will boot the desired system,
even in the presence of one of the two edge-cases where it was not
previously guaranteed:
* The latest generation was deleted at one point, and its generation
  number was reused by a different system configuration. This is
  detected because the toplevel will change.
* The secure boot signing key was rotated, so old stubs would not boot
  at all any more. This is detected because the public key will change.

Avoiding these two cases will allow to skip reinstallation of stubs that
are already in place at the correct path.
2023-10-03 22:08:10 +02:00
Alois Wohlschlager 240914d763
tool: make kernels and initrds content-addressed
Kernels and initrds on the ESP are now content-addressed. By definition,
it is impossible for two different kernels or initrds to ever end up at
the same place, even in the presence of changing initrd secrets or other
unreproducibility.

The basic advantage of this is that installing the kernel or initrd for
a generation can never break another generation. In turn, this enables
the following two improvements:
* All generations can be installed independently. In particular, the
  installation can be performed in one pass, one generation at a time.
  As a result, the code is significantly simplified, and memory usage
  (due to the temporary files) does not grow with the number of
  generations any more.
* Generations that already have their files in place on the ESP do not
  need to be reinstalled. This will be taken advantage of in a
  subsequent commit.
2023-10-03 22:08:03 +02:00
nikstur 0b5ce324d7 tool: clean up a few minor details 2023-09-14 16:35:53 +02:00
nikstur 3bf55f92b8 test: clean up a few minor details 2023-09-14 16:35:53 +02:00
Raito Bezarius 1330292008 tool/systemd: make clippy happy I guess 2023-09-14 16:35:53 +02:00
Raito Bezarius 0107754d62 tool(architecture): make it generic
Architecture is now a generic structure that can be specialized
via an "external" trait for generating the paths you care about
depending on your target bootloader.
2023-09-14 16:35:53 +02:00
Raito Bezarius 609c11f26d tool(systemd-boot): install it once instead of checking for each generation
systemd-boot is now installed once for many generations rather than multiple times.

This means it is not really possible to manage different system in the same "machine", which is a very
obscure usecase, theoretically possible, but not yet encountered.
2023-09-14 16:35:53 +02:00
Raito Bezarius e5c1d74e3f tool: introduce --target-system to choose target architecture
We will hard fail in case of encountering different architectures in bootspec.
This should still be compatible with cross-compiling systems in the future.
2023-09-14 16:35:53 +02:00
Raito Bezarius acc4c2e0a1 tool(tests): use library to use the "target architecture" properly in tests 2023-09-14 16:35:53 +02:00
Raito Bezarius 9af0e56527 tool(esp): add systemd stub filenames mapping for systems 2023-09-14 16:35:53 +02:00
Raito Bezarius 7acb1b218a tool: implement general architecture support - for aarch64, x86 for now 2023-09-14 16:35:53 +02:00
nikstur ff442cd032 tool: introduce some more whitespace 2023-09-14 12:38:40 +02:00
nikstur 143a000f36 tool: separates use statements correctly with whitespace 2023-09-14 12:36:02 +02:00
nikstur baf2f5f6bb tool: use workspace values in Cargo.toml 2023-09-14 12:35:42 +02:00
nikstur efd8c50214 tool: remove superfluous lock file 2023-09-14 12:29:54 +02:00
Raito Bezarius eba963b6f1 tool/shared: make clippy happy
- implements a trivial Default for Roots
- implements a FromStr for OsRelease
2023-09-14 11:55:09 +02:00
Raito Bezarius fd188a0e32 tool/shared: make constraints less concrete and drop lockfile
In a library, a lockfile is not really needed per se
and we should avoid creating duplicate dependencies
as much as possible.
2023-09-14 11:55:09 +02:00
Raito Bezarius 923567d08a systemd-tool: make integration test pass 2023-09-14 11:55:09 +02:00
Raito Bezarius 8029449cba tool: split systemd into a new crate and make tool into a lib-only crate
This is necessary to make integration testing specific to the backend.
2023-09-14 11:55:09 +02:00
Raito Bezarius efe7b40f5c lzbt: abstraction for multiple backends
This generates `lzbt-systemd` binary instead of `lzbt`
which is using a special systemd-specific entrypoint.

This is part of the effort to enable multiple backends.
2023-09-14 11:55:09 +02:00
tilpner 3895c94eb5
tool: only sync ESP filesystem 2023-08-17 21:23:33 +02:00
renovate[bot] 9cceec4008 fix(deps): update all dependencies 2023-07-20 01:27:43 +02:00
renovate[bot] 3cae2f1c63
fix(deps): update all dependencies 2023-06-05 02:00:30 +00:00
renovate[bot] f1d199d0b4
fix(deps): update rust crate log to 0.4.18 2023-05-29 01:38:08 +00:00
nikstur 30ddfcd2ce tool: improve command error messages 2023-05-24 00:17:11 +02:00
renovate[bot] 5ecd73cdac
fix(deps): update all dependencies 2023-05-22 02:56:28 +00:00
Raito Bezarius 77f1279406 tool(bootspec): remove boilerplate with newest bootspec 2023-05-20 19:41:31 +02:00
Raito Bezarius 39cda9e457 tool: bump crate to 0.3.0 2023-05-18 19:03:37 +02:00
nikstur 65dbe44999 stub: format with rustfmt 2023-05-17 21:40:03 +02:00
renovate[bot] 7378e06257
fix(deps): update all dependencies 2023-05-08 01:30:03 +00:00
renovate[bot] 008e7a65fd
fix(deps): update all dependencies 2023-05-01 02:39:28 +00:00
Raito Bezarius 4ef6957f88 feat: enable synthesis support
Bootspec has a mechanism called synthesis where you can synthesize
bootspecs if they are not present based on the generation link only.

This is useful for "vanilla bootspec" which does not contain any
extensions, as this is what we do right now.

If we need extensions, we can also implement our synthesis mechanism on
the top of it.

Enabling synthesis gives us the superpower to support non-bootspec
users. :-)
2023-04-29 22:55:39 +02:00
Raito Bezarius 9fe979d2d6 tests: adopt bootspec v1 format 2023-04-29 15:21:38 +02:00
Raito Bezarius 48ff4cb7c4 tool: adopt bootspec 0.1.0 2023-04-29 15:21:38 +02:00
nikstur 06edad2e83 tool: improve log message about malformed gens
Tells the user which generations are malformed and how to remove them.
2023-04-27 00:33:45 +02:00
nikstur 09e12eb559 tool: disable gc in the presence of malformed gens
Disable GC if there are any malformed gens to avoid catastrophic failure
when there are upstream changes to NixOS that are not handled in lzbt.
2023-04-24 22:03:14 +02:00
nikstur 1b27ddd753
Merge pull request #159 from nix-community/renovate/all
fix(deps): update rust crate clap to 4.2.4
2023-04-24 14:03:04 +02:00
Janne Heß c22352ca20
tool: Use mtime of the symlink rather than the target
When using the target, this will always result in a timestamp from 1970
because the symlink points to the store.
2023-04-24 11:57:34 +02:00
Janne Heß 979d25ee13
Revert "Merge pull request #139 from adtya/built_on_date"
This reverts commit d751d13b0a, reversing
changes made to 7c55847aaf.
2023-04-24 11:48:46 +02:00
renovate[bot] 2ecd951de1
fix(deps): update rust crate clap to 4.2.4 2023-04-24 01:08:24 +00:00
nikstur 8efc061e1d tool: add comment for log level of malformed gens
The message about malformed generatiosn should semantically be a
warning. However, since users might have hundres of old and thus
malformed generations and can do little about it, this should remain a
debug message. This way the user is not spammed with no-op warnings
while still enabling debugging.
2023-04-23 23:28:21 +02:00
nikstur 68d1928e3d Revert "tool: don't silently ignore generations"
This reverts commit 4f182704e0.
2023-04-23 23:27:32 +02:00
Julian Stecklina 4f182704e0 tool: don't silently ignore generations 2023-04-23 15:20:49 +02:00
Julian Stecklina be458e3385 tool: avoid creating unbootable system
lzbt currently happily nukes all boot entries, if it can't parse any
bootspecs. With the upcoming incompatible bootspec change, this might
be a problem that's worth avoiding. :)

I changed lzbt to fail hard in case, it can't generate any boot
items.
2023-04-23 15:17:32 +02:00
renovate[bot] b25e1b77d2
chore(deps): update all dependencies 2023-04-17 01:25:18 +00:00
renovate[bot] 51017c0f40
fix(deps): update all dependencies 2023-04-09 20:27:07 +00:00
Julian Stecklina 5d3fbf10a6
Merge pull request #142 from Myaats/master
tool: drop buggy condition for when to sign
2023-04-09 22:20:46 +02:00
Mats 223ab53d55 tool: drop buggy condition for when to sign 2023-03-30 23:53:24 +02:00
Adithya Nair 97874a2002
propagate error instead of unwrapping in tests 2023-03-22 11:19:12 +05:30
Adithya Nair 6a342a49a9
propagate error instead of unwrapping 2023-03-22 01:25:17 +05:30
Adithya Nair e033a2fcaf
replace mtime with birth time 2023-03-21 23:47:33 +05:30
renovate[bot] 9bbbae3168
fix(deps): update all dependencies 2023-03-20 09:25:02 +00:00
renovate[bot] dfa6c3db1f
chore(deps): lock file maintenance 2023-03-20 01:57:17 +00:00
renovate[bot] eed59b4d16
fix(deps): update all dependencies 2023-03-13 00:45:02 +00:00
nikstur 721b584940 tool: fine tune a few log messages 2023-03-06 00:52:46 +01:00
nikstur c8522e02b4 Merge pull request #122 from nix-community/renovate/all
fix(deps): update all dependencies
2023-02-28 22:20:33 +01:00
renovate[bot] e321ad1626
fix(deps): update all dependencies 2023-02-27 02:01:48 +00:00
Julian Stecklina cbccd64c57 tool: make file installation deterministic
Due to the use of hash maps, the order of file installation was not
deterministic. I've changed the code the use BTreeMaps instead, which
makes this deterministic. While I was here, I tried to simplify the
code a bit.
2023-02-25 20:42:08 +01:00
nikstur 32950b7708 tool: fix typos 2023-02-24 01:29:15 +01:00
nikstur 75a19cd818 tool: correctly sort generation links
To correctly overwrite existing initrd with newer secrets (from newer
generations), the links need to be sorted from oldest generation to
newest.
2023-02-24 00:32:14 +01:00
nikstur 1d21d7bdd8 tool: add install tests
Add a few integration tests for installing files, e.g. overwriting
signed and unsigned files.
2023-02-24 00:04:00 +01:00
nikstur 362205c2ec tool: check file hashes before copying
To minimize writes to the ESP but still find necessary changes, compare
the hashes of the files on the ESP with the "expected" hashes. Only copy
and overwrite already existing files if the hashes don't match. This
ensures a working-as-expected state on the ESP as opposed to previously
where already existing files were just ignored.
2023-02-24 00:04:00 +01:00
nikstur 06b9cdc69e tool: move file_hash() to utils module 2023-02-24 00:04:00 +01:00
nikstur 3a3ad7c40d tool: write all generation artifacts at once
Previously, generations were installed one after another. Now all
artifacts (kernels, initrd etc.) are first collected and then installed.
This way the writes to the ESP are reduced as duplicate paths are
already removed in the collection phase.
2023-02-24 00:04:00 +01:00
nikstur df6b1b07f7 tool: use random names for secure tempfiles
Using random names for tempfiles makes handling them easier. It reduces
the amount of noise in the code because no custom name needs to be
provided for each tempfile. The names were not really useful in any
case.

It also does not burden the developer with ensuring uniqueness of names.
This is relevant when files for multiple generations need to be stored
in the same directory (e.g. because they need to be accessed after
handling one generation).

Out of an abundance of caution, 32 random alphanumeric characters are
chosen for each filename. The tempfile crate, in comparison, only
chooses 8. 32 characters should be enough to avoid collisions, even
if the PRNG is not of cryptographic quality.
2023-02-21 00:13:40 +01:00
nikstur 4d2e67f799 tool: make some utility test functions reusable
Make them reusable by moving them to the common module.
2023-02-20 01:05:01 +01:00
nikstur a8d9ea128d tool: improve sd-boot generation display name
Leverage the bootspec `label` field in its intended way. The VERSION_ID
of the os-release in the stub now only contains the generation number
and the build time. This makes a correct PRETTY_NAME entirely dependent
on correct information in the bootspec `label` field.
2023-02-10 12:25:59 +01:00
nikstur 06f921ead0 tool: read build time from symlink
Read the build time from generation symlinks in /nix/var/nix/profiles
instead of from the underlying derivation. The derivation build time
will always be a UNIX epoch of 0 because of the `nix-build` sandbox,
which is useless for identifying when a generation was created.
2023-02-09 00:29:12 +01:00
Alois Wohlschlager 3885f114a8
Do not sign the kernel
Malicious boot loader specification entries could be used to make a
signed kernel load arbitrary unprotected initrds. Since we do not want
this, do not sign the kernel. This way, the only things allowed to boot
are our UKI stubs, which do verify the initrd.
2023-01-31 18:25:27 +01:00
Janne Heß 96d52b215c
Make the os-release parser more precise
Closes #77
2023-01-30 11:46:48 +01:00
nikstur ce3b2c27b5 tool: write systemd-boot loader.conf
To minimize the number of arguments passed to `lzbt`, the loader config
is assembled outside `lzbt` and passed as a single argument.

Instead of reimplementing `consoleMode` under the `lanzaboote`
namespace, `config.loader.systemd-boot.consoleMode` is reused as is.
2023-01-29 16:19:14 +01:00
nikstur 5f28ae75ea tool: atomically write to ESP
To minimize the potential for irrecoverable errors, only atomic writes
to the ESP are performed. This is implemented by first copying the file
to the destination with a `.tmp` suffix and then renaming it to the
final desintation. This is atomic because the rename operation is atomic
on POSIX platforms.

Specifically, this means that even if the system crashes during the
operation, the final desintation path will most likely be intact if it
exists at all. There are some nuances to this however. It **cannot** be
actually guaranteed that the operation was performed on the filesystem
level. However, this is the best we can do for now.

For reference:
- POSIX rename(2): https://pubs.opengroup.org/onlinepubs/9699919799/
- Rust fs::rename corresponds to rename(2) on Unix: https://doc.rust-lang.org/std/fs/fn.rename.html
- Rust fs::rename is implemented using libc's rename: https://github.com/rust-lang/rust/blob/master/library/std/src/sys/unix/fs.rs#L1397
- Renaming in libc is atomic: https://www.gnu.org/software/libc/manual/html_node/Renaming-Files.html
2023-01-29 15:31:38 +01:00
nikstur 0ca25a9bf0
Merge pull request #78 from nix-community/robust-systemd-version-parsing
tool: make systemd version parsing robust
2023-01-26 21:46:03 +01:00
nikstur 247afb33a2 tool: make systemd version parsing robust
To make handling systemd versions more robust, they are parsed into a
u32 tuple instead of an f32. Additionally, some unit tests for correct
parsing and comparing of versions are added.
2023-01-26 21:30:44 +01:00
nikstur 1970b95b68 tool: remove bootspec.json
This fixture is not necessary anymore as we have enough integration
tests.
2023-01-26 01:16:09 +01:00
nikstur cc169689f3 tool: smarter systemd-boot install
The process of installing systemd-boot is "smarter" because it now
considers a a few conditions instead of doing nothing if there is a file
at the deistination path. systemd-boot is now forcibly installed (i.e.
overwriting any file at the destination) if (1) there is no file at the
destination, OR (2) a newer version of systemd-boot is available, OR (3)
the signature of the file at the destination could not be verified.
2023-01-25 22:21:14 +01:00
nikstur db75203e31 tool: split esp paths
To access paths on the ESP before or after installing generations, split
EspPaths into general EspPaths that only depend on the path to the ESP
and EspGenerationPaths which additionally depend on generation specific
information (e.g. version number and initrd filename).
2023-01-25 00:24:40 +01:00
nikstur 6e452b50df tool: add SecureTempDirExt
Add an extension to TempDir that allows to create secure tempfiles. This
way, everything related to creating secure tempfiles is bundled in a
single place and can easily be reused.
2023-01-21 16:26:17 +01:00
Julian Stecklina dd499f6642 treewide: fix typos 2023-01-21 10:27:34 +01:00
nikstur 5bb33f3389 treewide: simplify subproject names
Lanzatool is renamed to 'tool' and lanzaboote is renamed to 'stub'.
The name of the lanzatool binary is now 'lzbt' standing for
LanZaBooteTool.
2023-01-17 21:31:14 +01:00
nikstur 2fce3c0802 treewde: simplify subproject directory names
This commit only moves the directories instead of chaning any names
inside files.
2023-01-17 21:31:14 +01:00