Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

qemu: extract swtpm #522

Merged
merged 3 commits into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/kola/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
58 changes: 2 additions & 56 deletions kola/tests/misc/tpm.go
Original file line number Diff line number Diff line change
@@ -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 (
Expand Down Expand Up @@ -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`.
Expand Down Expand Up @@ -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)
}
}
51 changes: 51 additions & 0 deletions platform/local/tpm.go
Original file line number Diff line number Diff line change
@@ -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
}
20 changes: 20 additions & 0 deletions platform/machine/qemu/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down
2 changes: 2 additions & 0 deletions platform/machine/qemu/flight.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ type Options struct {

ExtraBaseDiskSize string

EnableTPM bool

*platform.Options
}

Expand Down
5 changes: 4 additions & 1 deletion platform/machine/qemu/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ type machine struct {
journal *platform.Journal
consolePath string
console string
swtpm *local.SoftwareTPM
}

func (m *machine) ID() string {
Expand Down Expand Up @@ -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 {
Expand Down
3 changes: 2 additions & 1 deletion platform/qemu.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import (
type MachineOptions struct {
AdditionalDisks []Disk
ExtraPrimaryDiskSize string
EnableTPM bool
SoftwareTPMSocket string
}

Expand Down Expand Up @@ -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":
Expand Down