feat(tpm): add read-only TPM validation
This commit is contained in:
@@ -17,6 +17,8 @@ var runtimeRequiredTools = []string{
|
||||
"smartctl",
|
||||
"nvme",
|
||||
"ipmitool",
|
||||
"tpm2_getcap",
|
||||
"tpm2_pcrread",
|
||||
"dhclient",
|
||||
"mount",
|
||||
}
|
||||
|
||||
@@ -50,6 +50,9 @@ const (
|
||||
// RAM: memtester 512 MB / 1 pass (extrapolated from validate timing, linear with size).
|
||||
SATEstimatedMemoryStressSec = 140
|
||||
|
||||
// TPM capabilities, PCR values, and existing self-test result queries.
|
||||
SATEstimatedTPMValidateSec = 5
|
||||
|
||||
// NVIDIA dcgmi diag Level 2 (medium), all GPUs simultaneously.
|
||||
SATEstimatedNvidiaGPUValidateSec = 85
|
||||
// NVIDIA dcgmi diag Level 3 (targeted stress), all GPUs simultaneously.
|
||||
|
||||
@@ -29,6 +29,10 @@ var techDumpFixedCommands = []struct {
|
||||
{Name: "ipmitool", Args: []string{"sensor"}, File: "ipmitool-sensor.txt"},
|
||||
{Name: "ipmitool", Args: []string{"sel", "list"}, File: "ipmitool-sel.txt"},
|
||||
{Name: "ipmitool", Args: []string{"sel", "time", "get"}, File: "ipmitool-sel-time.txt"},
|
||||
{Name: "tpm2_getcap", Args: []string{"properties-fixed"}, File: "tpm-properties-fixed.txt"},
|
||||
{Name: "tpm2_getcap", Args: []string{"pcrs"}, File: "tpm-pcr-banks.txt"},
|
||||
{Name: "tpm2_pcrread", File: "tpm-pcr-values.txt"},
|
||||
{Name: "tpm2_gettestresult", File: "tpm-test-result.txt"},
|
||||
{Name: "nvme", Args: []string{"list", "-o", "json"}, File: "nvme-list.json"},
|
||||
{Name: "storcli64", Args: []string{"/call/eall/sall", "show", "all", "J"}, File: "storcli64-drives.json"},
|
||||
// storcli2 (Tri-Mode controllers, e.g. SAS3808-iMR/9500 series) needs an
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package platform
|
||||
|
||||
import "context"
|
||||
|
||||
// RunTPMValidationPack verifies TPM 2.0 communication using read-only
|
||||
// commands. It deliberately excludes SelfTest, provisioning, NV writes, PCR
|
||||
// changes, key creation, and ownership operations.
|
||||
func (s *System) RunTPMValidationPack(ctx context.Context, baseDir string, logFunc func(string)) (string, error) {
|
||||
return runAcceptancePackCtx(ctx, baseDir, "tpm", tpmValidationJobs(), logFunc)
|
||||
}
|
||||
|
||||
func tpmValidationJobs() []satJob {
|
||||
return []satJob{
|
||||
{name: "01-properties-fixed.log", cmd: []string{"tpm2_getcap", "properties-fixed"}},
|
||||
{name: "02-pcr-banks.log", cmd: []string{"tpm2_getcap", "pcrs"}},
|
||||
{name: "03-pcr-values.log", cmd: []string{"tpm2_pcrread"}},
|
||||
{name: "04-test-result.log", cmd: []string{"tpm2_gettestresult"}},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package platform
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTPMValidationJobsAreReadOnly(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
jobs := tpmValidationJobs()
|
||||
want := [][]string{
|
||||
{"tpm2_getcap", "properties-fixed"},
|
||||
{"tpm2_getcap", "pcrs"},
|
||||
{"tpm2_pcrread"},
|
||||
{"tpm2_gettestresult"},
|
||||
}
|
||||
if len(jobs) != len(want) {
|
||||
t.Fatalf("jobs=%d want %d", len(jobs), len(want))
|
||||
}
|
||||
for index, job := range jobs {
|
||||
if !reflect.DeepEqual(job.cmd, want[index]) {
|
||||
t.Fatalf("jobs[%d].cmd=%v want %v", index, job.cmd, want[index])
|
||||
}
|
||||
joined := strings.ToLower(strings.Join(job.cmd, " "))
|
||||
for _, forbidden := range []string{"selftest", "clear", "changeauth", "nvwrite", "pcrextend", "create"} {
|
||||
if strings.Contains(joined, forbidden) {
|
||||
t.Fatalf("job %q contains state-changing command %q", joined, forbidden)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user