From c5494bbb5b89178deaee173d8bd5244a517ddad8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20L=C3=B6nnegren?= Date: Wed, 24 Apr 2024 14:52:45 +0200 Subject: [PATCH] Disable boot entry if efivars is read-only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On some systems the efivars is mounted read-only if the firmware does not support writing (such as RPI). This commit turns off writing boot entries to efivars if the efivars filesystem is mounted read-only. Signed-off-by: Fredrik Lönnegren --- pkg/action/install.go | 5 ++++- pkg/action/reset.go | 4 +++- pkg/bootloader/grub.go | 23 +++++++++++++++++++++++ pkg/constants/constants.go | 1 + pkg/elemental/elemental.go | 6 +++--- pkg/snapshotter/loopdevice.go | 3 ++- 6 files changed, 36 insertions(+), 6 deletions(-) diff --git a/pkg/action/install.go b/pkg/action/install.go index 5d145d4648..0588c4a6be 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -61,7 +61,10 @@ func NewInstallAction(cfg *types.RunConfig, spec *types.InstallSpec, opts ...Ins } if i.bootloader == nil { - i.bootloader = bootloader.NewGrub(&cfg.Config, bootloader.WithGrubDisableBootEntry(i.spec.DisableBootEntry)) + i.bootloader = bootloader.NewGrub(&cfg.Config, + bootloader.WithGrubDisableBootEntry(i.spec.DisableBootEntry), + bootloader.WithGrubAutoDisableBootEntry(), + ) } if i.snapshotter == nil { diff --git a/pkg/action/reset.go b/pkg/action/reset.go index a191799711..7eef438e15 100644 --- a/pkg/action/reset.go +++ b/pkg/action/reset.go @@ -84,7 +84,9 @@ func NewResetAction(cfg *types.RunConfig, spec *types.ResetSpec, opts ...ResetAc if r.bootloader == nil { r.bootloader = bootloader.NewGrub( - &cfg.Config, bootloader.WithGrubDisableBootEntry(r.spec.DisableBootEntry), + &cfg.Config, + bootloader.WithGrubDisableBootEntry(r.spec.DisableBootEntry), + bootloader.WithGrubAutoDisableBootEntry(), bootloader.WithGrubClearBootEntry(false), ) } diff --git a/pkg/bootloader/grub.go b/pkg/bootloader/grub.go index ba0a0a6eaa..ec6b8dcb51 100644 --- a/pkg/bootloader/grub.go +++ b/pkg/bootloader/grub.go @@ -23,6 +23,7 @@ import ( "regexp" "github.com/rancher/elemental-toolkit/v2/pkg/constants" + "github.com/rancher/elemental-toolkit/v2/pkg/elemental" "github.com/rancher/elemental-toolkit/v2/pkg/types" "github.com/rancher/elemental-toolkit/v2/pkg/utils" @@ -121,6 +122,28 @@ func WithGrubDisableBootEntry(disableBootEntry bool) func(g *Grub) error { } } +func WithGrubAutoDisableBootEntry() func(g *Grub) error { + return func(g *Grub) error { + if g.disableBootEntry { + // already disabled manually, doing nothing + return nil + } + + rw, err := elemental.IsRWMountPoint(g.runner, constants.EfivarsMountPath) + if err != nil { + g.logger.Errorf("error finding efivar mounts: %s", err.Error()) + return err + } + + // If efivars is not RW, disable writing boot entries. + if !rw { + g.disableBootEntry = true + } + + return nil + } +} + func WithGrubClearBootEntry(clearBootEntry bool) func(g *Grub) error { return func(g *Grub) error { g.clearBootEntry = clearBootEntry diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index d0f563fca8..cc9ce31a2d 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -63,6 +63,7 @@ const ( Tmpfs = "tmpfs" Autofs = "auto" Block = "block" + EfivarsMountPath = "/sys/firmware/efi/efivars" // Maxium number of nested symlinks to resolve MaxLinkDepth = 4 diff --git a/pkg/elemental/elemental.go b/pkg/elemental/elemental.go index b106e54129..fc9efd4bbf 100644 --- a/pkg/elemental/elemental.go +++ b/pkg/elemental/elemental.go @@ -177,8 +177,8 @@ func IsMounted(c types.Config, part *types.Partition) (bool, error) { return !notMnt, nil } -func IsRWMountPoint(c types.Config, mountPoint string) (bool, error) { - cmdOut, err := c.Runner.Run("findmnt", "-fno", "OPTIONS", mountPoint) +func IsRWMountPoint(r types.Runner, mountPoint string) (bool, error) { + cmdOut, err := r.Run("findmnt", "-fno", "OPTIONS", mountPoint) if err != nil { return false, err } @@ -193,7 +193,7 @@ func IsRWMountPoint(c types.Config, mountPoint string) (bool, error) { // MountRWPartition mounts, or remounts if needed, a partition with RW permissions func MountRWPartition(c types.Config, part *types.Partition) (umount func() error, err error) { if mnt, _ := IsMounted(c, part); mnt { - if ok, _ := IsRWMountPoint(c, part.MountPoint); ok { + if ok, _ := IsRWMountPoint(c.Runner, part.MountPoint); ok { c.Logger.Debugf("Already RW mounted: %s at %s", part.Name, part.MountPoint) return func() error { return nil }, nil } diff --git a/pkg/snapshotter/loopdevice.go b/pkg/snapshotter/loopdevice.go index e8ea44b8dc..d642558d45 100644 --- a/pkg/snapshotter/loopdevice.go +++ b/pkg/snapshotter/loopdevice.go @@ -26,6 +26,7 @@ import ( "strings" "github.com/hashicorp/go-multierror" + "github.com/rancher/elemental-toolkit/v2/pkg/constants" "github.com/rancher/elemental-toolkit/v2/pkg/elemental" @@ -91,7 +92,7 @@ func (l *LoopDevice) InitSnapshotter(state *types.Partition, efiDir string) erro l.legacyClean = true // Legacy deployments might not include RW mounts for state partitions - if ok, _ := elemental.IsRWMountPoint(l.cfg, l.rootDir); !ok { + if ok, _ := elemental.IsRWMountPoint(l.cfg.Runner, l.rootDir); !ok { err = l.cfg.Mounter.Mount("", l.rootDir, "auto", []string{"remount", "rw"}) if err != nil { l.cfg.Logger.Errorf("Failed remounting root as RW: %v", err)