Skip to content

Commit

Permalink
preinstall: Check the value of TPM_PT_NV_COUNTERS_AVAIL
Browse files Browse the repository at this point in the history
When testing for sufficient NV counters, we check TPM_PT_NV_COUNTERS_MAX
(the maximum number of counters that are permitted to be allocated) and
TPM_PT_COUNTERS (the number of counters allocated).

There is another metric - TPM_PT_NV_COUNTERS_AVAIL which is an estimate
of the number of orderly counters that can be created based on the
amount of RAM remaining for orderly indices and the amount of shared NV
space remaining. This isn't perfect because we aren't creating orderly
counters (so the RAM constraints don't apply), and the TCG reference
library permits TPMs to always return 1 for this property, so we have to
handle this case as inconclusive.
  • Loading branch information
chrisccoulson committed Oct 17, 2024
1 parent e0c45dc commit ec7cabe
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 1 deletion.
22 changes: 22 additions & 0 deletions efi/preinstall/check_tpm.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,28 @@ func openAndCheckTPM2Device(env internal_efi.HostEnvironment, flags checkTPM2Dev
return nil, false, ErrTPMInsufficientNVCounters
}
}

// The above check isn't perfect because it doesn't consider the amount of NV space available.
// There is another metric available which estimates how much space there is for counters with
// the orderly attribute set. This works by taking the available NV space, subtracting the space
// for the minimum number of evict objects and the space currently used for NV indexes in order
// to work out how many counters would fit in the remaining NV storage. It does the same for RAM
// reserved for orderly data, subtracting the space allocated for current orderly NV indexes in
// order to work out how many counters would fit in the remaining RAM, and then it returns the
// minimum of the 2 numbers. This isn't perfect - we could create more or less than the minimum
// number of evict objects, and we aren't creating orderly counters so we don't need to care about
// RAM space. But, we'll check it anyway.
nvCountersAvail, err := tpm.GetCapabilityTPMProperty(tpm2.PropertyNVCountersAvail)
if err != nil {
return nil, false, fmt.Errorf("cannot obtain value for TPM_NV_COUNTERS_AVAIL: %w", err)
}
switch nvCountersAvail {
case 1:
// The TCG reference library permits implementations to always return 1, so we'll
// just have to accept this as inconclusive.
case 0:
return nil, false, ErrTPMInsufficientNVCounters
}
}

return tpm, discreteTPM, nil
Expand Down
49 changes: 48 additions & 1 deletion efi/preinstall/check_tpm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ var _ = Suite(&tpmSuite{})
func (s *tpmSuite) TestOpenAndCheckTPM2DeviceGoodPreInstallNoVMInfiniteCountersDiscreteTPM(c *C) {
s.addTPMPropertyModifiers(c, map[tpm2.Property]uint32{
tpm2.PropertyNVCountersMax: 0,
tpm2.PropertyNVCountersAvail: 0x14,
tpm2.PropertyPSFamilyIndicator: 1,
tpm2.PropertyManufacturer: uint32(tpm2.TPMManufacturerNTC),
})
Expand All @@ -123,6 +124,7 @@ func (s *tpmSuite) TestOpenAndCheckTPM2DeviceGoodPreInstallNoVMInfiniteCountersD
func (s *tpmSuite) TestOpenAndCheckTPM2DeviceGoodPreInstallNoVMInfiniteCountersFWTPM(c *C) {
s.addTPMPropertyModifiers(c, map[tpm2.Property]uint32{
tpm2.PropertyNVCountersMax: 0,
tpm2.PropertyNVCountersAvail: 0x14,
tpm2.PropertyPSFamilyIndicator: 1,
tpm2.PropertyManufacturer: uint32(tpm2.TPMManufacturerINTC),
})
Expand All @@ -143,6 +145,28 @@ func (s *tpmSuite) TestOpenAndCheckTPM2DeviceGoodPreInstallNoVMFiniteCountersDis
s.addTPMPropertyModifiers(c, map[tpm2.Property]uint32{
tpm2.PropertyNVCountersMax: 6,
tpm2.PropertyNVCounters: 4,
tpm2.PropertyNVCountersAvail: 0x12,
tpm2.PropertyPSFamilyIndicator: 1,
tpm2.PropertyManufacturer: uint32(tpm2.TPMManufacturerNTC),
})

dev := tpm2_testutil.NewTransportBackedDevice(s.Transport, false)
env := efitest.NewMockHostEnvironmentWithOpts(efitest.WithTPMDevice(dev))
tpm, discreteTPM, err := OpenAndCheckTPM2Device(env, 0)
c.Check(err, IsNil)
c.Assert(tpm, NotNil)
var tmpl tpm2_testutil.TransportWrapper
c.Assert(tpm.Transport(), Implements, &tmpl)
c.Check(tpm.Transport().(tpm2_testutil.TransportWrapper).Unwrap(), Equals, s.Transport)
c.Check(discreteTPM, testutil.IsTrue)
c.Check(dev.NumberOpen(), Equals, int(1))
}

func (s *tpmSuite) TestOpenAndCheckTPM2DeviceGoodPreInstallNoVMFiniteCountersDiscreteTPMOneAvailWorkaround(c *C) {
s.addTPMPropertyModifiers(c, map[tpm2.Property]uint32{
tpm2.PropertyNVCountersMax: 6,
tpm2.PropertyNVCounters: 4,
tpm2.PropertyNVCountersAvail: 1,
tpm2.PropertyPSFamilyIndicator: 1,
tpm2.PropertyManufacturer: uint32(tpm2.TPMManufacturerNTC),
})
Expand All @@ -163,6 +187,7 @@ func (s *tpmSuite) TestOpenAndCheckTPM2DeviceGoodPostInstallNoVMCountersCheckSki
s.addTPMPropertyModifiers(c, map[tpm2.Property]uint32{
tpm2.PropertyNVCountersMax: 6,
tpm2.PropertyNVCounters: 5,
tpm2.PropertyNVCountersAvail: 0x11,
tpm2.PropertyPSFamilyIndicator: 1,
tpm2.PropertyManufacturer: uint32(tpm2.TPMManufacturerNTC),
})
Expand All @@ -181,7 +206,9 @@ func (s *tpmSuite) TestOpenAndCheckTPM2DeviceGoodPostInstallNoVMCountersCheckSki

func (s *tpmSuite) TestOpenAndCheckTPM2DeviceGoodPreInstallVMInfiniteCounters(c *C) {
s.addTPMPropertyModifiers(c, map[tpm2.Property]uint32{
tpm2.PropertyNVCountersMax: 0,
tpm2.PropertyNVCountersMax: 0,
tpm2.PropertyNVCountersAvail: 0x14,

tpm2.PropertyPSFamilyIndicator: 1,
tpm2.PropertyManufacturer: uint32(tpm2.TPMManufacturerMSFT),
})
Expand All @@ -202,6 +229,7 @@ func (s *tpmSuite) TestOpenAndCheckTPM2DeviceGoodPostInstallNoVMLockoutCheckSkip
s.addTPMPropertyModifiers(c, map[tpm2.Property]uint32{
tpm2.PropertyNVCountersMax: 6,
tpm2.PropertyNVCounters: 4,
tpm2.PropertyNVCountersAvail: 0x12,
tpm2.PropertyPSFamilyIndicator: 1,
tpm2.PropertyManufacturer: uint32(tpm2.TPMManufacturerINTC),
})
Expand All @@ -224,6 +252,7 @@ func (s *tpmSuite) TestOpenAndCheckTPM2DeviceGoodPostInstallNoVMLockoutCheckSkip
func (s *tpmSuite) TestOpenAndCheckTPM2DeviceGoodPostInstallNoVMLockoutOwnedCheckSkipped(c *C) {
s.addTPMPropertyModifiers(c, map[tpm2.Property]uint32{
tpm2.PropertyNVCountersMax: 0,
tpm2.PropertyNVCountersAvail: 0x14,
tpm2.PropertyPSFamilyIndicator: 1,
tpm2.PropertyManufacturer: uint32(tpm2.TPMManufacturerINTC),
})
Expand All @@ -246,6 +275,7 @@ func (s *tpmSuite) TestOpenAndCheckTPM2DeviceGoodPostInstallNoVMLockoutOwnedChec
func (s *tpmSuite) TestOpenAndCheckTPM2DeviceGoodPostInstallNoVMOwnerOwnedCheckSkipped(c *C) {
s.addTPMPropertyModifiers(c, map[tpm2.Property]uint32{
tpm2.PropertyNVCountersMax: 0,
tpm2.PropertyNVCountersAvail: 0x14,
tpm2.PropertyPSFamilyIndicator: 1,
tpm2.PropertyManufacturer: uint32(tpm2.TPMManufacturerINTC),
})
Expand All @@ -268,6 +298,7 @@ func (s *tpmSuite) TestOpenAndCheckTPM2DeviceGoodPostInstallNoVMOwnerOwnedCheckS
func (s *tpmSuite) TestOpenAndCheckTPM2DeviceGoodPostInstallNoVMEndorsmentOwnedCheckSkipped(c *C) {
s.addTPMPropertyModifiers(c, map[tpm2.Property]uint32{
tpm2.PropertyNVCountersMax: 0,
tpm2.PropertyNVCountersAvail: 0x14,
tpm2.PropertyPSFamilyIndicator: 1,
tpm2.PropertyManufacturer: uint32(tpm2.TPMManufacturerINTC),
})
Expand Down Expand Up @@ -403,6 +434,22 @@ func (s *tpmSuite) TestOpenAndCheckTPM2DeviceInsufficientNVCountersPreInstall(c
s.addTPMPropertyModifiers(c, map[tpm2.Property]uint32{
tpm2.PropertyNVCountersMax: 6,
tpm2.PropertyNVCounters: 5,
tpm2.PropertyNVCountersAvail: 0x13,
tpm2.PropertyPSFamilyIndicator: 1,
})

dev := tpm2_testutil.NewTransportBackedDevice(s.Transport, false)
env := efitest.NewMockHostEnvironmentWithOpts(efitest.WithTPMDevice(dev))
_, _, err := OpenAndCheckTPM2Device(env, 0)
c.Check(err, Equals, ErrTPMInsufficientNVCounters)
c.Check(dev.NumberOpen(), Equals, int(0))
}

func (s *tpmSuite) TestOpenAndCheckTPM2DeviceInsufficientNVCountersPreInstall2(c *C) {
s.addTPMPropertyModifiers(c, map[tpm2.Property]uint32{
tpm2.PropertyNVCountersMax: 0,
tpm2.PropertyNVCounters: 6,
tpm2.PropertyNVCountersAvail: 0,
tpm2.PropertyPSFamilyIndicator: 1,
})

Expand Down

0 comments on commit ec7cabe

Please sign in to comment.