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
4 changes: 4 additions & 0 deletions cmd/test_efi_fde_compat/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type options struct {
PermitWeakSecureBootAlgorithms bool `long:"permit-weak-secure-boot-algs" description:"Permit secure boot verification using weak algorithms"`
PermitPreOSSecureBootAuthByEnrolledDigests bool `long:"permit-preos-secure-boot-auth-by-enrolled-digests" description:"Allow pre-OS components to be verified by including a digest in db. This increases fragility of profiles that include PCR7"`
PermitInsufficientDMAProtection bool `long:"permit-insufficient-dma-protection" description:"Permit environments that don't have sufficient DMA protection"`
PermitNoHardwareRootOfTrust bool `long:"permit-no-hw-root-of-trust" description:"Permit platforms that don't have a HW root of trust"`
} `group:"Initial check options"`

Profile struct {
Expand Down Expand Up @@ -75,6 +76,9 @@ func run() error {
if opts.Check.PermitInsufficientDMAProtection {
checkFlags |= preinstall.PermitInsufficientDMAProtection
}
if opts.Check.PermitNoHardwareRootOfTrust {
checkFlags |= preinstall.PermitNoHardwareRootOfTrust
}

var bootImages []secboot_efi.Image
for _, img := range opts.Positional.BootImages {
Expand Down
22 changes: 17 additions & 5 deletions efi/preinstall/check_host_security_amd64.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,27 +42,39 @@ func checkHostSecurity(env internal_efi.HostEnvironment, log *tcglog.Log) (platf
return platformFirmwareIntegrityNone, fmt.Errorf("cannot obtain AMD64 environment: %w", err)
}

var errs []error

var integrity platformFirmwareIntegrityConfig
switch cpuVendor {
case cpuVendorIntel:
if err := checkHostSecurityIntelBootGuard(env); err != nil {
return platformFirmwareIntegrityNone, fmt.Errorf("encountered an error when checking Intel BootGuard configuration: %w", err)
var nohwrotErr *NoHardwareRootOfTrustError
ctxErr := fmt.Errorf("encountered an error when checking Intel BootGuard configuration: %w", err)
if !errors.As(err, &nohwrotErr) {
return platformFirmwareIntegrityNone, ctxErr
}
errs = append(errs, ctxErr)
}
if err := checkHostSecurityIntelCPUDebuggingLocked(amd64Env); err != nil {
return platformFirmwareIntegrityNone, fmt.Errorf("encountered an error when checking Intel CPU debugging configuration: %w", err)
}
integrity = platformFirmwareIntegrityVerified
if len(errs) == 0 {
integrity = platformFirmwareIntegrityVerified
}
case cpuVendorAMD:
integrity, err = checkHostSecurityAMDPSP(env)
if err != nil {
return platformFirmwareIntegrityNone, fmt.Errorf("encountered an error when checking the AMD PSP configuration: %w", err)
ctxErr := fmt.Errorf("encountered an error when checking the AMD PSP configuration: %w", err)
var nohwrotErr *NoHardwareRootOfTrustError
if !errors.As(err, &nohwrotErr) {
return platformFirmwareIntegrityNone, ctxErr
}
errs = append(errs, ctxErr)
}
default:
panic("not reached")
}

var errs []error

if err := checkSecureBootPolicyPCRForDegradedFirmwareSettings(log); err != nil {
var ce CompoundError
if !errors.As(err, &ce) {
Expand Down
29 changes: 25 additions & 4 deletions efi/preinstall/check_host_security_amd64_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ func (s *hostSecurityAMD64Suite) TestCheckHostSecurityIntelErrMEI(c *C) {
"fw_status": fwStatusManufacturingMode,
}
devices := []internal_efi.SysfsDevice{
efitest.NewMockSysfsDevice("/sys/devices/virtual/iommu/dmar0", nil, "iommu", nil, nil),
efitest.NewMockSysfsDevice("/sys/devices/pci0000:00/0000:00:16.0/mei/mei0", map[string]string{"DEVNAME": "mei0"}, "mei", meiAttrs, efitest.NewMockSysfsDevice(
"/sys/devices/pci0000:00:16:0", map[string]string{"DRIVER": "mei_me"}, "pci", nil, nil,
)),
Expand All @@ -151,12 +152,22 @@ func (s *hostSecurityAMD64Suite) TestCheckHostSecurityIntelErrMEI(c *C) {
efitest.WithSysfsDevices(devices...),
efitest.WithAMD64Environment("GenuineIntel", 0x6, nil, 0, nil),
)

_, err := CheckHostSecurity(env, nil)
log := efitest.NewLog(c, &efitest.LogOptions{})
_, err := CheckHostSecurity(env, log)
c.Check(err, ErrorMatches, `encountered an error when checking Intel BootGuard configuration: no hardware root-of-trust properly configured: system is in manufacturing mode`)

// Check that there is a NoHardwareRootOfTrustError
// While with go1.23 errors.As() can unwrap automatically, with go1.18 we need to unwrap manually.
var nhrotErr *NoHardwareRootOfTrustError
c.Check(errors.As(err, &nhrotErr), testutil.IsTrue)
var cErr CompoundError
c.Check(errors.As(err, &cErr), testutil.IsTrue)
foundNhrot := false
for _, e := range cErr.Unwrap() {
if errors.As(e, &nhrotErr) {
foundNhrot = true
}
}
c.Check(foundNhrot, testutil.IsTrue)
c.Check(nhrotErr, ErrorMatches, `no hardware root-of-trust properly configured: system is in manufacturing mode`)
}

Expand All @@ -175,8 +186,18 @@ func (s *hostSecurityAMD64Suite) TestCheckHostSecurityAMDErrPSP(c *C) {
_, err := CheckHostSecurity(env, log)
c.Check(err, ErrorMatches, `encountered an error when checking the AMD PSP configuration: no hardware root-of-trust properly configured: PSP security reporting not available`)

// Check that there is a NoHardwareRootOfTrustError
// While with go1.23 errors.As() can unwrap automatically, with go1.18 we need to unwrap manually.
var nhrotErr *NoHardwareRootOfTrustError
c.Check(errors.As(err, &nhrotErr), testutil.IsTrue)
var cErr CompoundError
c.Check(errors.As(err, &cErr), testutil.IsTrue)
foundNhrot := false
for _, e := range cErr.Unwrap() {
if errors.As(e, &nhrotErr) {
foundNhrot = true
}
}
c.Check(foundNhrot, testutil.IsTrue)
c.Check(nhrotErr, ErrorMatches, `no hardware root-of-trust properly configured: PSP security reporting not available`)
}

Expand Down
11 changes: 10 additions & 1 deletion efi/preinstall/checks.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const (
// PCR 0 is optional.
PermitNoPlatformFirmwareProfileSupport CheckFlags = 1 << iota

// PermitNoPlatformConfigProfileSupportd indicates that support for
// PermitNoPlatformConfigProfileSupport indicates that support for
// generating profiles for PCR 1 is not optional.
//
// Note that this is currently mandatory because this profile is not
Expand Down Expand Up @@ -147,6 +147,10 @@ const (
// PermitSecureBootUserMode will prevent RunChecks from returning an error if secure
// boot is enabled but not in deployed mode on systems that support UEFI >= 2.5.
PermitSecureBootUserMode

// PermitNoHardwareRootOfTrust will prevent RunChecks from returning an error if
// the platform firmware is not protected by a properly configured hardware root-of-trust.
PermitNoHardwareRootOfTrust
)

var (
Expand Down Expand Up @@ -308,14 +312,19 @@ func RunChecks(ctx context.Context, flags CheckFlags, loadedImages []secboot_efi
if virtMode == detectVirtNone {
// Only run host security checks if we are not in a VM
fwIntegrity, err := checkHostSecurity(runChecksEnv, log)

if err != nil {
// Either a simple error or a compound error
var ce CompoundError
if !errors.As(err, &ce) {
return nil, &HostSecurityError{err}
}
for _, e := range ce.Unwrap() {
var nohwrotErr *NoHardwareRootOfTrustError
if (errors.Is(e, ErrInsufficientDMAProtection) || errors.Is(e, ErrNoKernelIOMMU)) && flags&PermitInsufficientDMAProtection > 0 {
warnings = append(warnings, e)
} else if errors.As(e, &nohwrotErr) && flags&PermitNoHardwareRootOfTrust > 0 {
warnings = append(warnings, e)
} else {
deferredErrs = append(deferredErrs, &HostSecurityError{e})
}
Expand Down
9 changes: 9 additions & 0 deletions efi/preinstall/checks_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,9 @@ func init() {
ErrorKindPreOSSecureBootAuthByEnrolledDigests: []Action{
// TODO: Add action to add PermitPreOSSecureBootAuthByEnrolledDigests to CheckFlags.
},
ErrorKindNoHardwareRootOfTrust: []Action{
// TODO: Add action to add PermitNoHardwareRootOfTrust to CheckFlags.
},
}

errorKindToProceedFlag = map[ErrorKind]CheckFlags{
Expand All @@ -165,6 +168,7 @@ func init() {
ErrorKindAbsolutePresent: PermitAbsoluteComputrace,
ErrorKindWeakSecureBootAlgorithmsDetected: PermitWeakSecureBootAlgorithms,
ErrorKindPreOSSecureBootAuthByEnrolledDigests: PermitPreOSSecureBootAuthByEnrolledDigests,
ErrorKindNoHardwareRootOfTrust: PermitNoHardwareRootOfTrust,
}

errorKindWithArgsToProceedFlag = map[errorKindWithArgs]CheckFlags{
Expand Down Expand Up @@ -516,6 +520,11 @@ func (c *RunChecksContext) classifyRunChecksError(ctx context.Context, err error
return errorInfo{kind: ErrorKindNoKernelIOMMU}, nil
}

var nohwrotErr *NoHardwareRootOfTrustError
if errors.As(err, &nohwrotErr) {
return errorInfo{kind: ErrorKindNoHardwareRootOfTrust}, nil
}

var hsErr *HostSecurityError
if errors.As(err, &hsErr) {
return errorInfo{kind: ErrorKindHostSecurity}, nil
Expand Down
76 changes: 74 additions & 2 deletions efi/preinstall/checks_context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,78 @@ func (s *runChecksContextSuite) TestRunGoodActionProceedPermitInsufficientDMAPro
c.Assert(errs, HasLen, 0)
}

func (s *runChecksContextSuite) TestRunGoodActionProceedPermitNoHardwareRootOfTrust(c *C) {
// Test that ActionProceed enables PermitNoHardwareRootOfTrust.
meiAttrs := map[string][]byte{
"fw_ver": []byte(`0:16.1.27.2176
0:16.1.27.2176
0:16.0.15.1624
`),
"fw_status": fwStatusManufacturingMode,
}
devices := []internal_efi.SysfsDevice{
efitest.NewMockSysfsDevice("/sys/devices/virtual/iommu/dmar0", nil, "iommu", nil, nil),
efitest.NewMockSysfsDevice("/sys/devices/virtual/iommu/dmar1", nil, "iommu", nil, nil),
efitest.NewMockSysfsDevice("/sys/devices/pci0000:00/0000:00:16.0/mei/mei0", map[string]string{"DEVNAME": "mei0"}, "mei", meiAttrs, efitest.NewMockSysfsDevice(
"/sys/devices/pci0000:00:16:0", map[string]string{"DRIVER": "mei_me"}, "pci", nil, nil,
)),
}

errs := s.testRun(c, &testRunChecksContextRunParams{
env: efitest.NewMockHostEnvironmentWithOpts(
efitest.WithVirtMode(internal_efi.VirtModeNone, internal_efi.DetectVirtModeAll),
efitest.WithTPMDevice(newTpmDevice(tpm2_testutil.NewTransportBackedDevice(s.Transport, false, 1), nil, tpm2_device.ErrNoPPI)),
efitest.WithLog(efitest.NewLog(c, &efitest.LogOptions{Algorithms: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256}})),
efitest.WithAMD64Environment("GenuineIntel", 0x6, []uint64{cpuid.SDBG, cpuid.SMX}, 4, map[uint32]uint64{0x13a: (3 << 1), 0xc80: 0x40000000}),
efitest.WithSysfsDevices(devices...),
efitest.WithMockVars(efitest.MockVars{
{Name: "AuditMode", GUID: efi.GlobalVariable}: &efitest.VarEntry{Attrs: efi.AttributeNonVolatile | efi.AttributeBootserviceAccess | efi.AttributeRuntimeAccess, Payload: []byte{0x0}},
{Name: "DeployedMode", GUID: efi.GlobalVariable}: &efitest.VarEntry{Attrs: efi.AttributeNonVolatile | efi.AttributeBootserviceAccess | efi.AttributeRuntimeAccess, Payload: []byte{0x1}},
{Name: "SetupMode", GUID: efi.GlobalVariable}: &efitest.VarEntry{Attrs: efi.AttributeBootserviceAccess | efi.AttributeRuntimeAccess, Payload: []byte{0x0}},
{Name: "OsIndicationsSupported", GUID: efi.GlobalVariable}: &efitest.VarEntry{Attrs: efi.AttributeBootserviceAccess | efi.AttributeRuntimeAccess, Payload: []byte{0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
}.SetSecureBoot(true).SetPK(c, efitest.NewSignatureListX509(c, snakeoilCert, efi.MakeGUID(0x03f66fa4, 0x5eee, 0x479c, 0xa408, [...]uint8{0xc4, 0xdc, 0x0a, 0x33, 0xfc, 0xde})))),
),
tpmPropertyModifiers: map[tpm2.Property]uint32{
tpm2.PropertyNVCountersMax: 0,
tpm2.PropertyPSFamilyIndicator: 1,
tpm2.PropertyManufacturer: uint32(tpm2.TPMManufacturerINTC),
},
enabledBanks: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256},
iterations: 2,
loadedImages: efiImagesDefault(),
profileOpts: PCRProfileOptionsDefault,
checkIntermediateErrs: func(i int, errs []*WithKindAndActionsError) {
switch i {
case 0:
c.Assert(errs, HasLen, 1)
c.Check(errs[0], DeepEquals, NewWithKindAndActionsError(
ErrorKindNoHardwareRootOfTrust,
nil,
[]Action{ActionProceed},
errs[0].Unwrap(),
))
}
},
actions: []actionAndArgs{
{action: ActionNone},
{action: ActionProceed},
},
expectedPcrAlg: tpm2.HashAlgorithmSHA256,
expectedUsedSecureBootCAs: []*X509CertificateID{NewX509CertificateID(testutil.ParseCertificate(c, msUefiCACert))},
expectedFlags: NoPlatformConfigProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerConfigProfileSupport,
expectedAcceptedErrors: map[ErrorKind]json.RawMessage{
ErrorKindNoHardwareRootOfTrust: nil,
},
expectedWarningsMatch: `4 errors detected:
- encountered an error when checking Intel BootGuard configuration: no hardware root-of-trust properly configured: system is in manufacturing mode
- error with platform config \(PCR1\) measurements: generating profiles for PCR 1 is not supported yet, see https://github.com/canonical/secboot/issues/322
- error with drivers and apps config \(PCR3\) measurements: generating profiles for PCR 3 is not supported yet, see https://github.com/canonical/secboot/issues/341
- error with boot manager config \(PCR5\) measurements: generating profiles for PCR 5 is not supported yet, see https://github.com/canonical/secboot/issues/323
`,
})
c.Check(errs, HasLen, 0)
}

func (s *runChecksContextSuite) TestRunGoodPostInstall(c *C) {
// Test good post-install scenario on a fTPM, which skips some tests related to
// TPM ownership, lockout status and checking the number of available
Expand Down Expand Up @@ -4415,7 +4487,7 @@ func (s *runChecksContextSuite) TestRunBadHostSecurityErrorMissingMSR(c *C) {
c.Check(errors.Is(errs[0], MissingKernelModuleError("msr")), testutil.IsTrue)
}

func (s *runChecksContextSuite) TestRunBadHostSecurityError(c *C) {
func (s *runChecksContextSuite) TestRunBadNoHardwareRootOfTrust(c *C) {
// Test the error case where we're running on an Intel based device
// and BootGuard is mis-configured.
meiAttrs := map[string][]byte{
Expand Down Expand Up @@ -4452,7 +4524,7 @@ func (s *runChecksContextSuite) TestRunBadHostSecurityError(c *C) {
})
c.Assert(errs, HasLen, 1)
c.Check(errs[0], ErrorMatches, `error with system security: encountered an error when checking Intel BootGuard configuration: no hardware root-of-trust properly configured: system is in manufacturing mode`)
c.Check(errs[0], DeepEquals, NewWithKindAndActionsError(ErrorKindHostSecurity, nil, []Action{ActionContactOEM}, errs[0].Unwrap()))
c.Check(errs[0], DeepEquals, NewWithKindAndActionsError(ErrorKindNoHardwareRootOfTrust, nil, []Action{ActionProceed}, errs[0].Unwrap()))
}

func (s *runChecksContextSuite) TestRunBadSHA1(c *C) {
Expand Down
Loading
Loading