Skip to content
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
18 changes: 18 additions & 0 deletions efi/preinstall/check_host_security.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,24 @@ const (
dtpmPartialResetAttackMitigationUnavailable
)

// platformFirmwareIntegrityConfig indicates how the root-of-trust provides
// assurances of the platform firmware integrity.
type platformFirmwareIntegrityConfig int

const (
// platformFirmwareIntegrityNone indicates that no firmware integrity assurances
// are provided.
platformFirmwareIntegrityNone platformFirmwareIntegrityConfig = iota

// platformFirmwareIntegrityMeasured indicates that firmware integrity is provided
// by measured boot.
platformFirmwareIntegrityMeasured

// platformFirmwareIntegrityVerified indicates that firmware integrity is provided
// by verifying it against a key that is fused into the platform.
platformFirmwareIntegrityVerified
)

// checkForKernelIOMMU checks that the kernel has enabled some sort of DMA protection.
// On Intel devices, the domains are defined by the DMAR ACPI table. The check is quite
// simple, and based on the fwupd HSI checks. If it is not enabled, a [ErrNoKernelIOMMU]
Expand Down
49 changes: 32 additions & 17 deletions efi/preinstall/check_host_security_amd.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func readAMDPSPBooleanAttribute(dev internal_efi.SysfsDevice, name string) (bool
return strconv.ParseBool(string(bytes.TrimSuffix(data, []byte("\n"))))
}

func checkHostSecurityAMDPSP(env internal_efi.HostEnvironment) error {
func checkHostSecurityAMDPSP(env internal_efi.HostEnvironment) (platformFirmwareIntegrityConfig, error) {
// Enumerate the PCI devices that are bound to the ccp driver.
devices, err := env.EnumerateDevices(&netlink.RuleDefinition{
Env: map[string]string{
Expand All @@ -56,7 +56,7 @@ func checkHostSecurityAMDPSP(env internal_efi.HostEnvironment) error {
},
})
if err != nil {
return fmt.Errorf("cannot obtain PCI devices that are bound to the ccp driver: %w", err)
return platformFirmwareIntegrityNone, fmt.Errorf("cannot obtain PCI devices that are bound to the ccp driver: %w", err)
}

if len(devices) == 0 {
Expand All @@ -70,39 +70,54 @@ func checkHostSecurityAMDPSP(env internal_efi.HostEnvironment) error {
},
})
if err != nil {
return fmt.Errorf("cannot enumerate AMD PCI CCP devices: %w", err)
return platformFirmwareIntegrityNone, fmt.Errorf("cannot enumerate AMD PCI CCP devices: %w", err)
}
if len(devices) == 0 {
// We can't find the PSP device, so this platform is unsupported.
return &UnsupportedPlatformError{errors.New("no PSP PCI device")}
return platformFirmwareIntegrityNone, &UnsupportedPlatformError{errors.New("no PSP PCI device")}
}

// We found the PSP device, so indicate that the ccp module should
// be loaded.
return MissingKernelModuleError("ccp")
return platformFirmwareIntegrityNone, MissingKernelModuleError("ccp")
}

device := devices[0]

debugLock, err := readAMDPSPBooleanAttribute(device, "debug_lock_on")
switch {
amd64Env, err := env.AMD64()
if err != nil {
return platformFirmwareIntegrityNone, fmt.Errorf("cannot obtain AMD64 environment: %w", err)
}
if amd64Env.CPUFamily() < 0x17 {
// Require at least Zen.
return platformFirmwareIntegrityNone, &UnsupportedPlatformError{errors.New("unsupported CPU family")}
}

switch debugLock, err := readAMDPSPBooleanAttribute(device, "debug_lock_on"); {
case errors.Is(err, internal_efi.ErrNoDeviceAttribute):
return &NoHardwareRootOfTrustError{errors.New("PSP security reporting not available")}
return platformFirmwareIntegrityNone, &NoHardwareRootOfTrustError{errors.New("PSP security reporting not available")}
case err != nil:
return fmt.Errorf("cannot determine if debug lock is on: %w", err)
return platformFirmwareIntegrityNone, fmt.Errorf("cannot determine if debug lock is on: %w", err)
case !debugLock:
return &NoHardwareRootOfTrustError{errors.New("PSP debug lock is not enabled")}
return platformFirmwareIntegrityNone, &NoHardwareRootOfTrustError{errors.New("PSP debug lock is not enabled")}
}

fused, err := readAMDPSPBooleanAttribute(device, "fused_part")
switch {
case errors.Is(err, internal_efi.ErrNoDeviceAttribute):
return &NoHardwareRootOfTrustError{errors.New("PSP security reporting not available")}
switch fused, err := readAMDPSPBooleanAttribute(device, "fused_part"); {
case err != nil:
return fmt.Errorf("cannot determine if PSB is enabled: %w", err)
return platformFirmwareIntegrityNone, fmt.Errorf("cannot determine if part is fused: %w", err)
case !fused:
return &NoHardwareRootOfTrustError{errors.New("Platform Secure Boot is not enabled")}
return platformFirmwareIntegrityMeasured, nil
}

switch integrity, err := readAMDPSPBooleanAttribute(device, "boot_integrity"); {
case errors.Is(err, internal_efi.ErrNoDeviceAttribute):
// Only exists since https://lore.kernel.org/linux-crypto/20260123033457.645189-1-superm1@kernel.org/
return platformFirmwareIntegrityMeasured, nil
case err != nil:
return platformFirmwareIntegrityNone, fmt.Errorf("cannot determine if PSB is enabled: %w", err)
case !integrity:
return platformFirmwareIntegrityMeasured, nil
}

return nil
return platformFirmwareIntegrityVerified, nil
}
25 changes: 14 additions & 11 deletions efi/preinstall/check_host_security_amd64.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,28 +31,31 @@ import (
// is sufficient. Errors that can't be resolved or which should prevent further checks from running
// are returned immediately and without any wrapping. Errors that can be resolved and which shouldn't
// prevent further checks from running are returned wrapped in [joinError].
func checkHostSecurity(env internal_efi.HostEnvironment, log *tcglog.Log) error {
func checkHostSecurity(env internal_efi.HostEnvironment, log *tcglog.Log) (platformFirmwareIntegrityConfig, error) {
cpuVendor, err := determineCPUVendor(env)
if err != nil {
return &UnsupportedPlatformError{fmt.Errorf("cannot determine CPU vendor: %w", err)}
return platformFirmwareIntegrityNone, &UnsupportedPlatformError{fmt.Errorf("cannot determine CPU vendor: %w", err)}
}

amd64Env, err := env.AMD64()
if err != nil {
return fmt.Errorf("cannot obtain AMD64 environment: %w", err)
return platformFirmwareIntegrityNone, fmt.Errorf("cannot obtain AMD64 environment: %w", err)
}

var integrity platformFirmwareIntegrityConfig
switch cpuVendor {
case cpuVendorIntel:
if err := checkHostSecurityIntelBootGuard(env); err != nil {
return fmt.Errorf("encountered an error when checking Intel BootGuard configuration: %w", err)
return platformFirmwareIntegrityNone, fmt.Errorf("encountered an error when checking Intel BootGuard configuration: %w", err)
}
if err := checkHostSecurityIntelCPUDebuggingLocked(amd64Env); err != nil {
return fmt.Errorf("encountered an error when checking Intel CPU debugging configuration: %w", err)
return platformFirmwareIntegrityNone, fmt.Errorf("encountered an error when checking Intel CPU debugging configuration: %w", err)
}
integrity = platformFirmwareIntegrityVerified
case cpuVendorAMD:
if err := checkHostSecurityAMDPSP(env); err != nil {
return fmt.Errorf("encountered an error when checking the AMD PSP configuration: %w", err)
integrity, err = checkHostSecurityAMDPSP(env)
if err != nil {
return platformFirmwareIntegrityNone, fmt.Errorf("encountered an error when checking the AMD PSP configuration: %w", err)
}
default:
panic("not reached")
Expand All @@ -63,7 +66,7 @@ func checkHostSecurity(env internal_efi.HostEnvironment, log *tcglog.Log) error
if err := checkSecureBootPolicyPCRForDegradedFirmwareSettings(log); err != nil {
var ce CompoundError
if !errors.As(err, &ce) {
return fmt.Errorf("encountered an error whilst checking the TCG log for degraded firmware settings: %w", err)
return platformFirmwareIntegrityNone, fmt.Errorf("encountered an error whilst checking the TCG log for degraded firmware settings: %w", err)
}
errs = append(errs, ce.Unwrap()...)
}
Expand All @@ -72,15 +75,15 @@ func checkHostSecurity(env internal_efi.HostEnvironment, log *tcglog.Log) error
case errors.Is(err, ErrNoKernelIOMMU):
errs = append(errs, err)
default:
return fmt.Errorf("encountered an error whilst checking sysfs to determine that kernel IOMMU support is enabled: %w", err)
return platformFirmwareIntegrityNone, fmt.Errorf("encountered an error whilst checking sysfs to determine that kernel IOMMU support is enabled: %w", err)
}
}

if len(errs) > 0 {
return joinErrors(errs...)
return platformFirmwareIntegrityNone, joinErrors(errs...)
}

return nil
return integrity, nil
}

// checkDiscreteTPMPartialResetAttackMitigationStatus determines whether a partial mitigation
Expand Down
Loading
Loading