mirror of
https://github.com/kairos-io/immucore.git
synced 2025-07-13 14:34:22 +00:00
Add a UKI transition step (#460)
This commit is contained in:
parent
367ab5610e
commit
19a0c2d681
@ -102,6 +102,7 @@ const (
|
|||||||
OpUkiKcrypt = "uki-unlock"
|
OpUkiKcrypt = "uki-unlock"
|
||||||
OpUkiMountLivecd = "mount-livecd"
|
OpUkiMountLivecd = "mount-livecd"
|
||||||
OpUkiExtractCerts = "extract-certs"
|
OpUkiExtractCerts = "extract-certs"
|
||||||
|
OpUkiTransitionSysext = "uki-transition-sysext"
|
||||||
OpUkiCopySysExtensions = "enable-sysextensions"
|
OpUkiCopySysExtensions = "enable-sysextensions"
|
||||||
UkiLivecdMountPoint = "/run/initramfs/live"
|
UkiLivecdMountPoint = "/run/initramfs/live"
|
||||||
UkiIsoBaseTree = "/run/rootfsbase"
|
UkiIsoBaseTree = "/run/rootfsbase"
|
||||||
@ -120,4 +121,5 @@ const (
|
|||||||
DestSysExtDir = "/run/extensions"
|
DestSysExtDir = "/run/extensions"
|
||||||
VerityCertDir = "/run/verity.d/"
|
VerityCertDir = "/run/verity.d/"
|
||||||
SysextDefaultPolicy = "--image-policy=\"root=verity+signed+absent:usr=verity+signed+absent\""
|
SysextDefaultPolicy = "--image-policy=\"root=verity+signed+absent:usr=verity+signed+absent\""
|
||||||
|
EfiDir = "/efi"
|
||||||
)
|
)
|
||||||
|
@ -63,10 +63,11 @@ func RegisterUKI(s *state.State, g *herd.Graph) error {
|
|||||||
// Depends on mount binds as that usually mounts COS_PERSISTENT
|
// Depends on mount binds as that usually mounts COS_PERSISTENT
|
||||||
s.LogIfError(s.MountCustomBindsDagStep(g, herd.WeakDeps), "custom binds mount")
|
s.LogIfError(s.MountCustomBindsDagStep(g, herd.WeakDeps), "custom binds mount")
|
||||||
|
|
||||||
|
s.LogIfError(s.MigrateSysExt(g, herd.WithWeakDeps(cnst.OpMountBind)), "uki transition sysextensions")
|
||||||
// Copy any sysextensions found under cnst.SourceSysExtDir into cnst.DestSysExtDir so its loaded by systemd automatically on start
|
// Copy any sysextensions found under cnst.SourceSysExtDir into cnst.DestSysExtDir so its loaded by systemd automatically on start
|
||||||
// always after cnst.OpMountBind stage so we have a persistent cnst.DestSysExtDir
|
// always after cnst.OpMountBind stage so we have a persistent cnst.DestSysExtDir
|
||||||
// Note that the loading of the extensions is done by systemd with the systemd-sysext service
|
// Note that the loading of the extensions is done by systemd with the systemd-sysext service
|
||||||
s.LogIfError(s.EnableSysExtensions(g, herd.WithWeakDeps(cnst.OpMountBind)), "enable sysextensions")
|
s.LogIfError(s.EnableSysExtensions(g, herd.WithWeakDeps(cnst.OpMountBind, cnst.OpUkiTransitionSysext)), "enable sysextensions")
|
||||||
|
|
||||||
// run initramfs stage
|
// run initramfs stage
|
||||||
s.LogIfError(s.InitramfsStageDagStep(g, herd.WeakDeps, herd.WithDeps(cnst.OpMountBind, cnst.OpUkiCopySysExtensions)), "uki initramfs")
|
s.LogIfError(s.InitramfsStageDagStep(g, herd.WeakDeps, herd.WithDeps(cnst.OpMountBind, cnst.OpUkiCopySysExtensions)), "uki initramfs")
|
||||||
|
@ -561,6 +561,10 @@ func (s *State) UKIMountESPPartition(g *herd.Graph, opts ...herd.OpOption) error
|
|||||||
}))...)
|
}))...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExtractCerts extracts the public keys from the EFI variables and writes them to `/run/verity.d`.
|
||||||
|
// This is used by the sysextensions to verify the signatures of the images
|
||||||
|
// TODO: A public cert could be provided in the config that its used for this, so we should
|
||||||
|
// expand this in the future to also extract that cert during boot from the config into the /run/verity.d.
|
||||||
func (s *State) ExtractCerts(g *herd.Graph, opts ...herd.OpOption) error {
|
func (s *State) ExtractCerts(g *herd.Graph, opts ...herd.OpOption) error {
|
||||||
return g.Add(cnst.OpUkiExtractCerts, append(opts, herd.WithCallback(func(_ context.Context) error {
|
return g.Add(cnst.OpUkiExtractCerts, append(opts, herd.WithCallback(func(_ context.Context) error {
|
||||||
// Get all the full certs
|
// Get all the full certs
|
||||||
@ -611,3 +615,100 @@ func (s *State) ExtractCerts(g *herd.Graph, opts ...herd.OpOption) error {
|
|||||||
return nil
|
return nil
|
||||||
}))...)
|
}))...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MigrateSysExt is a workaround for upgrades from `3.3.x` to `>= 3.4.x`.
|
||||||
|
// In 3.3.x we had the extensions in the EFI dir directly, under /efi/EFI/kairos/{active,passive}.efi.extra.d/
|
||||||
|
// In 3.4.x we moved them to /var/lib/kairos/extensions/ for generic and for enabled ones to /var/lib/kairos/extensions/{active,passive}/
|
||||||
|
// This is a workaround to move the extensions from the old location to the new one to help with upgrades
|
||||||
|
// The order is:
|
||||||
|
// Check both active and passive dirs
|
||||||
|
// If something is found, move it to the new location at /var/lib/kairos/extensions/
|
||||||
|
// Enable it by creating a softlink from /var/lib/kairos/extensions/{active,passive}/EXTENSION to /var/lib/kairos/extensions/EXTENSION
|
||||||
|
// Remove it from the old location.
|
||||||
|
func (s *State) MigrateSysExt(g *herd.Graph, opts ...herd.OpOption) error {
|
||||||
|
return g.Add(cnst.OpUkiTransitionSysext, append(opts, herd.WithCallback(func(_ context.Context) error {
|
||||||
|
if !state.EfiBootFromInstall(internalUtils.Log) {
|
||||||
|
internalUtils.Log.Debug().Msg("Not transitioning sysext as we think we are booting from removable media")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check or create target dir
|
||||||
|
if _, err := os.Stat(s.path("/var/lib/kairos/extensions")); os.IsNotExist(err) {
|
||||||
|
err = os.MkdirAll(s.path("/var/lib/kairos/extensions"), 0755)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have to remount the EFI partition as RW to be able to move the files
|
||||||
|
err := syscall.Mount(cnst.EfiDir, cnst.EfiDir, cnst.UkiDefaultEfiimgFsType, syscall.MS_REMOUNT, "rw")
|
||||||
|
if err != nil {
|
||||||
|
internalUtils.Log.Err(err).Msg("Mounting EFI partition")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// We need to remount it as RO after we are done
|
||||||
|
defer func() {
|
||||||
|
err := syscall.Mount(cnst.EfiDir, cnst.EfiDir, cnst.UkiDefaultEfiimgFsType, syscall.MS_REMOUNT|syscall.MS_RDONLY, "")
|
||||||
|
if err != nil {
|
||||||
|
internalUtils.Log.Err(err).Msg("Mounting EFI partition as RO")
|
||||||
|
} else {
|
||||||
|
internalUtils.Log.Debug().Msg("Remounting EFI partition as RO")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
for _, bootState := range []string{"active", "passive"} {
|
||||||
|
sourceDir := s.path(fmt.Sprintf("/efi/EFI/kairos/%s.efi.extra.d/", bootState))
|
||||||
|
internalUtils.Log.Debug().Str("dir", sourceDir).Msg("Checking for sysextensions")
|
||||||
|
targetDir := s.path(fmt.Sprintf("/var/lib/kairos/extensions/%s", bootState))
|
||||||
|
if _, err := os.Stat(sourceDir); os.IsNotExist(err) {
|
||||||
|
internalUtils.Log.Debug().Str("dir", sourceDir).Msg("No sysextensions found")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Create target dirs as well
|
||||||
|
if _, err := os.Stat(targetDir); os.IsNotExist(err) {
|
||||||
|
err = os.MkdirAll(targetDir, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Move the files over to the main extensions dir
|
||||||
|
files, err := os.ReadDir(sourceDir)
|
||||||
|
if err != nil {
|
||||||
|
internalUtils.Log.Err(err).Msg("Reading dir")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, file := range files {
|
||||||
|
if file.IsDir() {
|
||||||
|
// Skip directories
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
source := filepath.Join(sourceDir, file.Name())
|
||||||
|
target := filepath.Join(s.path("/var/lib/kairos/extensions"), file.Name())
|
||||||
|
// Copy the file to the main extensions dir
|
||||||
|
internalUtils.Log.Debug().Str("source", source).Str("target", target).Msg("Moving sysextension")
|
||||||
|
err = internalUtils.Copy(source, target)
|
||||||
|
if err != nil {
|
||||||
|
internalUtils.Log.Err(err).Str("source", source).Str("target", target).Msg("Moving sysextension")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
internalUtils.Log.Debug().Str("source", source).Str("target", target).Msg("Moved sysextension")
|
||||||
|
|
||||||
|
internalUtils.Log.Debug().Str("target", target).Str("to", s.path(filepath.Join("/var/lib/kairos/extensions", bootState, file.Name()))).Msg("Creating symlink")
|
||||||
|
// Create a symlink to the new location
|
||||||
|
err = os.Symlink(target, s.path(filepath.Join("/var/lib/kairos/extensions", bootState, file.Name())))
|
||||||
|
if err != nil {
|
||||||
|
internalUtils.Log.Err(err).Str("target", target).Str("to", s.path(filepath.Join("/var/lib/kairos/extensions", bootState, file.Name()))).Msg("Creating symlink")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// If no errors at this point, remove the original sysext
|
||||||
|
err = os.Remove(source)
|
||||||
|
if err != nil {
|
||||||
|
internalUtils.Log.Err(err).Str("source", source).Msg("Removing old sysext")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
internalUtils.Log.Debug().Str("source", source).Msg("Done sysext")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}))...)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user