114 Commits

Author SHA1 Message Date
Valentin David
2034c7edb2 boot,bootloader: add support for shim fallback and setting EFI boot variables on install (#13511)
* boot: added function to set EFI variables

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

boot: renamed trustedShimFallbackBinary to seedShimPath

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

boot: refactored setting EFI boot variables at install

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

boot: adjusted variable names and fixed variable initialization

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

boot: improve setting Boot#### EFI variable

Notably, splits off the process of reading a Boot#### variable and
extracting its DevicePath into its own function `readBootVariable` which
can be mocked and otherwise simplifies the `setBootNumberVariable`
function.

Also, fixes behavior around the final BootFFFF variable.  Previously, it
was not possible to select the BootFFFF variable if it was unused, due
to overflow concerns on uint16.  Now, the behavior around BootFFFF is
identical to that of any other boot variable, by using an int internally
instead of uint16, which also allows a more robust check for whether
there were no matching variables.

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

boot: added unit tests for setting EFI Boot#### variable

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

boot: refactored setting EFI boot variables

Rewrote EFI boot variable functions to more closely match the behavior
of shim fallback: https://github.com/rhboot/shim/blob/main/fallback.c

In particular, the following have changed:

1. Existing Boot#### variables must fully match the new load option to
   be considered a match.  In particular, the load option attributes,
   label, and device path must all be byte-for-byte identical.
   Previously, only the device paths were compared.
2. Matching Boot#### variables are no longer overwritten.  Since the
   variable data must now byte-for-byte match the new load option, there
   is no need to overwrite the existing variable.
3. Since existing Boot#### variables are no longer overwritten, the
   variable attributes are no longer checked for those variables.
   Instead, it is assumed that the Boot#### variable attributes are
   viable for it to be used as a boot option.  This matches the behavior
   of `rhboot/shim/fallback.c`, for better or for worse.
4. When modifying the BootOrder variable, boot option numbers are no
   longer pruned if there is no matching Boot#### variable.

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

boot,bootloader: introduce UefiBootloader to build EFI load options

Previously, the path of the shim binary relative to the EFI partition
was passed into `SetEfiBootVariables`. However, different bootloaders
may wish to set up `OptionalData` in the load option.

Additionally, not all `TrustedAssetBootloaders` will attempt to set
EFI boot variables, and not all bootloaders which should set EFI boot
variables necessarily support secure boot. Thus, these should be
decoupled.

This commit adds a new `UefiBootloader` interface with the
`ConstructShimEfiLoadOption` method, which builds an EFI load option
from the shim path for the given bootloader.

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

boot,bootloader: fixed linting errors and improved EFI boot variable test clarity

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

bootloader: improved unit test for grub EFI load option creation

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

boot: set EFI boot variables in `MakeRunnableSystem`

Previously, attempted to set boot variables in
`MakeRecoverySystemBootable`, which is called by `MakeBootableImage`,
which is called when building the image file, rather than during install
mode.

`MakeRunnableSystem` is called on first boot during install mode, and
thus should be responsible for setting EFI boot variables.

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

boot: use seed bootloader when setting EFI variables

In install mode, the bootloader located in ubuntu-seed should be used
when setting the EFI boot variables. Previously, the bootloader in
ubuntu-boot was accidentally re-used.

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

tests: added simple test to execute setefibootvar.go code

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

tests: fixed standalone set EFI vars code test to work with different layouts

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

tests: moved simple setefibootvar.go check to nested test

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

tests: added check for idempotence when setting EFI boot variables

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

bootloader: adjust comments, organization, and add TODO

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

boot,bootloader: fix setting EFI boot variables

Make function to search for EFI asset device path and construct load
option common so each UefiBootloader does not have to re-implement it.
Instead, the bootloader returns the description, asset file path, and
optional data, which can then be used to create the EFI load option.

Also, in `makeRunnableSystem`, the bootloader in ubuntu-seed must have
`NoSlashBoot` in order to correctly find the grub.cfg file and thus the
grub bootloader. This commit fixes this bug, and refactors a bit to
account for the changes in responsibilities between the bootloader and
the setefibootvars.go code.

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

bootloader: fixed grub EFI load option test with tmp rootdir

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

go.mod: move golang.org/x/text import next to other golang.org/x/ imports

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

boot: adjust opts to look for recovery bootloader when setting EFI variables

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

boot: do not overwrite BootOrder if unchanged, and unexport EFI variable helper functions

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

boot: unexport `setEfiBootOrderVariable`

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

boot: move code to detect bootloader and set EFI variables accordingly into dedicated function

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

boot: unexport `setUbuntuSeedEfiBootVariables` and accompanying error

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

boot,bootloader: ensure nil optionalData for EFI variable is equivalent to 0-length slice

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

boot: handle empty boot order and other boot var improvements

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

boot: make setefibootvars functions linux-only

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* tests: add nested spread test for setting EFI vars

The test checks that EFI boot variables exist for the following:
1. A Boot#### variable pointing to the shim file path.
2. A BootOrder variable with the #### from the above Boot#### as first.

Since the layout of EFI assets is dependent on the gadget snap, the test
downloads and unpacks the gadget, then modifies the contents so that one
variant has the shim and grub binaries in `EFI/boot/` and another
variant has the shim and grub binaries in `EFI/ubuntu/` and the fallback
binary in `EFI/boot/`.

After building a core image around that modified gadget, the VM is
booted and the test checks that the EFI variables are set correctly.
Then, the test modifies the gadget to match the other variant's initial
layout, and then installs the newly modified gadget. This should trigger
re-setting EFI boot variables as well.

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

tests: fix problems in spread test for setting EFI boot variables

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

tests: disabled TPM on EFI boot vars test and separated gadget script

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

tests: fixed EFI vars test to use correct toolbox and include all EFI assets

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

tests: modify-gadget.sh re-use existing gadget so edition is incremented

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

tests: fix mangled EFI var search string and other improvements

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

tests: polish tests for setting EFI boot variables

Notably, allow tests/nested/core/core20-set-efi-boot-variables to run on
arm64 as well as amd64, simplify setefivars.go to search for multiple
assets on multiple architectures, and allow
tests/nested/manual/core20-set-efi-boot-vars to run on any ubuntu-2*.

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* bootloader/grub.go: only consider new shim asset in boot entry for now

* tests/nested/core/core20-set-efi-boot-variables: fix details

* boot: update uefi variables on gadget update

* tests/nested/manual/core20-set-efi-boot-vars: work-around file not deleted

* tests/nested/manual/core20-set-efi-boot-vars: use fb.efi like other tests

* tests/nested/manual/core20-set-efi-boot-vars: drop use of toolbox snap

* tests/nested/manual/core20-set-efi-boot-vars: drop work-around for not deleted files

* tests/nested/manual/core20-set-efi-boot-vars: verify install does add a boot entry

* tests/nested/manual/core20-set-efi-boot-vars: run only on version that have UC

* tests/nested/manual/core20-set-efi-boot-vars: obey GADGET_CHANNEL

* tests/nested/manual/core20-set-efi-boot-vars: move get_boot_entry.py to libs

* tests/nested/manual/core20-set-efi-boot-vars: factorize copy of variables

... so we can reuse the script in other tests

* tests/nested/core/core20-set-efi-boot-variables: stop using toolbox snap

* tests/nested/core/core20-set-efi-boot-variables: only run on versions with UC available

* overlord/devicestate: test using EfiLoadOptionParameters

* boot: test that variables are set

* boot: test observers' UpdateBootEntry

* tests/nested/manual/core20-set-efi-boot-vars: also test without secure boot

* many: use trusted install observer when UEFI variables are supported

* boot/makebootable.go: rename sealer to observer

* boot/grub.go: fix function name in doc

* cmd/snap-bootstrap: verify that ObserveExistingTrustedRecoveryAssets is called

* boot: add tests for SetEfiBootVariables

* many: comment on calls to ObserveExistingTrustedRecoveryAssets

---------

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>
Co-authored-by: Oliver Calder <oliver.calder@canonical.com>
2024-06-03 10:03:50 +02:00
Valentin David
b248f6c7f7 bootloader/grub.go: add new boot chain binary paths 2024-03-13 12:41:32 +01:00
Valentin David
9edec0a419 bootloader/grub.go: return all possible boot chains
We need to resolve the boot chains another place based on the trusted
assets we encountered to be installed. At this point it could be any chain.
We will need to discover later what the correct chain is.

Also make TrustedAssets return an unsorted data structure to make sure
we do not use the order like the comments claimed.
2024-03-13 12:41:32 +01:00
Valentin David
0954b5ac79 gadget: add kernel command-line remove filter to gadget yaml 2023-10-26 09:34:20 +02:00
Valentin David
7ab5e25a69 boot: update cmdline variables also when updating gadget
Since the cmdline variable will contain default arguments for
the edition, we need to update the variable if we change of edition.
2023-10-18 11:20:15 +02:00
Valentin David
33f5a54f40 boot: only use variable snapd_full_cmdline_args
We know what are the default the default command line so that we can
compute measurement, so there is not much reason to use
`snapd_extra_cmdline_args`. Always using `snapd_full_cmdline_args`
will allow us to filter part of the default command line.

There is a potential bug when filtering all arguments, `grub.cfg` will
just revert to the all the default. We will need to fix it when we
introduce the filtering.
2023-10-18 11:20:15 +02:00
Philip Meulengracht
0bb8d996ab o/restart: add first part of the new restart logic
Implement RestartParameters which helps keeping track of tasks that needs to restart and why for a change. It also adds the new logic for performing deferred restarts.
2023-08-03 15:22:04 +02:00
Miguel Pires
d097436c1c many: fix formatting w/ gofmt 1.19
Go 1.19 includes some changes to gofmt which intend to make lists and
heading clearer when rendered (https://go.dev/doc/go1.19). This commit
is the result of running the new gofmt and manually fixing some of it.
This was necessary because the new gofmt assumed lines beginning w/ tabs
to start lists or examples. While this is often true in our codebase,
we occasionally also use tabs to indent the lines after a TODO or FIXME
prefix or in yaml (e.g., excerpts of a snap.yaml). This meant that a lot of the
reformatted comments were broken and had to be fixed manually.

Signed-off-by: Miguel Pires <miguel.pires@canonical.com>
2023-01-16 14:23:11 +01:00
Alfonso Sánchez-Beato
8a519f46b1 boot,bootloader: add error parameter to GetRebootArguments() 2022-02-23 16:23:53 +01:00
Alfonso Sánchez-Beato
2543d2c2e3 Merge branch 'master' into piboot 2022-02-22 15:38:12 +01:00
Alfonso Sánchez-Beato
a51858b1e7 bootloader: rename RebootArgumentsBootloader interface to RebootBootloader 2022-02-02 18:12:39 +01:00
Alfonso Sánchez-Beato
f0d19f3379 bootloader: add interface for bootloaders needing reboot args
These reboot arguments are passed from systemd to the reboot syscall.
2022-01-28 16:48:30 +01:00
Alfonso Sánchez-Beato
8e4e1f1901 boot,bootloader: add interface to update env from initramfs
This new interface is needed by piboot for the moment, and makes sure
that we do not reconfigure the bootloader while changing the
environment file from the initramfs.
2022-01-18 12:47:14 +01:00
Alfonso Sánchez-Beato
5403502c9f bootloader: add support for piboot
Add support for the official RPi bootloader, so we can use it instead
of RPi's U-Boot port. The U-Boot port is a community effort, so it has
a series of problems, like:

  1. It takes some time until it gets ported when a new RPi model
     appears in the market
  2. It lacks support for USB drivers so USB is not possible

This commit makes it possible to use RPi bootloader, however there are
some limitations that cannot be directly solved as this firmware is
closed source:

  1. We can cold-boot only from the first partition in the disk. This
     implies that we need to write boot assets to the ubuntu-seed
     partition instead of to ubuntu-boot.
  2. The OS updates mechanism depends on a volatile flag that gets
     removed in cold boots. That makes it not possible to distinguish
     sometimes between failed updates and having power-cycled a device
     before really trying a pending update.
  3. There is no scripting language for the RPi bootloader. The only
     way to influence its behavior is by changes to the
     {config,tryboot}.txt files.

The implementation leverages the os_prefix [1] setting in the
bootloader configuration files to select the
kernel/initramfs/dtb/dtbos/cmdline to use in the next
boot. Environment is stored in key=value pairs in text files that are
translated to bootloader configuration when needed (a new kernel is
installed, the run mode changes, etc.). To be able to try new kernels,
fail-safe OS updates are used [2].

[1] https://www.raspberrypi.com/documentation/computers/config_txt.html#os_prefix
[2] https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#fail-safe-os-updates-tryboot
2021-11-16 16:43:55 +01:00
Maciej Borzecki
d4f888598f boot, bootloader: extend unit tests, bump year
Signed-off-by: Maciej Borzecki <maciej.zenon.borzecki@canonical.com>
2021-04-15 19:21:46 +02:00
Maciej Borzecki
98da32f4ef bootloader: introduce full set of command line arguments, refactor trusted bootloader interface
Introduce a structure for passing components of kernel command line. Extend the
structure with a field to carry the full set of arguments. Introduce support in
grub.

Signed-off-by: Maciej Borzecki <maciej.zenon.borzecki@canonical.com>
2021-04-15 19:20:21 +02:00
Ian Johnson
8275345afc bootloader: add check for prepare-image time and more tests validating options
Signed-off-by: Ian Johnson <ian.johnson@canonical.com>
2020-12-03 12:03:07 -06:00
Ian Johnson
421c677428 bootloader: remove installableBootloader interface and methods
This is not used anywhere anymore, so let's just drop it. If we need it again,
we can bring it back.

Signed-off-by: Ian Johnson <ian.johnson@canonical.com>
2020-11-30 17:49:09 -06:00
Ian Johnson
e3d7c4f378 Merge pull request #9673 from anonymouse64/feature/uc20-lk-bootloader-4-take-2
bootloader/many: rm ConfigFile, add Present for indicating presence of bloader

Now we have a specific method on the Bootloader interface which tells Find()
whether the specific bootloader is actually present on the current system. This
will simplify future bootloader implementations to be able to return errors when
identifying if a bootloader is present on the system is more complicated a
question than just if the config file for that bootloader exists.

This is required for the UC20 lk bootloader work, where the Present() implementation will be more complicated than just whether a file exists.
2020-11-23 18:24:52 -06:00
Ian Johnson
5a717a278a bootloader: refactor static set of bootloaders to list instead of a map
This is simpler and avoids from having to maintain the list of names of
bootloaders in three locations, one in the bootloader implementation itself, one
in the gadget.yaml bootloader setting, and one in Find(). Now we just have the
bootloader implementation and the gadget.yaml validator.

Signed-off-by: Ian Johnson <ian.johnson@canonical.com>
2020-11-20 09:03:22 -06:00
Ian Johnson
e3df360d41 Revert "bootloader/bootloader.go: refactor ForGadget slightly"
This reverts commit 072b8847eb.

Signed-off-by: Ian Johnson <ian.johnson@canonical.com>
2020-11-20 08:56:03 -06:00
Maciej Borzecki
900faa90f6 bootloader: indicate when boot config was updated
Indicate when the bootloader boot config was updated. This allows the callers to
take a better decision as to whether an update or some other action is required.

Signed-off-by: Maciej Borzecki <maciej.zenon.borzecki@canonical.com>
2020-11-20 13:31:44 +01:00
Ian Johnson
072b8847eb bootloader/bootloader.go: refactor ForGadget slightly
Signed-off-by: Ian Johnson <ian.johnson@canonical.com>
2020-11-19 15:39:56 -06:00
Ian Johnson
e4ab1c5ca9 bootloader/many: rm ConfigFile, add Present for indicating presence of bloader
Now we have a specific method on the Bootloader interface which tells Find()
whether the specific bootloader is actually present on the current system. This
will simplify future bootloader implementations to be able to return errors when
identifying if a bootloader is present on the system is more complicated a
question than just if the config file for that bootloader exists.

Signed-off-by: Ian Johnson <ian.johnson@canonical.com>
2020-11-19 15:39:56 -06:00
Maciej Borzecki
a13a6f7e8f image, bootloader: comment tweaks
Signed-off-by: Maciej Borzecki <maciej.zenon.borzecki@canonical.com>
2020-11-16 09:05:02 +01:00