Skip to content

Commit

Permalink
CSM-support is automatically disabled if we enable secure boot for bi… (
Browse files Browse the repository at this point in the history
#19)

* CSM-support is automatically disabled if we enable secure boot for bigtwin servers. Secure boot remains inactive as long as Platform Key(PK) is not enrolled or the system is not in User mode

* UpdateBIOS -> ConfigureBIOS
  • Loading branch information
Sandro Koll authored May 26, 2020
1 parent fc1b6a3 commit 390024d
Show file tree
Hide file tree
Showing 5 changed files with 227 additions and 96 deletions.
58 changes: 58 additions & 0 deletions cmd/bios.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package cmd

import (
"github.com/metal-stack/metal-hammer/cmd/event"
"github.com/metal-stack/metal-hammer/pkg/kernel"
"github.com/metal-stack/metal-hammer/pkg/sum"
"time"

log "github.com/inconshreveable/log15"
)

// ConfigureBIOS ensures that UEFI boot is enabled and CSM-support is disabled.
// It then reboots the machine.
func (h *Hammer) ConfigureBIOS() error {
s, err := sum.New()
if err != nil {
return err
}

reboot, err := s.ConfigureBIOS()
if err != nil {
log.Warn("BIOS updates for this machine type are intentionally not supported, skipping ConfigureBIOS", "error", err)
return nil
}
if reboot {
h.EventEmitter.Emit(event.ProvisioningEventPlannedReboot, "update BIOS configuration, need to reboot")

log.Info("bios", "message", "updated BIOS configuration, reboot in 1 sec")
time.Sleep(1 * time.Second)
err = kernel.Reboot()
if err != nil {
log.Error("reboot", "error", err)
}
}

return nil
}

// EnsureBootOrder ensures that the BIOS boot order is properly set,
// i.e. first boot from OS image and then PXE boot
func (h *Hammer) EnsureBootOrder(bootloaderID string) error {
if h.Spec.DevMode {
return nil
}

s, err := sum.New()
if err != nil {
return err
}

err = s.EnsureBootOrder(bootloaderID)
if err != nil {
return err
}
log.Info("bios", "message", "boot order ensured")

return nil
}
11 changes: 4 additions & 7 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,11 @@ func Run(spec *Specification) (*event.EventEmitter, error) {
return eventEmitter, errors.Wrap(err, "wipe")
}

firmware := kernel.Firmware()
log.Info("firmware", "is", firmware)

if firmware != "efi" && !spec.DevMode {
log.Info("firmware is not efi, enforce efi boot mode using preparation image")
err = hammer.EnsureUEFI()
if !spec.DevMode {
err = hammer.ConfigureBIOS()
if err != nil {
log.Warn("BIOS updates for this machine type are intentionally not supported, skipping EnsureUEFI", "error", err)
log.Error("failed to update BIOS", "error", err)
return eventEmitter, err
}
}

Expand Down
58 changes: 0 additions & 58 deletions cmd/uefi.go

This file was deleted.

103 changes: 72 additions & 31 deletions pkg/sum/sum.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package sum
import (
"encoding/xml"
"fmt"
"github.com/metal-stack/metal-hammer/pkg/kernel"
"io/ioutil"
"os"
"os/exec"
Expand Down Expand Up @@ -45,6 +46,11 @@ var (
<Setting name="Boot Option #8" order="1" selectedOption="Disabled" type="Option"/>
<Setting name="Boot Option #9" order="1" selectedOption="Disabled" type="Option"/>
</Menu>
<Menu name="Security">
<Menu name="SMC Secure Boot Configuration">
<Setting name="Secure Boot" selectedOption="Enabled" type="Option"/>
</Menu>
</Menu>
</BiosCfg>`,
s2: `<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
<BiosCfg>
Expand All @@ -61,6 +67,11 @@ var (
<Setting name="UEFI Boot Option #8" selectedOption="Disabled" type="Option"/>
<Setting name="UEFI Boot Option #9" selectedOption="Disabled" type="Option"/>
</Menu>
<Menu name="Security">
<Menu name="SMC Secure Boot Configuration">
<Setting name="Secure Boot" selectedOption="Enabled" type="Option"/>
</Menu>
</Menu>
</BiosCfg>`,
}

Expand Down Expand Up @@ -96,24 +107,27 @@ var (
}
)

type Menu struct {
XMLName xml.Name `xml:"Menu"`
Name string `xml:"name,attr"`
Settings []struct {
XMLName xml.Name `xml:"Setting"`
Name string `xml:"name,attr"`
Order string `xml:"order,attr,omitempty"`
SelectedOption string `xml:"selectedOption,attr"`
} `xml:"Setting"`
Menus []Menu `xml:"Menu"`
}

type BiosCfg struct {
XMLName xml.Name `xml:"BiosCfg"`
Menu []struct {
XMLName xml.Name `xml:"Menu"`
Name string `xml:"name,attr"`
Setting []struct {
XMLName xml.Name `xml:"Setting"`
Name string `xml:"name,attr"`
Order string `xml:"order,attr,omitempty"`
SelectedOption string `xml:"selectedOption,attr"`
}
}
Menus []Menu `xml:"Menu"`
}

// Sum defines methods to interact with Supermicro Update Manager (SUM)
type Sum interface {
EnsureUEFIBoot(reboot bool) error
EnsureBootOrder(bootloaderID string, reboot bool) error
ConfigureBIOS() (bool, error)
EnsureBootOrder(bootloaderID string) error
}

// sum is used to modify the BIOS config from the host OS.
Expand All @@ -123,27 +137,36 @@ type sum struct {
biosCfg BiosCfg
machineType machineType
uefiNetworkBootOption string
secureBootEnabled bool
}

func New() (Sum, error) {
return &sum{}, nil
}

// EnsureUEFIBoot updates BIOS to UEFI boot.
func (s *sum) EnsureUEFIBoot(reboot bool) error {
// ConfigureBIOS updates BIOS to UEFI boot and disables CSM-module if required.
// If returns whether machine needs to be rebooted or not.
func (s *sum) ConfigureBIOS() (bool, error) {
firmware := kernel.Firmware()
log.Info("firmware", "is", firmware)

err := s.prepare()
if err != nil {
return err
return false, err
}

if firmware == "efi" && (s.machineType == s2 || s.secureBootEnabled) { // we cannot disable csm-support for S2 servers yet
return false, nil
}

fragment := uefiBootXMLFragmentTemplates[s.machineType]
fragment = strings.ReplaceAll(fragment, "UEFI_NETWORK_BOOT_OPTION", s.uefiNetworkBootOption)

return s.changeBiosCfg(fragment, reboot)
return true, s.changeBiosCfg(fragment)
}

// EnsureBootOrder ensures BIOS boot order so that boot from the given allocated OS image is attempted before PXE boot.
func (s *sum) EnsureBootOrder(bootloaderID string, reboot bool) error {
func (s *sum) EnsureBootOrder(bootloaderID string) error {
s.bootloaderID = bootloaderID

err := s.prepare()
Expand All @@ -162,7 +185,7 @@ func (s *sum) EnsureBootOrder(bootloaderID string, reboot bool) error {
fragment = strings.ReplaceAll(fragment, "BOOTLOADER_ID", s.bootloaderID)
fragment = strings.ReplaceAll(fragment, "UEFI_NETWORK_BOOT_OPTION", s.uefiNetworkBootOption)

return s.changeBiosCfg(fragment, reboot)
return s.changeBiosCfg(fragment)
}

func (s *sum) prepare() error {
Expand All @@ -177,6 +200,7 @@ func (s *sum) prepare() error {
}

s.determineMachineType()
s.determineSecureBoot()

return s.findUEFINetworkBootOption()
}
Expand All @@ -197,11 +221,11 @@ func (s *sum) getCurrentBiosCfg() error {
}

func (s *sum) determineMachineType() {
for _, menu := range s.biosCfg.Menu {
for _, menu := range s.biosCfg.Menus {
if menu.Name != "Boot" {
continue
}
for _, setting := range menu.Setting {
for _, setting := range menu.Settings {
if setting.Name == "UEFI Boot Option #1" { // not available in BigTwin BIOS
s.machineType = s2
return
Expand All @@ -212,6 +236,28 @@ func (s *sum) determineMachineType() {
s.machineType = bigTwin
}

func (s *sum) determineSecureBoot() {
if s.machineType == s2 { // secure boot option is not available in S2 BIOS
return
}
for _, menu := range s.biosCfg.Menus {
if menu.Name != "Security" {
continue
}
for _, m := range menu.Menus {
if m.Name != "SMC Secure Boot Configuration" {
continue
}
for _, setting := range m.Settings {
if setting.Name == "Secure Boot" {
s.secureBootEnabled = setting.SelectedOption == "Enabled"
return
}
}
}
}
}

func (s *sum) unmarshalBiosCfg() error {
s.biosCfg = BiosCfg{}
decoder := xml.NewDecoder(strings.NewReader(s.biosCfgXML))
Expand All @@ -220,11 +266,11 @@ func (s *sum) unmarshalBiosCfg() error {
}

func (s *sum) findUEFINetworkBootOption() error {
for _, menu := range s.biosCfg.Menu {
for _, menu := range s.biosCfg.Menus {
if menu.Name != "Boot" {
continue
}
for _, setting := range menu.Setting {
for _, setting := range menu.Settings {
if strings.Contains(setting.SelectedOption, "UEFI Network") {
s.uefiNetworkBootOption = setting.SelectedOption
return nil
Expand All @@ -251,11 +297,11 @@ func (s *sum) bootOrderProperlySet() bool {
}

func (s *sum) checkBootOptionAt(index int, bootOption string) bool {
for _, menu := range s.biosCfg.Menu {
for _, menu := range s.biosCfg.Menus {
if menu.Name != "Boot" {
continue
}
for _, setting := range menu.Setting {
for _, setting := range menu.Settings {
switch s.machineType {
case bigTwin:
if setting.Order != "1" {
Expand All @@ -277,18 +323,13 @@ func (s *sum) checkBootOptionAt(index int, bootOption string) bool {
return false
}

func (s *sum) changeBiosCfg(fragment string, reboot bool) error {
func (s *sum) changeBiosCfg(fragment string) error {
err := ioutil.WriteFile(biosCfgUpdateXML, []byte(fragment), 0644)
if err != nil {
return err
}

args := []string{"-c", "ChangeBiosCfg", "--file", biosCfgUpdateXML}
if reboot {
args = append(args, "--reboot")
}

return s.execute(args...)
return s.execute("-c", "ChangeBiosCfg", "--file", biosCfgUpdateXML)
}

func (s *sum) execute(args ...string) error {
Expand Down
Loading

0 comments on commit 390024d

Please sign in to comment.