forked from canonical/secboot
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
preinstall: Add simple checks for PCRs 0 and 2
This adds some trivial to checks to both PCRs 0 and 2: - that they contain events of the expected type. - that there are no measurements to them from the OS-present phase. As we don't do any sort of prediction for these PCRs (yet), it doesn't perform additional checking such as ensuring that the event data is consistent with the event digests when the event digests are a tagged hash of the event data (ie, not purely informational). Note that this modifies the internal/efitest package to emit EV_S_CRTM_VERSION and EV_EFI_PLATFORM_FIRMWARE_BLOB events with the correct event data types.
- Loading branch information
1 parent
0c803fc
commit ad99a33
Showing
6 changed files
with
346 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
// -*- Mode: Go; indent-tabs-mode: t -*- | ||
|
||
/* | ||
* Copyright (C) 2024 Canonical Ltd | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License version 3 as | ||
* published by the Free Software Foundation. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
* | ||
*/ | ||
|
||
package preinstall | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
|
||
"github.com/canonical/tcglog-parser" | ||
internal_efi "github.com/snapcore/secboot/internal/efi" | ||
) | ||
|
||
// checkPlatformFirmwareMeasurements checks measurements related to platfor firmware in PCR0, | ||
// including that measurements are of expected types, and that no measurements are made during | ||
// the OS-present phase. | ||
func checkPlatformFirmwareMeasurements(log *tcglog.Log) error { | ||
// Iterate over the log until OS-present and make sure that we have expected | ||
// event types | ||
events := log.Events | ||
for len(events) > 0 { | ||
ev := events[0] | ||
events = events[1:] | ||
|
||
if ev.PCRIndex != internal_efi.PlatformFirmwarePCR { | ||
// Not PCR0 | ||
continue | ||
} | ||
if ev.EventType == tcglog.EventTypeSeparator { | ||
break | ||
} | ||
|
||
switch ev.EventType { | ||
case tcglog.EventTypePostCode, tcglog.EventTypeEFIPlatformFirmwareBlob: | ||
// Platform firmware blobs - deprecated. | ||
// EV_POST_CODE should contain a non-NULL terminated string or a | ||
// UEFI_PLATFORM_FIRMWARE_BLOB structure. EV_EFI_PLATFORM_FIRMWARE_BLOB | ||
// should contain a UEFI_PLATFORM_FIRMWARE_BLOB structure. | ||
case tcglog.EventTypeNoAction: | ||
// Information, not measured | ||
case tcglog.EventTypeSCRTMContents, tcglog.EventTypeSCRTMVersion: | ||
// SCRTM measurements. EV_S_SCRTM_CONTENTS should either contain a | ||
// UEFI_PLATFORM_FIRMWARE_BLOB or UEFI_PLATFORM_FIRMWARE_BLOB2 structure, | ||
// or it can contain a NULL terminated ASCII string if measured by a H-CRTM | ||
// event. EV_S_CRTM_VERSION should contain a NULL terminated UCS2 string or | ||
// a EFI_GUID. | ||
// | ||
// We don't make any special accommodations for these when measured as part | ||
// of a H-CRTM sequence, so it's possible we already mis-predicted PCR0 and | ||
// marked it invalid before getting to this point. | ||
// | ||
// EV_S_CRTM_VERSION is not informational but we don't check that the data matches | ||
// the event digests because we don't do any prediction for this value. | ||
case tcglog.EventTypeNonhostCode, tcglog.EventTypeNonhostInfo: | ||
// Non-host platform code running on an embedded controller. The second one is used | ||
// if the host platform cannot reliably measure the non-host code. The event data is | ||
// determined by the platform manufacturer. | ||
case tcglog.EventTypePostCode2, tcglog.EventTypeEFIPlatformFirmwareBlob2: | ||
// Platform firmware blobs. | ||
// EV_POST_CODE2 should contain a non-NULL terminated string or a | ||
// UEFI_PLATFORM_FIRMWARE_BLOB2 structure. EV_EFI_PLATFORM_FIRMWARE_BLOB | ||
// should contain a EF_EFI_PLATFORM_FIRMWARE_BLOB2 structure. | ||
case tcglog.EventTypeEFIBootServicesDriver, tcglog.EventTypeEFIRuntimeServicesDriver: | ||
// Platform firmware blobs as PE images and loaded via the LoadImage API. | ||
// We don't check the digests here because it's likely that the device path | ||
// takes us to something we can't read, and we don't do any prediction here | ||
// yet either. | ||
case tcglog.EventTypeEFIHCRTMEvent: | ||
// a H-CRTM sequence that occurred before TPM2_Startup. There may be more than | ||
// one of these. | ||
// There should be a corresponding EV_NO_ACTION event indicating that the startup | ||
// locality is 4, and there may be other EV_NO_ACTION events containing | ||
// TCG_HCRTMComponentEvent structures. | ||
case tcglog.EventTypeEFISPDMFirmwareBlob: | ||
// Firmware of a component that supports SPDM "GET_MEASUREMENTS". | ||
// Note that this is very new (only in the TCG PFP spec v1.06) | ||
default: | ||
return fmt.Errorf("unexpected pre-OS log event type %v", ev.EventType) | ||
} | ||
} | ||
|
||
// Nothing should measure to PCR0 outside of pre-OS - we'll generate an invalid profile | ||
// if it does. | ||
for len(events) > 0 { | ||
ev := events[0] | ||
events = events[1:] | ||
|
||
if ev.PCRIndex == internal_efi.PlatformFirmwarePCR { | ||
return errors.New("firmware measures events as part of the OS-present environment") | ||
} | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
// -*- Mode: Go; indent-tabs-mode: t -*- | ||
|
||
/* | ||
* Copyright (C) 2024 Canonical Ltd | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License version 3 as | ||
* published by the Free Software Foundation. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
* | ||
*/ | ||
|
||
package preinstall_test | ||
|
||
import ( | ||
"github.com/canonical/tcglog-parser" | ||
. "github.com/snapcore/secboot/efi/preinstall" | ||
internal_efi "github.com/snapcore/secboot/internal/efi" | ||
"github.com/snapcore/secboot/internal/efitest" | ||
. "gopkg.in/check.v1" | ||
) | ||
|
||
type pcr0Suite struct{} | ||
|
||
var _ = Suite(&pcr0Suite{}) | ||
|
||
func (s *pcr0Suite) TestCheckPlatformFirmwareMeasurementsGood(c *C) { | ||
log := efitest.NewLog(c, &efitest.LogOptions{}) | ||
c.Check(CheckPlatformFirmwareMeasurements(log), IsNil) | ||
} | ||
|
||
func (s *pcr0Suite) TestCheckPlatformFirmwareMeasurementsGoodSL3(c *C) { | ||
log := efitest.NewLog(c, &efitest.LogOptions{StartupLocality: 3}) | ||
c.Check(CheckPlatformFirmwareMeasurements(log), IsNil) | ||
} | ||
|
||
func (s *pcr0Suite) TestCheckPlatformFirmwareMeasurementsGoodHCRTM(c *C) { | ||
log := efitest.NewLog(c, &efitest.LogOptions{StartupLocality: 4}) | ||
c.Check(CheckPlatformFirmwareMeasurements(log), IsNil) | ||
} | ||
|
||
func (s *pcr0Suite) TestCheckPlatformFirmwareMeasurementsUnexpectedEventType(c *C) { | ||
log := efitest.NewLog(c, &efitest.LogOptions{}) | ||
for i, ev := range log.Events { | ||
if ev.PCRIndex == internal_efi.PlatformFirmwarePCR && ev.EventType == tcglog.EventTypeEFIPlatformFirmwareBlob { | ||
log.Events[i].EventType = tcglog.EventTypeNonhostConfig | ||
} | ||
} | ||
c.Check(CheckPlatformFirmwareMeasurements(log), ErrorMatches, `unexpected pre-OS log event type EV_NONHOST_CONFIG`) | ||
} | ||
|
||
func (s *pcr0Suite) TestCheckPlatformFirmwareMeasurementsUnexpectedOSPresentEvent(c *C) { | ||
log := efitest.NewLog(c, &efitest.LogOptions{}) | ||
log.Events = append(log.Events, &tcglog.Event{ | ||
PCRIndex: internal_efi.PlatformFirmwarePCR, | ||
EventType: tcglog.EventTypeEFIAction, | ||
Data: tcglog.StringEventData("foo"), | ||
}) | ||
c.Check(CheckPlatformFirmwareMeasurements(log), ErrorMatches, `firmware measures events as part of the OS-present environment`) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
// -*- Mode: Go; indent-tabs-mode: t -*- | ||
|
||
/* | ||
* Copyright (C) 2024 Canonical Ltd | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License version 3 as | ||
* published by the Free Software Foundation. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
* | ||
*/ | ||
|
||
package preinstall | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
|
||
"github.com/canonical/tcglog-parser" | ||
internal_efi "github.com/snapcore/secboot/internal/efi" | ||
) | ||
|
||
type driversAndAppsResultFlags int | ||
|
||
const ( | ||
driversAndAppsDriversPresent driversAndAppsResultFlags = 1 << iota | ||
) | ||
|
||
func checkDriversAndAppsMeasurements(log *tcglog.Log) (result driversAndAppsResultFlags, err error) { | ||
// Iterate over the log until OS-present and make sure we have expected | ||
// event types. | ||
events := log.Events | ||
for len(events) > 0 { | ||
ev := events[0] | ||
events = events[1:] | ||
|
||
if ev.PCRIndex != internal_efi.DriversAndAppsPCR { | ||
// Not PCR2 | ||
continue | ||
} | ||
if ev.EventType == tcglog.EventTypeSeparator { | ||
break | ||
} | ||
|
||
switch ev.EventType { | ||
case tcglog.EventTypeAction, tcglog.EventTypeEFIAction: | ||
// Some sort of action. The event data is a non-NULL terminated ASCII string. | ||
// The data in these events is not informational (the event digests are the tagged | ||
// hashes of the event data), but we don't verify that the event data is consistent | ||
// with the digests yet because we don't do any prediction here. | ||
case tcglog.EventTypeNonhostCode, tcglog.EventTypeNonhostInfo: | ||
// Non-host platform code running on an embedded controller. The second one is used | ||
// if the host platform cannot reliably measure the non-host code. The event data is | ||
// determined by the platform manufacturer and is purely informational. | ||
case tcglog.EventTypeEFIBootServicesApplication, tcglog.EventTypeEFIBootServicesDriver, tcglog.EventTypeEFIRuntimeServicesDriver: | ||
// Code from value-added-retailer component loaded via the LoadImage API. | ||
// We don't check the digests here because it's likely that the device path | ||
// takes us to something we can't read, and we don't do any prediction here | ||
// yet either. | ||
result |= driversAndAppsDriversPresent | ||
case tcglog.EventTypeEFIPlatformFirmwareBlob: | ||
// Code blob from value-added-retailer component - deprecated. Event data should | ||
// contain a UEFI_PLATFORM_FIRMWARE_BLOB structure. | ||
result |= driversAndAppsDriversPresent | ||
case tcglog.EventTypeEFIPlatformFirmwareBlob2: | ||
// Code blob from value-added-retailer component. Event data should contain a | ||
// UEFI_PLATFORM_FIRMWARE_BLOB2 structure. | ||
result |= driversAndAppsDriversPresent | ||
case tcglog.EventTypeEFISPDMFirmwareBlob: | ||
// Firmware of a component that supports SPDM "GET_MEASUREMENTS". | ||
// Note that this is very new (only in the TCG PFP spec v1.06) | ||
result |= driversAndAppsDriversPresent | ||
default: | ||
return 0, fmt.Errorf("unexpected pre-OS log event type %v", ev.EventType) | ||
} | ||
} | ||
|
||
// Nothing should measure to PCR2 outside of pre-OS - we'll generate an invalid profile | ||
// if it does. | ||
for len(events) > 0 { | ||
ev := events[0] | ||
events = events[1:] | ||
|
||
if ev.PCRIndex == internal_efi.DriversAndAppsPCR { | ||
return 0, errors.New("firmware measures events as part of the OS-present environment") | ||
} | ||
} | ||
|
||
return result, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
// -*- Mode: Go; indent-tabs-mode: t -*- | ||
|
||
/* | ||
* Copyright (C) 2024 Canonical Ltd | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License version 3 as | ||
* published by the Free Software Foundation. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
* | ||
*/ | ||
|
||
package preinstall_test | ||
|
||
import ( | ||
"github.com/canonical/tcglog-parser" | ||
. "github.com/snapcore/secboot/efi/preinstall" | ||
internal_efi "github.com/snapcore/secboot/internal/efi" | ||
"github.com/snapcore/secboot/internal/efitest" | ||
. "gopkg.in/check.v1" | ||
) | ||
|
||
type pcr2Suite struct{} | ||
|
||
var _ = Suite(&pcr2Suite{}) | ||
|
||
func (s *pcr2Suite) TestCheckDriversAndAppsMeasurementsGood(c *C) { | ||
log := efitest.NewLog(c, &efitest.LogOptions{}) | ||
result, err := CheckDriversAndAppsMeasurements(log) | ||
c.Check(err, IsNil) | ||
c.Check(result, Equals, DriversAndAppsResultFlags(0)) | ||
} | ||
|
||
func (s *pcr2Suite) TestCheckDriversAndAppsMeasurementsWithDrivers(c *C) { | ||
log := efitest.NewLog(c, &efitest.LogOptions{IncludeDriverLaunch: true}) | ||
result, err := CheckDriversAndAppsMeasurements(log) | ||
c.Check(err, IsNil) | ||
c.Check(result, Equals, DriversAndAppsDriversPresent) | ||
} | ||
|
||
func (s *pcr2Suite) TestCheckDriversAndAppsMeasurementsUnexpectedEventType(c *C) { | ||
log := efitest.NewLog(c, &efitest.LogOptions{IncludeDriverLaunch: true}) | ||
for i, ev := range log.Events { | ||
if ev.PCRIndex == internal_efi.DriversAndAppsPCR && ev.EventType == tcglog.EventTypeEFIBootServicesDriver { | ||
log.Events[i].EventType = tcglog.EventTypeNonhostConfig | ||
} | ||
} | ||
_, err := CheckDriversAndAppsMeasurements(log) | ||
c.Check(err, ErrorMatches, `unexpected pre-OS log event type EV_NONHOST_CONFIG`) | ||
} | ||
|
||
func (s *pcr2Suite) TestCheckDriversAndAppsMeasurementsUnexpectedOSPresentEvent(c *C) { | ||
log := efitest.NewLog(c, &efitest.LogOptions{}) | ||
log.Events = append(log.Events, &tcglog.Event{ | ||
PCRIndex: internal_efi.DriversAndAppsPCR, | ||
EventType: tcglog.EventTypeEFIAction, | ||
Data: tcglog.StringEventData("foo"), | ||
}) | ||
_, err := CheckDriversAndAppsMeasurements(log) | ||
c.Check(err, ErrorMatches, `firmware measures events as part of the OS-present environment`) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters