mirror of
https://github.com/kairos-io/immucore.git
synced 2025-08-31 22:27:29 +00:00
Add a UKI transition step
This help the transition between 3.3.x to 3.4.x by moving existing sysexts to their new places and creating the expected links so it should behave exactly like it was before Signed-off-by: Itxaka <itxaka@kairos.io>
This commit is contained in:
@@ -102,6 +102,7 @@ const (
|
||||
OpUkiKcrypt = "uki-unlock"
|
||||
OpUkiMountLivecd = "mount-livecd"
|
||||
OpUkiExtractCerts = "extract-certs"
|
||||
OpUkiTransitionSysext = "uki-transition-sysext"
|
||||
OpUkiCopySysExtensions = "enable-sysextensions"
|
||||
UkiLivecdMountPoint = "/run/initramfs/live"
|
||||
UkiIsoBaseTree = "/run/rootfsbase"
|
||||
@@ -120,4 +121,5 @@ const (
|
||||
DestSysExtDir = "/run/extensions"
|
||||
VerityCertDir = "/run/verity.d/"
|
||||
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
|
||||
s.LogIfError(s.MountCustomBindsDagStep(g, herd.WeakDeps), "custom binds mount")
|
||||
|
||||
s.LogIfError(s.TransitionSysext(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
|
||||
// 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
|
||||
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
|
||||
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 {
|
||||
return g.Add(cnst.OpUkiExtractCerts, append(opts, herd.WithCallback(func(_ context.Context) error {
|
||||
// Get all the full certs
|
||||
@@ -611,3 +615,100 @@ func (s *State) ExtractCerts(g *herd.Graph, opts ...herd.OpOption) error {
|
||||
return nil
|
||||
}))...)
|
||||
}
|
||||
|
||||
// TransitionSysext 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) TransitionSysext(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(source string, target string, fstype string, flags uintptr, data string) {
|
||||
err := syscall.Mount(source, target, fstype, flags, data)
|
||||
if err != nil {
|
||||
internalUtils.Log.Err(err).Msg("Mounting EFI partition as RO")
|
||||
} else {
|
||||
internalUtils.Log.Debug().Msg("Remounting EFI partition as RO")
|
||||
}
|
||||
}(cnst.EfiDir, cnst.EfiDir, cnst.UkiDefaultEfiimgFsType, syscall.MS_REMOUNT|syscall.MS_RDONLY, "")
|
||||
|
||||
for _, bootState := range []string{"active", "passive"} {
|
||||
dir := s.path(fmt.Sprintf("/efi/EFI/kairos/%s.efi.extra.d/", bootState))
|
||||
internalUtils.Log.Debug().Str("dir", dir).Msg("Checking for sysextensions")
|
||||
targetDir := s.path(fmt.Sprintf("/var/lib/kairos/extensions/%s", bootState))
|
||||
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
||||
internalUtils.Log.Debug().Str("dir", dir).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(dir)
|
||||
if err != nil {
|
||||
internalUtils.Log.Err(err).Msg("Reading dir")
|
||||
continue
|
||||
}
|
||||
for _, file := range files {
|
||||
if file.IsDir() {
|
||||
// Skip directories
|
||||
continue
|
||||
}
|
||||
source := filepath.Join(dir, 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
|
||||
}))...)
|
||||
}
|
||||
|
Reference in New Issue
Block a user