Skip to content

Commit a7fccd4

Browse files
committed
efi/preinstall: Record accepted errors in CheckResult
This records errors accepted via ActionProceed to a new AcceptedErrors field of CheckResult. There are 2 uses for this: - To use accepted errors to turn on options when generating PCR profiles. The WithAllowInsufficientDmaProtection() opt-in makes use of this new field with this PR. Future PRs will add additional opt-ins which make use of this new field. - To compare future check results against, in order to determine whether anything has changed. At the moment, only the accepted error kinds are retained. However, the new field is a map of ErrorKind to arbitrary JSON value so that a future update can use the arbitrary JSON value to record arguments that can limit the scope of an accepted error. Fixes: FR-11919
1 parent fcc9a2a commit a7fccd4

File tree

7 files changed

+115
-18
lines changed

7 files changed

+115
-18
lines changed

efi/preinstall/checks_context.go

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,9 +195,12 @@ type RunChecksContext struct {
195195
// being returned.
196196
expectedActions []Action
197197

198-
// proceedFlags indicates the CheckFlags that will be enabled if Run is called
198+
// proceedFlags indicates the CheckFlags that can be enabled if Run is called
199199
// with ActionProceed.
200200
proceedFlags CheckFlags
201+
202+
// acceptedErrors indicates the ErrorKinds that have been accepted with ActionProceed.
203+
acceptedErrors []ErrorKind
201204
}
202205

203206
// NewRunChecksContext returns a new RunChecksContext instance with the initial flags for [RunChecks]
@@ -729,7 +732,10 @@ func (c *RunChecksContext) runAction(action Action, args map[string]json.RawMess
729732
)
730733
}
731734
case ActionProceed:
732-
var proceedFlags CheckFlags
735+
var (
736+
proceedFlags CheckFlags
737+
acceptedErrors []ErrorKind
738+
)
733739
if args != nil {
734740
const fieldName = "error-kinds"
735741

@@ -775,6 +781,7 @@ func (c *RunChecksContext) runAction(action Action, args map[string]json.RawMess
775781
}
776782

777783
proceedFlags |= flag
784+
acceptedErrors = append(acceptedErrors, kind)
778785
c.proceedFlags &^= flag
779786
}
780787
}
@@ -783,9 +790,16 @@ func (c *RunChecksContext) runAction(action Action, args map[string]json.RawMess
783790
// Handle the case where no argument is supplied or
784791
// an empty []ErrorKind slice is supplied
785792
proceedFlags = c.proceedFlags
793+
for kind, flag := range errorKindToProceedFlag {
794+
if flag&proceedFlags > 0 {
795+
acceptedErrors = append(acceptedErrors, kind)
796+
}
797+
}
798+
c.proceedFlags = 0
786799
}
787800

788801
c.flags |= proceedFlags
802+
c.acceptedErrors = append(c.acceptedErrors, acceptedErrors...)
789803
default:
790804
return NewWithKindAndActionsError(
791805
ErrorKindUnexpectedAction,
@@ -850,6 +864,10 @@ func (c *RunChecksContext) Run(ctx context.Context, action Action, args map[stri
850864
}
851865
if err == nil && profileErr == nil {
852866
// If neither step failed, break and return success.
867+
result.AcceptedErrors = make(map[ErrorKind]json.RawMessage)
868+
for _, kind := range c.acceptedErrors {
869+
result.AcceptedErrors[kind] = nil
870+
}
853871
c.result = result
854872
break
855873
}

efi/preinstall/checks_context_test.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ type testRunChecksContextRunParams struct {
8585
expectedPcrAlg tpm2.HashAlgorithmId
8686
expectedUsedSecureBootCAs []*X509CertificateID
8787
expectedFlags CheckResultFlags
88+
expectedAcceptedErrors map[ErrorKind]json.RawMessage
8889
expectedWarningsMatch string
8990
}
9091

@@ -202,6 +203,11 @@ func (s *runChecksContextSuite) testRun(c *C, params *testRunChecksContextRunPar
202203
c.Check(ca, DeepEquals, params.expectedUsedSecureBootCAs[i])
203204
}
204205
c.Check(result.Flags, Equals, params.expectedFlags)
206+
expectedAcceptedErrors := params.expectedAcceptedErrors
207+
if expectedAcceptedErrors == nil {
208+
expectedAcceptedErrors = make(map[ErrorKind]json.RawMessage)
209+
}
210+
c.Check(result.AcceptedErrors, DeepEquals, expectedAcceptedErrors)
205211
c.Check(result.Warnings, ErrorMatches, params.expectedWarningsMatch)
206212

207213
c.Check(ctx.Result(), DeepEquals, result)
@@ -579,6 +585,9 @@ C7E003CB
579585
expectedPcrAlg: tpm2.HashAlgorithmSHA256,
580586
expectedUsedSecureBootCAs: []*X509CertificateID{NewX509CertificateID(testutil.ParseCertificate(c, msUefiCACert))},
581587
expectedFlags: NoPlatformConfigProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerConfigProfileSupport,
588+
expectedAcceptedErrors: map[ErrorKind]json.RawMessage{
589+
ErrorKindEmptyPCRBanks: nil,
590+
},
582591
expectedWarningsMatch: `3 errors detected:
583592
- error with platform config \(PCR1\) measurements: generating profiles for PCR 1 is not supported yet
584593
- error with drivers and apps config \(PCR3\) measurements: generating profiles for PCR 3 is not supported yet
@@ -743,6 +752,10 @@ C7E003CB
743752
expectedPcrAlg: tpm2.HashAlgorithmSHA256,
744753
expectedUsedSecureBootCAs: []*X509CertificateID{NewX509CertificateID(testutil.ParseCertificate(c, msUefiCACert))},
745754
expectedFlags: NoPlatformConfigProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerConfigProfileSupport | InsufficientDMAProtectionDetected,
755+
expectedAcceptedErrors: map[ErrorKind]json.RawMessage{
756+
ErrorKindInsufficientDMAProtection: nil,
757+
ErrorKindNoKernelIOMMU: nil,
758+
},
746759
expectedWarningsMatch: `3 errors detected:
747760
- error with platform config \(PCR1\) measurements: generating profiles for PCR 1 is not supported yet
748761
- error with drivers and apps config \(PCR3\) measurements: generating profiles for PCR 3 is not supported yet
@@ -1097,6 +1110,9 @@ C7E003CB
10971110
expectedPcrAlg: tpm2.HashAlgorithmSHA256,
10981111
expectedUsedSecureBootCAs: []*X509CertificateID{NewX509CertificateID(testutil.ParseCertificate(c, msUefiCACert))},
10991112
expectedFlags: NoPlatformConfigProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerConfigProfileSupport,
1113+
expectedAcceptedErrors: map[ErrorKind]json.RawMessage{
1114+
ErrorKindRunningInVM: nil,
1115+
},
11001116
expectedWarningsMatch: `4 errors detected:
11011117
- virtual machine environment detected
11021118
- error with platform config \(PCR1\) measurements: generating profiles for PCR 1 is not supported yet
@@ -1686,6 +1702,9 @@ C7E003CB
16861702
expectedPcrAlg: tpm2.HashAlgorithmSHA256,
16871703
expectedUsedSecureBootCAs: []*X509CertificateID{NewX509CertificateID(testutil.ParseCertificate(c, msUefiCACert))},
16881704
expectedFlags: NoPlatformConfigProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerConfigProfileSupport,
1705+
expectedAcceptedErrors: map[ErrorKind]json.RawMessage{
1706+
ErrorKindAddonDriversPresent: nil,
1707+
},
16891708
expectedWarningsMatch: `4 errors detected:
16901709
- error with platform config \(PCR1\) measurements: generating profiles for PCR 1 is not supported yet
16911710
- addon drivers were detected:
@@ -1920,6 +1939,9 @@ C7E003CB
19201939
expectedPcrAlg: tpm2.HashAlgorithmSHA256,
19211940
expectedUsedSecureBootCAs: []*X509CertificateID{NewX509CertificateID(testutil.ParseCertificate(c, msUefiCACert))},
19221941
expectedFlags: NoPlatformConfigProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerConfigProfileSupport,
1942+
expectedAcceptedErrors: map[ErrorKind]json.RawMessage{
1943+
ErrorKindSysPrepApplicationsPresent: nil,
1944+
},
19231945
expectedWarningsMatch: `4 errors detected:
19241946
- error with platform config \(PCR1\) measurements: generating profiles for PCR 1 is not supported yet
19251947
- error with drivers and apps config \(PCR3\) measurements: generating profiles for PCR 3 is not supported yet
@@ -2087,6 +2109,9 @@ C7E003CB
20872109
expectedPcrAlg: tpm2.HashAlgorithmSHA256,
20882110
expectedUsedSecureBootCAs: []*X509CertificateID{NewX509CertificateID(testutil.ParseCertificate(c, msUefiCACert))},
20892111
expectedFlags: NoPlatformConfigProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerConfigProfileSupport,
2112+
expectedAcceptedErrors: map[ErrorKind]json.RawMessage{
2113+
ErrorKindAbsolutePresent: nil,
2114+
},
20902115
expectedWarningsMatch: `4 errors detected:
20912116
- error with platform config \(PCR1\) measurements: generating profiles for PCR 1 is not supported yet
20922117
- error with drivers and apps config \(PCR3\) measurements: generating profiles for PCR 3 is not supported yet
@@ -2378,6 +2403,10 @@ C7E003CB
23782403
expectedPcrAlg: tpm2.HashAlgorithmSHA256,
23792404
expectedUsedSecureBootCAs: []*X509CertificateID{NewX509CertificateID(testutil.ParseCertificate(c, msUefiCACert))},
23802405
expectedFlags: NoPlatformConfigProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerConfigProfileSupport,
2406+
expectedAcceptedErrors: map[ErrorKind]json.RawMessage{
2407+
ErrorKindAddonDriversPresent: nil,
2408+
ErrorKindPreOSDigestVerificationDetected: nil,
2409+
},
23812410
expectedWarningsMatch: `5 errors detected:
23822411
- error with platform config \(PCR1\) measurements: generating profiles for PCR 1 is not supported yet
23832412
- addon drivers were detected:
@@ -2600,6 +2629,11 @@ C7E003CB
26002629
expectedPcrAlg: tpm2.HashAlgorithmSHA256,
26012630
expectedUsedSecureBootCAs: []*X509CertificateID{NewX509CertificateID(testutil.ParseCertificate(c, msUefiCACert))},
26022631
expectedFlags: NoPlatformConfigProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerConfigProfileSupport,
2632+
expectedAcceptedErrors: map[ErrorKind]json.RawMessage{
2633+
ErrorKindAddonDriversPresent: nil,
2634+
ErrorKindWeakSecureBootAlgorithmsDetected: nil,
2635+
ErrorKindPreOSDigestVerificationDetected: nil,
2636+
},
26032637
expectedWarningsMatch: `6 errors detected:
26042638
- error with platform config \(PCR1\) measurements: generating profiles for PCR 1 is not supported yet
26052639
- addon drivers were detected:
@@ -2768,6 +2802,11 @@ C7E003CB
27682802
expectedPcrAlg: tpm2.HashAlgorithmSHA256,
27692803
expectedUsedSecureBootCAs: []*X509CertificateID{NewX509CertificateID(testutil.ParseCertificate(c, msUefiCACert))},
27702804
expectedFlags: NoPlatformConfigProfileSupport | NoDriversAndAppsConfigProfileSupport | NoBootManagerConfigProfileSupport,
2805+
expectedAcceptedErrors: map[ErrorKind]json.RawMessage{
2806+
ErrorKindAddonDriversPresent: nil,
2807+
ErrorKindWeakSecureBootAlgorithmsDetected: nil,
2808+
ErrorKindPreOSDigestVerificationDetected: nil,
2809+
},
27712810
expectedWarningsMatch: `6 errors detected:
27722811
- error with platform config \(PCR1\) measurements: generating profiles for PCR 1 is not supported yet
27732812
- addon drivers were detected:

efi/preinstall/export_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ const (
5757
DtpmPartialResetAttackMitigationNotRequired = dtpmPartialResetAttackMitigationNotRequired
5858
DtpmPartialResetAttackMitigationPreferred = dtpmPartialResetAttackMitigationPreferred
5959
DtpmPartialResetAttackMitigationUnavailable = dtpmPartialResetAttackMitigationUnavailable
60+
InsufficientDMAProtectionDetected = insufficientDMAProtectionDetected
6061
SecureBootIncludesWeakAlg = secureBootIncludesWeakAlg
6162
SecureBootPreOSVerificationIncludesDigest = secureBootPreOSVerificationIncludesDigest
6263
StartupLocalityNotProtected = startupLocalityNotProtected

efi/preinstall/profile.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ func (o *pcrProfileAutoSetPcrsOption) ApplyOptionTo(visitor internal_efi.PCRProf
393393
return fmt.Errorf("cannot add PCR profile option %d: %w", i, err)
394394
}
395395
}
396-
if o.result.Flags&InsufficientDMAProtectionDetected != 0 {
396+
if _, permitted := o.result.AcceptedErrors[ErrorKindInsufficientDMAProtection]; permitted {
397397
if err := secboot_efi.WithAllowInsufficientDmaProtection().ApplyOptionTo(visitor); err != nil {
398398
return fmt.Errorf("cannot add DMA allow insufficient protection profile option: %w", err)
399399
}

efi/preinstall/profile_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -570,7 +570,7 @@ func (s *profileSuite) TestWithAutoTCGPCRInsufficientDMAProtection(c *C) {
570570
result := &CheckResult{
571571
PCRAlg: tpm2.HashAlgorithmSHA256,
572572
UsedSecureBootCAs: []*X509CertificateID{NewX509CertificateID(testutil.ParseCertificate(c, msUefiCACert))},
573-
Flags: InsufficientDMAProtectionDetected,
573+
AcceptedErrors: map[ErrorKind]json.RawMessage{ErrorKindInsufficientDMAProtection: nil},
574574
}
575575
profile := WithAutoTCGPCRProfile(result, PCRProfileOptionsDefault)
576576

efi/preinstall/result.go

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -96,14 +96,9 @@ const (
9696
// lifting pins.
9797
RequestPartialDiscreteTPMResetAttackMitigation
9898

99-
// InsufficientDMAProtectionDetected indicates that DMA remapping was disabled in the pre-OS environment.
100-
// This weakens security because it allows pre-OS DMA attacks to compromise system integrity.
101-
// Support for this has to be opted into with the PermitInsufficientDMAProtection flag to RunChecks.
102-
// This check may not run if the NoSecureBootPolicyProfileSupport flag is set.
103-
InsufficientDMAProtectionDetected
104-
10599
discreteTPMDetected
106100
startupLocalityNotProtected
101+
insufficientDMAProtectionDetected
107102
)
108103

109104
func (f CheckResultFlags) toStringSlice() []string {
@@ -132,8 +127,6 @@ func (f CheckResultFlags) toStringSlice() []string {
132127
str = "no-secure-boot-policy-profile-support"
133128
case RequestPartialDiscreteTPMResetAttackMitigation:
134129
str = "request-partial-dtpm-reset-attack-mitigation"
135-
case InsufficientDMAProtectionDetected:
136-
str = "insufficient-dma-protection-detected"
137130
default:
138131
str = fmt.Sprintf("%#08x", uint32(flag))
139132
}
@@ -179,7 +172,7 @@ func (f *CheckResultFlags) UnmarshalJSON(data []byte) error {
179172
case "request-partial-dtpm-reset-attack-mitigation":
180173
val = RequestPartialDiscreteTPMResetAttackMitigation
181174
case "insufficient-dma-protection-detected":
182-
val = InsufficientDMAProtectionDetected
175+
val = insufficientDMAProtectionDetected
183176
case "discrete-tpm-detected":
184177
val = discreteTPMDetected
185178
case "startup-locality-not-protected":
@@ -213,9 +206,10 @@ func (f CheckResultFlags) String() string {
213206
}
214207

215208
type checkResultJSON struct {
216-
PCRAlg hashAlgorithmId `json:"pcr-alg"`
217-
UsedSecureBootCAs []*X509CertificateID `json:"used-secure-boot-cas"`
218-
Flags CheckResultFlags `json:"flags"`
209+
PCRAlg hashAlgorithmId `json:"pcr-alg"`
210+
UsedSecureBootCAs []*X509CertificateID `json:"used-secure-boot-cas"`
211+
Flags CheckResultFlags `json:"flags"`
212+
AcceptedErrors map[ErrorKind]json.RawMessage `json:"accepted-errors,omitempty"`
219213
}
220214

221215
// CheckResult is returned from [RunChecks] when it completes successfully.
@@ -232,6 +226,12 @@ type CheckResult struct {
232226
// Flags contains a set of result flags
233227
Flags CheckResultFlags
234228

229+
// AcceptedErrors are the errors that were initially accepted using ActionProceed.
230+
// It is a map of each accepted error kind to a set of arguments associated with
231+
// the accepted error. The arguments are currently unused and this is only here
232+
// for future proofing.
233+
AcceptedErrors map[ErrorKind]json.RawMessage
234+
235235
// Warnings contains any non-fatal errors that were detected when running the tests
236236
// on the current platform with the specified configuration. Note that this field is
237237
// not serialized.
@@ -244,6 +244,7 @@ func (r CheckResult) MarshalJSON() ([]byte, error) {
244244
PCRAlg: hashAlgorithmId(r.PCRAlg),
245245
UsedSecureBootCAs: r.UsedSecureBootCAs,
246246
Flags: r.Flags,
247+
AcceptedErrors: r.AcceptedErrors,
247248
}
248249
return json.Marshal(res)
249250
}
@@ -259,7 +260,17 @@ func (r *CheckResult) UnmarshalJSON(data []byte) error {
259260
PCRAlg: tpm2.HashAlgorithmId(res.PCRAlg),
260261
UsedSecureBootCAs: res.UsedSecureBootCAs,
261262
Flags: res.Flags,
263+
AcceptedErrors: res.AcceptedErrors,
262264
}
265+
if r.Flags&insufficientDMAProtectionDetected > 0 {
266+
if r.AcceptedErrors == nil {
267+
r.AcceptedErrors = make(map[ErrorKind]json.RawMessage)
268+
}
269+
r.AcceptedErrors[ErrorKindInsufficientDMAProtection] = nil
270+
r.AcceptedErrors[ErrorKindNoKernelIOMMU] = nil
271+
r.Flags &^= insufficientDMAProtectionDetected
272+
}
273+
263274
return nil
264275
}
265276

0 commit comments

Comments
 (0)