diff --git a/cmd/kola/options.go b/cmd/kola/options.go index c904e3a3a..b0ad3bd11 100644 --- a/cmd/kola/options.go +++ b/cmd/kola/options.go @@ -227,6 +227,7 @@ func init() { sv(&kola.QEMUOptions.BIOSImage, "qemu-bios", "", "BIOS to use for QEMU vm") bv(&kola.QEMUOptions.UseVanillaImage, "qemu-skip-mangle", false, "don't modify CL disk image to capture console log") sv(&kola.QEMUOptions.ExtraBaseDiskSize, "qemu-grow-base-disk-by", "", "grow base disk by the given size in bytes, following optional 1024-based suffixes are allowed: b (ignored), k, K, M, G, T") + bv(&kola.QEMUOptions.EnableTPM, "qemu-tpm", false, "enable TPM device in QEMU. Requires installing swtpm. Use only with 'kola spawn', test cases are responsible for creating a VM with TPM explicitly.") // BrightBox specific options sv(&kola.BrightboxOptions.ClientID, "brightbox-client-id", "", "Brightbox client ID") diff --git a/kola/tests/misc/tpm.go b/kola/tests/misc/tpm.go index c32b1c92b..d1e5a51c6 100644 --- a/kola/tests/misc/tpm.go +++ b/kola/tests/misc/tpm.go @@ -1,21 +1,15 @@ package misc import ( - "fmt" - "os" - "strings" "time" "github.com/coreos/go-semver/semver" - "github.com/coreos/pkg/capnslog" "github.com/flatcar/mantle/kola/cluster" "github.com/flatcar/mantle/kola/register" "github.com/flatcar/mantle/platform" "github.com/flatcar/mantle/platform/conf" "github.com/flatcar/mantle/platform/machine/qemu" "github.com/flatcar/mantle/platform/machine/unprivqemu" - "github.com/flatcar/mantle/system/exec" - "github.com/flatcar/mantle/util" ) const ( @@ -311,19 +305,14 @@ func init() { } func tpmTest(c cluster.TestCluster, userData *conf.UserData, mountpoint string, variant string) { - swtpm, err := startSwtpm() - if err != nil { - c.Fatalf("could not start software TPM emulation: %v", err) - } - defer swtpm.stop() - options := platform.MachineOptions{ AdditionalDisks: []platform.Disk{ {Size: "520M", DeviceOpts: []string{"serial=secondary"}}, }, - SoftwareTPMSocket: swtpm.socketPath, + EnableTPM: true, } var m platform.Machine + var err error switch pc := c.Cluster.(type) { // These cases have to be separated because otherwise the golang compiler doesn't type-check // the case bodies using the proper subtype of `pc`. @@ -370,46 +359,3 @@ func tpmTest(c cluster.TestCluster, userData *conf.UserData, mountpoint string, checkIfMountpointIsEncrypted(c, m, "/") } } - -type softwareTPM struct { - process *exec.ExecCmd - socketPath string - dir string -} - -func startSwtpm() (*softwareTPM, error) { - swtpm := &softwareTPM{} - - swtpmDir, err := os.MkdirTemp("", "swtpm-") - if err != nil { - return nil, err - } - swtpm.dir = swtpmDir - swtpm.socketPath = fmt.Sprintf("%v/swtpm-sock", swtpm.dir) - - swtpm.process = exec.Command("swtpm", "socket", "--tpmstate", fmt.Sprintf("dir=%v", swtpm.dir), "--ctrl", fmt.Sprintf("type=unixio,path=%v", swtpm.socketPath), "--tpm2") - out, err := swtpm.process.StdoutPipe() - if err != nil { - return nil, err - } - go util.LogFrom(capnslog.INFO, out) - - if err = swtpm.process.Start(); err != nil { - return nil, err - } - - plog.Debugf("swtpm PID: %v", swtpm.process.Pid()) - - return swtpm, nil -} - -func (swtpm *softwareTPM) stop() { - if err := swtpm.process.Kill(); err != nil { - plog.Errorf("Error killing swtpm: %v", err) - } - // To be double sure that we do not delete the wrong directory, check that "tpm" occurs in the directory path we delete. - if strings.Contains(swtpm.dir, "tpm") { - plog.Debugf("Delete swtpm temporary directory %v", swtpm.dir) - os.RemoveAll(swtpm.dir) - } -} diff --git a/platform/local/tpm.go b/platform/local/tpm.go new file mode 100644 index 000000000..c4187813b --- /dev/null +++ b/platform/local/tpm.go @@ -0,0 +1,51 @@ +package local + +import ( + "fmt" + "os" + + "github.com/coreos/pkg/capnslog" + "github.com/flatcar/mantle/system/exec" + "github.com/flatcar/mantle/util" +) + +type SoftwareTPM struct { + process *exec.ExecCmd + socketPath string + dir string +} + +func NewSwtpm(dir string) (*SoftwareTPM, error) { + swtpm := &SoftwareTPM{} + + os.Mkdir(dir, 0700) + swtpm.dir = dir + swtpm.socketPath = fmt.Sprintf("%v/sock", swtpm.dir) + + swtpm.process = exec.Command("swtpm", "socket", "--tpmstate", fmt.Sprintf("dir=%v", swtpm.dir), "--ctrl", fmt.Sprintf("type=unixio,path=%v", swtpm.socketPath), "--tpm2") + out, err := swtpm.process.StderrPipe() + if err != nil { + return nil, err + } + go util.LogFrom(capnslog.INFO, out) + + if err = swtpm.process.Start(); err != nil { + return nil, err + } + + plog.Debugf("swtpm PID: %v", swtpm.process.Pid()) + + return swtpm, nil +} + +func (swtpm *SoftwareTPM) Stop() { + if err := swtpm.process.Kill(); err != nil { + plog.Errorf("Error killing swtpm: %v", err) + } + plog.Debugf("Delete swtpm temporary directory %v", swtpm.dir) + os.RemoveAll(swtpm.dir) +} + +func (swtpm *SoftwareTPM) SocketPath() string { + return swtpm.socketPath +} diff --git a/platform/machine/qemu/cluster.go b/platform/machine/qemu/cluster.go index 853129b2b..3df499663 100644 --- a/platform/machine/qemu/cluster.go +++ b/platform/machine/qemu/cluster.go @@ -43,6 +43,9 @@ type Cluster struct { func (qc *Cluster) NewMachine(userdata *conf.UserData) (platform.Machine, error) { options := platform.MachineOptions{ ExtraPrimaryDiskSize: qc.flight.opts.ExtraBaseDiskSize, + // Use for 'kola spawn'; test cases should pass true through + // NewMachineWithOptions() + EnableTPM: qc.flight.opts.EnableTPM, } return qc.NewMachineWithOptions(userdata, options) } @@ -111,6 +114,20 @@ ExecStartPost=/usr/bin/ln -fs /run/metadata/flatcar /run/metadata/coreos consolePath: filepath.Join(dir, "console.txt"), } + var swtpm *local.SoftwareTPM + if options.EnableTPM { + swtpm, err = local.NewSwtpm(filepath.Join(dir, "tpm")) + if err != nil { + return nil, fmt.Errorf("starting swtpm: %v", err) + } + options.SoftwareTPMSocket = swtpm.SocketPath() + defer func() { + if swtpm != nil { + swtpm.Stop() + } + }() + } + qmCmd, extraFiles, err := platform.CreateQEMUCommand(qc.flight.opts.Board, qm.id, qc.flight.opts.BIOSImage, qm.consolePath, confPath, qc.flight.diskImagePath, conf.IsIgnition(), options) if err != nil { return nil, err @@ -150,6 +167,9 @@ ExecStartPost=/usr/bin/ln -fs /run/metadata/flatcar /run/metadata/coreos return nil, err } + // from this point on Destroy() is responsible for cleaning up swtpm + qm.swtpm, swtpm = swtpm, nil + plog.Debugf("qemu PID (manual cleanup needed if --remove=false): %v", qm.qemu.Pid()) if err := platform.StartMachine(qm, qm.journal); err != nil { diff --git a/platform/machine/qemu/flight.go b/platform/machine/qemu/flight.go index 2716ed38a..5ec981a10 100644 --- a/platform/machine/qemu/flight.go +++ b/platform/machine/qemu/flight.go @@ -44,6 +44,8 @@ type Options struct { ExtraBaseDiskSize string + EnableTPM bool + *platform.Options } diff --git a/platform/machine/qemu/machine.go b/platform/machine/qemu/machine.go index 50883f734..8b527e724 100644 --- a/platform/machine/qemu/machine.go +++ b/platform/machine/qemu/machine.go @@ -32,6 +32,7 @@ type machine struct { journal *platform.Journal consolePath string console string + swtpm *local.SoftwareTPM } func (m *machine) ID() string { @@ -70,7 +71,9 @@ func (m *machine) Destroy() { if err := m.qemu.Kill(); err != nil { plog.Errorf("Error killing instance %v: %v", m.ID(), err) } - + if m.swtpm != nil { + m.swtpm.Stop() + } m.journal.Destroy() if buf, err := ioutil.ReadFile(m.consolePath); err == nil { diff --git a/platform/qemu.go b/platform/qemu.go index 6414f9d16..ac6e1f301 100644 --- a/platform/qemu.go +++ b/platform/qemu.go @@ -36,6 +36,7 @@ import ( type MachineOptions struct { AdditionalDisks []Disk ExtraPrimaryDiskSize string + EnableTPM bool SoftwareTPMSocket string } @@ -348,7 +349,7 @@ func CreateQEMUCommand(board, uuid, biosImage, consolePath, confPath, diskImageP "-device", "virtio-rng-pci,rng=rng0", ) - if options.SoftwareTPMSocket != "" { + if options.EnableTPM { var tpm string switch board { case "amd64-usr":