Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/BTGimprovements #373

Merged
merged 6 commits into from
Jan 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/bg-suite/TESTPLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ Id | Test | Implemented | Document | Chapter
04 | Verifies BPM and IBBs match firmware image | :white_check_mark: | Document 557867 / 575623 |
05 | [RUNTIME] Validates Intel ME specific configuration against KM/BPM in firmware image | :white_check_mark: | Document 557867 / 575623 |
06 | [RUNTIME] Verifies Intel ME Boot Guard configuration is sane and safe | :white_check_mark: | Document 557867 / 575623 |
07 | [RUNTIME] BtG/TXT registers are sane | :white_check_mark: | Document 315168-017 |
32 changes: 23 additions & 9 deletions cmd/bg-suite/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,20 @@ type context struct {
logpath string
}

type listCmd struct {
}
type listCmd struct{}

type markdownCmd struct {
}
type markdownCmd struct{}

type versionCmd struct {
}
type versionCmd struct{}

type execTestsCmd struct {
Set string `required default:"all" help:"Select subset of tests. Options: all"`
Set string `required default:"all" help:"Select subset of tests. Options: all, single"`
Strict bool `required default:"false" short:"s" help:"Enable strict mode. This enables more tests and checks."`
Interactive bool `optional short:"i" help:"Interactive mode. Errors will stop the testing."`
Config string `optional short:"c" help:"Path/Filename to config file."`
Log string `optional help:"Give a path/filename for test result output inJSON format. e.g.: /path/to/filename.json"`
Firmware string `optional short:"f" help:"Path/Filename to firmware to test with."`
Number int `optional default:"-1" short:"n" help:"Test number to run."`
}

var cli struct {
Expand All @@ -57,11 +56,20 @@ func (e *execTestsCmd) Run(ctx *context) error {
preset := test.PreSet{
Firmware: data,
HostBridgeDeviceID: 0x00,
Strict: e.Strict,
}
switch e.Set {
case "all":
fmt.Println("For more information about the documents and chapters, run: bg-suite -m")
ret = run("All", getTests(), &preset, e.Interactive)
case "single":
if e.Number < 0 {
return fmt.Errorf("no test number given")
}
if e.Number >= len(getTests()) {
return fmt.Errorf("test number out of range")
}
ret = run("Single", []*test.Test{getTests()[e.Number]}, &preset, e.Interactive)
default:
return fmt.Errorf("no valid test set given")
}
Expand Down Expand Up @@ -116,7 +124,7 @@ func getTests() []*test.Test {
}

func run(testGroup string, tests []*test.Test, preset *test.PreSet, interactive bool) bool {
var result = false
result := false
f := bufio.NewWriter(os.Stdout)

hwAPI := hwapi.GetAPI()
Expand Down Expand Up @@ -156,7 +164,13 @@ func run(testGroup string, tests []*test.Test, preset *test.PreSet, interactive
}
}
data, _ := json.MarshalIndent(t, "", "")
os.WriteFile(logfile, data, 0664)
err := os.WriteFile(logfile, data, 0o664)
if err != nil {
fmt.Println("Error writing log file")
}

// If not interactive, we just print the results and return
result = true
}

for index := range tests {
Expand Down
66 changes: 50 additions & 16 deletions pkg/provisioning/bootguard/bootguard.go
Original file line number Diff line number Diff line change
Expand Up @@ -888,20 +888,42 @@ func (b *BootGuard) BPMKeyMatchKMHash() (bool, error) {
return true, nil
}

// SaneBPMSecurityProps verifies that BPM contains security properties set accordingly to spec
walterchris marked this conversation as resolved.
Show resolved Hide resolved
func (b *BootGuard) SaneBPMSecurityProps() (bool, error) {
// StrictSaneBPMSecurityProps verifies that BPM contains security properties more strictly
func (b *BootGuard) StrictSaneBPMSecurityProps() (bool, error) {
switch b.Version {
case bgheader.Version10:
flags := b.VData.BGbpm.SE[0].Flags
if !flags.DMAProtection() {
return false, fmt.Errorf("dma protection should be enabled for bootguard")
}
walterchris marked this conversation as resolved.
Show resolved Hide resolved
if !flags.AuthorityMeasure() {
return false, fmt.Errorf("pcr-7 data should extended for OS security")
}
if !flags.TPMFailureLeavesHierarchiesEnabled() {
return false, fmt.Errorf("tpm failure should lead to default measurements from PCR0 to PCR7")
}
case bgheader.Version20:
bgFlags := b.VData.CBNTbpm.SE[0].Flags
if !bgFlags.AuthorityMeasure() {
return false, fmt.Errorf("pcr-7 data should extended for OS security")
}
if !bgFlags.TPMFailureLeavesHierarchiesEnabled() {
return false, fmt.Errorf("tpm failure should lead to default measurements from PCR0 to PCR7")
}
txtFlags := b.VData.CBNTbpm.TXTE.ControlFlags
if txtFlags.MemoryScrubbingPolicy() != cbntbootpolicy.MemoryScrubbingPolicySACM {
return false, fmt.Errorf("S-ACM memory scrubbing should be used over the BIOS")
}
}

return b.SaneBPMSecurityProps()
}

// SaneBPMSecurityProps verifies that BPM contains security properties set accordingly to spec
func (b *BootGuard) SaneBPMSecurityProps() (bool, error) {
switch b.Version {
case bgheader.Version10:
flags := b.VData.BGbpm.SE[0].Flags
if !flags.DMAProtection() {
return false, fmt.Errorf("dma protection should be enabled for bootguard")
}
walterchris marked this conversation as resolved.
Show resolved Hide resolved
if b.VData.BGbpm.SE[0].PBETValue.PBETValue() == 0 {
return false, fmt.Errorf("firmware shall not allowed to run infinitely after incident happened")
}
Expand All @@ -912,19 +934,10 @@ func (b *BootGuard) SaneBPMSecurityProps() (bool, error) {
return false, fmt.Errorf("dma protection should be enabled for bootguard")
}
}
if !bgFlags.AuthorityMeasure() {
return false, fmt.Errorf("pcr-7 data should extended for OS security")
}
if !bgFlags.TPMFailureLeavesHierarchiesEnabled() {
return false, fmt.Errorf("tpm failure should lead to default measurements from PCR0 to PCR7")
}
if b.VData.BGbpm.SE[0].PBETValue.PBETValue() == 0 {
if b.VData.CBNTbpm.SE[0].PBETValue.PBETValue() == 0 {
return false, fmt.Errorf("firmware shall not allowed to run infinitely after incident happened")
}
txtFlags := b.VData.CBNTbpm.TXTE.ControlFlags
if txtFlags.MemoryScrubbingPolicy() != cbntbootpolicy.MemoryScrubbingPolicySACM {
return false, fmt.Errorf("S-ACM memory scrubbing should be used over the BIOS")
}
if !txtFlags.IsSACMRequestedToExtendStaticPCRs() {
return false, fmt.Errorf("S-ACM shall always extend static PCRs")
}
Expand Down Expand Up @@ -965,7 +978,7 @@ func (b *BootGuard) ValidateMEAgainstManifests(fws *FirmwareStatus6) (bool, erro
return false, fmt.Errorf("km KMID doesn't match me configuration")
}
case bgheader.Version20:
if fws.BPMSVN != uint32(b.VData.CBNTbpm.BPMSVN) {
if fws.BPMSVN > uint32(b.VData.CBNTbpm.BPMSVN) {
return false, fmt.Errorf("bpm svn doesn't match me configuration")
}
if fws.KMSVN != uint32(b.VData.CBNTkm.KMSVN) {
Expand All @@ -977,3 +990,24 @@ func (b *BootGuard) ValidateMEAgainstManifests(fws *FirmwareStatus6) (bool, erro
}
return true, nil
}

// Validate if HFSTS1 is sane
func (b *BootGuard) ValidateHFSTS1(fws *FirmwareStatus1) (bool, error) {
if fws.WorkingState != 0x05 {
return false, fmt.Errorf("HFSTS1 working state is not 0x05")
}

if fws.FPTBad {
return false, fmt.Errorf("FPT bad")
}

if fws.MfgMode {
return false, fmt.Errorf("ME is in manufacturing mode")
}

if fws.ErrorCode != 0 {
return false, fmt.Errorf("HFSTS1 error code is not 0")
}

return true, nil
}
138 changes: 138 additions & 0 deletions pkg/provisioning/bootguard/hfsts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package bootguard

import (
"encoding/binary"
"fmt"

"github.com/9elements/go-linux-lowlevel-hw/pkg/hwapi"
)

// Const Array with HFSTS Offsets
var hfstsOffset = []int{0x40, 0x48, 0x60, 0x64, 0x68, 0x6c}

type FirmwareStatus1 struct {
WorkingState uint32
MfgMode bool
FPTBad bool
OperatingState uint32
FWInitComplete bool
FTBUPLoaded bool
FWUpdateInProgress bool
ErrorCode uint32
OperatingMode uint32
ResetCount uint32
BootOptionPresent bool
BISTFinished bool
BISTTestState bool
BISTResetRequest bool
}

type FirmwareStatus6 struct {
ForceACMBootPolicy bool
CPUDebugDisabled bool
BSPInitDisabled bool
ProtectBIOSEnvironment bool
BypassBootPolicy bool
BootPolicyInvalid bool
ErrorEnforcementPolicy uint32
MeasuredBootPolicy bool
VerifiedBootPolicy bool
ACMSVN uint32
KMSVN uint32
BPMSVN uint32
KMID uint32
BootPolicyManifestExecutionStatus bool
Error bool
BootGuardDisable bool
FPFDisable bool
FPFLock bool
TXTSupported bool
}

func GetHFSTS1(hw hwapi.LowLevelHardwareInterfaces) (*FirmwareStatus1, error) {
hfsts1, err := readHFSTSFromPCIConfigSpace(hw, 1)
if err != nil {
return nil, fmt.Errorf("couldn't read HFSTS6 from PCI config space: %v", err)
}

firmwareStatus := FirmwareStatus1{}

configSpace := binary.LittleEndian.Uint32(hfsts1)

firmwareStatus.WorkingState = (configSpace >> 0) & 15
firmwareStatus.MfgMode = (configSpace>>4)&1 != 0
firmwareStatus.FPTBad = (configSpace>>5)&1 != 0
firmwareStatus.OperatingState = (configSpace >> 6) & 7
firmwareStatus.FWInitComplete = (configSpace>>9)&1 != 0
firmwareStatus.FTBUPLoaded = (configSpace>>10)&1 != 0
firmwareStatus.FWUpdateInProgress = (configSpace>>11)&1 != 0
firmwareStatus.ErrorCode = (configSpace >> 12) & 15
firmwareStatus.OperatingMode = (configSpace >> 16) & 15
firmwareStatus.ResetCount = (configSpace >> 20) & 15
firmwareStatus.BootOptionPresent = (configSpace>>24)&1 != 0
firmwareStatus.BISTFinished = (configSpace>>25)&1 != 0
firmwareStatus.BISTTestState = (configSpace>>26)&1 != 0
firmwareStatus.BISTResetRequest = (configSpace>>27)&1 != 0

return &firmwareStatus, nil
}

func GetHFSTS6(hw hwapi.LowLevelHardwareInterfaces) (*FirmwareStatus6, error) {
hfsts6, err := readHFSTSFromPCIConfigSpace(hw, 6)
if err != nil {
return nil, fmt.Errorf("couldn't read HFSTS6 from PCI config space: %v", err)
}

firmwareStatus := FirmwareStatus6{}

configSpace := binary.LittleEndian.Uint32(hfsts6)
firmwareStatus.ForceACMBootPolicy = (configSpace>>0)&1 != 0
firmwareStatus.CPUDebugDisabled = (configSpace>>1)&1 != 0
firmwareStatus.BSPInitDisabled = (configSpace>>2)&1 != 0
firmwareStatus.ProtectBIOSEnvironment = (configSpace>>3)&1 != 0
firmwareStatus.BypassBootPolicy = (configSpace>>4)&1 != 0
firmwareStatus.BootPolicyInvalid = (configSpace>>5)&1 != 0
firmwareStatus.ErrorEnforcementPolicy = (configSpace >> 6) & 3
firmwareStatus.MeasuredBootPolicy = (configSpace>>8)&1 != 0
firmwareStatus.VerifiedBootPolicy = (configSpace>>9)&1 != 0
firmwareStatus.ACMSVN = (configSpace >> 10) & 15
firmwareStatus.KMSVN = (configSpace >> 14) & 15
firmwareStatus.BPMSVN = (configSpace >> 18) & 15
firmwareStatus.KMID = (configSpace >> 22) & 15
firmwareStatus.BootPolicyManifestExecutionStatus = (configSpace>>26)&1 != 0
firmwareStatus.Error = (configSpace>>27)&1 != 0
firmwareStatus.BootGuardDisable = (configSpace>>28)&1 != 0
firmwareStatus.FPFDisable = (configSpace>>29)&1 != 0
firmwareStatus.FPFLock = (configSpace>>30)&1 != 0
firmwareStatus.TXTSupported = (configSpace>>31)&1 != 0

return &firmwareStatus, nil
}

func readHFSTSFromPCIConfigSpace(hw hwapi.LowLevelHardwareInterfaces, offset int) ([]byte, error) {
if offset < 1 || offset > 6 {
return nil, fmt.Errorf("invalid HFSTS offset")
}

var err error
hfsts := make([]byte, 4)
if err := hw.PCIEnumerateVisibleDevices(
func(d hwapi.PCIDevice) (abort bool) {
if (d.Device == IntelCSMEDeviceID && d.Function == IntelFunction) ||
(d.Device == IntelSPSDeviceID && d.Function == IntelFunction) {
hfsts, err = hw.PCIReadConfigSpace(d, hfstsOffset[offset-1], len(hfsts))
if err != nil {
return true
}
return true
}
return false
}); err != nil {
return nil, fmt.Errorf("couldn't enumerate PCI devices")
}
if err != nil {
return nil, fmt.Errorf("couldn't find Intel ME device for runtime checks")
}

return hfsts, nil
}
Loading
Loading