From 7f2813e5b7e83d176c5b2ede4bdda0e962241d51 Mon Sep 17 00:00:00 2001 From: Itxaka Date: Mon, 25 Sep 2023 14:14:56 +0200 Subject: [PATCH] Mount ESP under /efi if possible + identify EFI run source (#158) --- internal/utils/common.go | 21 ++++++++++ pkg/mount/dag_steps.go | 82 +++++++++++++++++++++++++++++++++++++-- pkg/mount/dag_uki_boot.go | 3 ++ 3 files changed, 102 insertions(+), 4 deletions(-) diff --git a/internal/utils/common.go b/internal/utils/common.go index c3e1da6..82507b8 100644 --- a/internal/utils/common.go +++ b/internal/utils/common.go @@ -233,3 +233,24 @@ func GetHostProcCmdline() string { } return proc } + +// EfiBootFromInstall will try to check the /sys/firmware/efi/LoaderDevicePartUUID-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f +// systemd vendor Id is 4a67b082-0a4c-41cf-b6c7-440b29bb8c4f and will never change +// LoaderDevicePartUUID contains the partition UUID of the EFI System Partition the boot loader was run from. Set by the boot loader. +// This will return true if we are running from a DISK device, which sets the efivar +// This wil return false when running from a volatile media, like CD or netboot as it cannot infer where it was booted from +// Useful to check if we are on install phase or not +// This efi var is VOLATILE so once we reboot is GONE. No way of keeping it across reboots, its set by the bootloader. +func EfiBootFromInstall() bool { + file := "/sys/firmware/efi/efivars/LoaderDevicePartUUID-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f" + readFile, err := os.ReadFile(file) + if err != nil { + Log.Debug().Err(err).Msg("Error reading LoaderDevicePartUUID file") + return false + } + if len(readFile) == 0 || string(readFile) == "" { + Log.Debug().Str("file", string(readFile)).Msg("Error reading LoaderDevicePartUUID file") + return false + } + return true +} diff --git a/pkg/mount/dag_steps.go b/pkg/mount/dag_steps.go index 48e3a09..ec9ba51 100644 --- a/pkg/mount/dag_steps.go +++ b/pkg/mount/dag_steps.go @@ -2,6 +2,7 @@ package mount import ( "context" + "encoding/json" "errors" "fmt" "os" @@ -384,9 +385,19 @@ func (s *State) WriteSentinelDagStep(g *herd.Graph, deps ...string) error { // Lets add a uki sentinel as well! cmdline, _ := os.ReadFile(internalUtils.GetHostProcCmdline()) if strings.Contains(string(cmdline), "rd.immucore.uki") { - err = os.WriteFile("/run/cos/uki_mode", []byte("1"), os.ModePerm) - if err != nil { - return err + // sentinel for uki mode + if internalUtils.EfiBootFromInstall() { + internalUtils.Log.Info().Str("to", "uki_boot_mode").Msg("Setting sentinel file") + err = os.WriteFile("/run/cos/uki_boot_mode", []byte("1"), os.ModePerm) + if err != nil { + return err + } + } else { + internalUtils.Log.Info().Str("to", "uki_install_mode").Msg("Setting sentinel file") + err := os.WriteFile("/run/cos/uki_install_mode", []byte("1"), os.ModePerm) + if err != nil { + return err + } } } @@ -430,6 +441,13 @@ func (s *State) UKIMountBaseSystem(g *herd.Graph) error { syscall.MS_NOSUID | syscall.MS_NODEV, "", }, + { + "/sys/firmware/efi/efivars", + "efivarfs", + "efivarfs", + syscall.MS_NOSUID | syscall.MS_NODEV | syscall.MS_NOEXEC | syscall.MS_RELATIME, + "", + }, } for _, m := range mounts { e := os.MkdirAll(m.where, 0755) @@ -545,7 +563,7 @@ func (s *State) LoadKernelModules(g *herd.Graph) error { cmd := fmt.Sprintf("modprobe %s", driver) out, err := internalUtils.CommandWithPath(cmd) if err != nil { - internalUtils.Log.Err(err).Str("out", out).Msg("modprobe") + internalUtils.Log.Debug().Err(err).Str("out", out).Msg("modprobe") } } return nil @@ -608,3 +626,59 @@ func (s *State) RunKcryptUpgrade(g *herd.Graph, opts ...herd.OpOption) error { return internalUtils.UpgradeKcryptPartitions() }))...) } + +type LsblkOutput struct { + Blockdevices []struct { + Name string `json:"name,omitempty"` + Parttype interface{} `json:"parttype,omitempty"` + Children []struct { + Name string `json:"name,omitempty"` + Parttype string `json:"parttype,omitempty"` + } `json:"children,omitempty"` + } `json:"blockdevices,omitempty"` +} + +// MountESPPartition tries to mount the ESP into /efi +// Doesnt matter if it fails, its just for niceness. +func (s *State) MountESPPartition(g *herd.Graph, opts ...herd.OpOption) error { + return g.Add("mount-esp", append(opts, herd.WithCallback(func(ctx context.Context) error { + if !internalUtils.EfiBootFromInstall() { + internalUtils.Log.Debug().Msg("Not mounting ESP as we think we are booting from removable media") + return nil + } + cmd := "lsblk -J -o NAME,PARTTYPE" + out, err := internalUtils.CommandWithPath(cmd) + internalUtils.Log.Debug().Str("out", out).Str("cmd", cmd).Msg("ESP") + if err != nil { + internalUtils.Log.Err(err).Msg("ESP") + return nil + } + + lsblk := &LsblkOutput{} + err = json.Unmarshal([]byte(out), lsblk) + if err != nil { + return nil + } + + for _, bd := range lsblk.Blockdevices { + for _, cd := range bd.Children { + if strings.TrimSpace(cd.Parttype) == "c12a7328-f81f-11d2-ba4b-00a0c93ec93b" { + // This is the ESP device + device := filepath.Join("/dev", cd.Name) + if !internalUtils.IsMounted(device) { + op := s.MountOP( + device, + s.path("/efi"), + "vfat", + []string{ + "ro", + }, 5*time.Second) + return op(ctx) + } + } + } + + } + return nil + }))...) +} diff --git a/pkg/mount/dag_uki_boot.go b/pkg/mount/dag_uki_boot.go index afa7916..54668cb 100644 --- a/pkg/mount/dag_uki_boot.go +++ b/pkg/mount/dag_uki_boot.go @@ -21,6 +21,9 @@ func (s *State) RegisterUKI(g *herd.Graph) error { // Udev for devices discovery s.LogIfError(s.UKIUdevDaemon(g), "udev") + // Mount ESP partition under efi if it exists + s.LogIfError(s.MountESPPartition(g, herd.WithDeps(cnst.OpSentinel, cnst.OpUkiUdev)), "mount ESP partition") + // Run rootfs stage s.LogIfError(s.RootfsStageDagStep(g, herd.WithDeps(cnst.OpSentinel, cnst.OpUkiUdev)), "uki rootfs")