From 2ae44a829e37e4b443413ff215cb82e6d7f1f5e3 Mon Sep 17 00:00:00 2001 From: Frederic Hoerni Date: Mon, 22 Jun 2026 09:40:55 +0200 Subject: [PATCH 1/2] efi/preinstall: add PermitNoHardwareRootOfTrust This changes the way RunChecksContext.Run() handles NoHardwareRootOfTrustError. Run() with no action will raise NoHardwareRootOfTrustError as before but will continue the preinstall compatibility analysis and suggest a corrective action using PermitNoHardwareRootOfTrust. The related error kind is ErrorKindNoHardwareRootOfTrust. Run() with ActionProceed and PermitNoHardwareRootOfTrust will ignore the error and continue the preinstall compatibility analysis. --- cmd/test_efi_fde_compat/main.go | 4 ++++ efi/preinstall/check_host_security_amd64.go | 22 ++++++++++++++++----- efi/preinstall/checks.go | 11 ++++++++++- efi/preinstall/checks_context.go | 9 +++++++++ efi/preinstall/error_kinds.go | 5 +++++ efi/preinstall/errors.go | 2 +- 6 files changed, 46 insertions(+), 7 deletions(-) diff --git a/cmd/test_efi_fde_compat/main.go b/cmd/test_efi_fde_compat/main.go index 6d195340..8df39da3 100644 --- a/cmd/test_efi_fde_compat/main.go +++ b/cmd/test_efi_fde_compat/main.go @@ -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 { @@ -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 { diff --git a/efi/preinstall/check_host_security_amd64.go b/efi/preinstall/check_host_security_amd64.go index 4a5f30df..9571ca12 100644 --- a/efi/preinstall/check_host_security_amd64.go +++ b/efi/preinstall/check_host_security_amd64.go @@ -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) { diff --git a/efi/preinstall/checks.go b/efi/preinstall/checks.go index 8981a909..c114e096 100644 --- a/efi/preinstall/checks.go +++ b/efi/preinstall/checks.go @@ -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 @@ -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 ( @@ -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}) } diff --git a/efi/preinstall/checks_context.go b/efi/preinstall/checks_context.go index ae8a41aa..d10e45c3 100644 --- a/efi/preinstall/checks_context.go +++ b/efi/preinstall/checks_context.go @@ -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{ @@ -165,6 +168,7 @@ func init() { ErrorKindAbsolutePresent: PermitAbsoluteComputrace, ErrorKindWeakSecureBootAlgorithmsDetected: PermitWeakSecureBootAlgorithms, ErrorKindPreOSSecureBootAuthByEnrolledDigests: PermitPreOSSecureBootAuthByEnrolledDigests, + ErrorKindNoHardwareRootOfTrust: PermitNoHardwareRootOfTrust, } errorKindWithArgsToProceedFlag = map[errorKindWithArgs]CheckFlags{ @@ -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 diff --git a/efi/preinstall/error_kinds.go b/efi/preinstall/error_kinds.go index a570c52f..f9c41329 100644 --- a/efi/preinstall/error_kinds.go +++ b/efi/preinstall/error_kinds.go @@ -215,6 +215,11 @@ const ( // TODO: it might be worth attempting to match the verification with a corresponding // launch event from PCR2 or PCR4 to grab the device path and include it as an argument. ErrorKindPreOSSecureBootAuthByEnrolledDigests ErrorKind = "pre-os-secure-boot-auth-by-enrolled-digests" + + // ErrorKindNoHardwareRootOfTrust indicates that the platform's UEFI firmware is not + // verified nor measured by a hardware root of trust (typically Boot Guard Authenticated + // Code Module (ACM) on Intel systems and Platform Secure Boot (PSB) enabled on AMD systems. + ErrorKindNoHardwareRootOfTrust ErrorKind = "no-hardware-root-of-trust" ) // PCRUnusableArg represents an unusable PCR handle that can be diff --git a/efi/preinstall/errors.go b/efi/preinstall/errors.go index 555dbcff..1d14419a 100644 --- a/efi/preinstall/errors.go +++ b/efi/preinstall/errors.go @@ -214,7 +214,7 @@ func (e *HostSecurityError) Unwrap() error { // NoHardwareRootOfTrustError is returned wrapped in [HostSecurityError] if the platform // firmware is not protected by a properly configured hardware root-of-trust. This won't // be returned if the PermitVirtualMachine flag is supplied to [RunChecks] and the current -// environment is a virtual machine. +// environment is a virtual machine, or if the PermitNoHardwareRootOfTrust flag is supplied. type NoHardwareRootOfTrustError struct { err error } From c84837e6b6f31fca4b387443fd6a1bdc01d5dee7 Mon Sep 17 00:00:00 2001 From: Frederic Hoerni Date: Mon, 15 Jun 2026 14:31:02 +0200 Subject: [PATCH 2/2] efi/preinstall: align tests for NoHardwareRootOfTrust --- .../check_host_security_amd64_test.go | 29 +++++- efi/preinstall/checks_context_test.go | 76 ++++++++++++++- efi/preinstall/checks_test.go | 92 ++++++++++++++++++- 3 files changed, 187 insertions(+), 10 deletions(-) diff --git a/efi/preinstall/check_host_security_amd64_test.go b/efi/preinstall/check_host_security_amd64_test.go index d3e3f5e1..2ea4892e 100644 --- a/efi/preinstall/check_host_security_amd64_test.go +++ b/efi/preinstall/check_host_security_amd64_test.go @@ -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, )), @@ -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`) } @@ -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`) } diff --git a/efi/preinstall/checks_context_test.go b/efi/preinstall/checks_context_test.go index cb9c3b99..e7ed9448 100644 --- a/efi/preinstall/checks_context_test.go +++ b/efi/preinstall/checks_context_test.go @@ -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 @@ -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{ @@ -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) { diff --git a/efi/preinstall/checks_test.go b/efi/preinstall/checks_test.go index 9bd8fe96..d1a5a4cb 100644 --- a/efi/preinstall/checks_test.go +++ b/efi/preinstall/checks_test.go @@ -2836,21 +2836,40 @@ func (s *runChecksSuite) TestRunChecksBadNoHardwareRootOfTrustError(c *C) { 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{0xc80: 0x40000000, 0x13a: (3 << 1)}), efitest.WithSysfsDevices(devices...), - efitest.WithMockVars(efitest.MockVars{}.SetSecureBoot(false)), + 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}, - flags: PermitNoPlatformConfigProfileSupport | PermitNoDriversAndAppsConfigProfileSupport | PermitNoBootManagerConfigProfileSupport, + enabledBanks: []tpm2.HashAlgorithmId{tpm2.HashAlgorithmSHA256}, + flags: PermitNoPlatformConfigProfileSupport | PermitNoDriversAndAppsConfigProfileSupport | PermitNoBootManagerConfigProfileSupport, + loadedImages: efiImagesDefault(), + expectedPcrAlg: tpm2.HashAlgorithmSHA256, + expectedUsedSecureBootCAs: []*X509CertificateID{NewX509CertificateID(testutil.ParseCertificate(c, msUefiCACert))}, + expectedFlags: NoPlatformConfigProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerConfigProfileSupport, }) c.Check(err, 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`) + // Check that there is a NoHardwareRootOfTrustError wrapped in a HostSecurityError + // While with go1.23 errors.As() can unwrap automatically, with go1.18 we need to unwrap manually. var hse *HostSecurityError - c.Assert(errors.As(err, &hse), testutil.IsTrue) + var cErr CompoundError + c.Check(errors.As(err, &cErr), testutil.IsTrue) + foundHse := false + for _, e := range cErr.Unwrap() { + if errors.As(e, &hse) { + foundHse = true + } + } + c.Check(foundHse, testutil.IsTrue) var rote *NoHardwareRootOfTrustError c.Check(errors.As(hse, &rote), testutil.IsTrue) } @@ -4157,3 +4176,68 @@ func (s *runChecksSuite) TestRunChecksAllowInsufficientDMAProtection(c *C) { var bmce *BootManagerConfigPCRError c.Check(errors.As(warning, &bmce), testutil.IsTrue) } + +func (s *runChecksSuite) TestRunChecksAllowNoHardwareRootOfTrust(c *C) { + // Test that PermitNoHardwareRootOfTrust converts related errors to warnings + 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, + )), + } + + warnings, err := s.testRunChecks(c, &testRunChecksParams{ + 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{0xc80: 0x40000000, 0x13a: (3 << 1)}), + 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}, + flags: PermitNoPlatformConfigProfileSupport | PermitNoDriversAndAppsConfigProfileSupport | PermitNoBootManagerConfigProfileSupport | PermitNoHardwareRootOfTrust, + loadedImages: efiImagesDefault(), + expectedPcrAlg: tpm2.HashAlgorithmSHA256, + expectedUsedSecureBootCAs: []*X509CertificateID{NewX509CertificateID(testutil.ParseCertificate(c, msUefiCACert))}, + expectedFlags: NoPlatformConfigProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerConfigProfileSupport, + }) + c.Assert(err, IsNil) + c.Assert(warnings, HasLen, 4) + + warning := warnings[0] + c.Check(warning, ErrorMatches, "encountered an error when checking Intel BootGuard configuration: no hardware root-of-trust properly configured: system is in manufacturing mode") + var nohwrot *NoHardwareRootOfTrustError + c.Check(errors.As(warning, &nohwrot), testutil.IsTrue) + + // Do not check the error messages below, as it is verified in another test + warning = warnings[1] + var pce *PlatformConfigPCRError + c.Check(errors.As(warning, &pce), testutil.IsTrue) + + warning = warnings[2] + var dce *DriversAndAppsConfigPCRError + c.Check(errors.As(warning, &dce), testutil.IsTrue) + + warning = warnings[3] + var bmce *BootManagerConfigPCRError + c.Check(errors.As(warning, &bmce), testutil.IsTrue) +}