mirror of
https://github.com/ultravioletrs/cocos.git
synced 2026-06-23 04:10:25 +00:00
NOISSUE - Add launch TCB info to VM info (#333)
* add launch TCB to VM info * add mutex for AP * add policy info to run test * fix manager Run test * add SEV-SNP check
This commit is contained in:
committed by
GitHub
parent
0315e7ddfa
commit
e48f184075
@@ -14,8 +14,8 @@ import (
|
||||
func TestComputationIDFromAddress(t *testing.T) {
|
||||
ms := &managerService{
|
||||
vms: map[string]vm.VM{
|
||||
"comp1": qemu.NewVM(qemu.Config{VSockConfig: qemu.VSockConfig{GuestCID: 3}}, func(event interface{}) error { return nil }, "comp1"),
|
||||
"comp2": qemu.NewVM(qemu.Config{VSockConfig: qemu.VSockConfig{GuestCID: 5}}, func(event interface{}) error { return nil }, "comp2"),
|
||||
"comp1": qemu.NewVM(qemu.VMInfo{Config: qemu.Config{VSockConfig: qemu.VSockConfig{GuestCID: 3}}}, func(event interface{}) error { return nil }, "comp1"),
|
||||
"comp2": qemu.NewVM(qemu.VMInfo{Config: qemu.Config{VSockConfig: qemu.VSockConfig{GuestCID: 5}}}, func(event interface{}) error { return nil }, "comp2"),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ func TestReportBrokenConnection(t *testing.T) {
|
||||
ms := &managerService{
|
||||
eventsChan: make(chan *ClientStreamMessage, 1),
|
||||
vms: map[string]vm.VM{
|
||||
"comp1": qemu.NewVM(qemu.Config{VSockConfig: qemu.VSockConfig{GuestCID: 3}}, func(event interface{}) error { return nil }, "comp1"),
|
||||
"comp1": qemu.NewVM(qemu.VMInfo{Config: qemu.Config{VSockConfig: qemu.VSockConfig{GuestCID: 3}}}, func(event interface{}) error { return nil }, "comp1"),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -34,17 +34,21 @@ func (ms *managerService) FetchAttestationPolicy(_ context.Context, computationI
|
||||
return nil, fmt.Errorf("computationId %s not found", computationId)
|
||||
}
|
||||
|
||||
config, ok := vm.GetConfig().(qemu.Config)
|
||||
vmi, ok := vm.GetConfig().(qemu.VMInfo)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("failed to cast config to qemu.Config")
|
||||
return nil, fmt.Errorf("failed to cast config to qemu.VMInfo")
|
||||
}
|
||||
|
||||
ms.ap.Lock()
|
||||
_, err := cmd.Output()
|
||||
ms.ap.Unlock()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ms.ap.Lock()
|
||||
f, err := os.ReadFile("./attestation_policy.json")
|
||||
ms.ap.Unlock()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -57,13 +61,13 @@ func (ms *managerService) FetchAttestationPolicy(_ context.Context, computationI
|
||||
|
||||
var measurement []byte
|
||||
switch {
|
||||
case config.EnableSEV:
|
||||
measurement, err = guest.CalcLaunchDigest(guest.SEV, config.SMPCount, uint64(cpuid.CpuSigs[ms.qemuCfg.CPU]), config.OVMFCodeConfig.File, config.KernelFile, config.RootFsFile, strconv.Quote(qemu.KernelCommandLine), defGuestFeatures, "", vmmtypes.QEMU, false, "", 0)
|
||||
case vmi.Config.EnableSEV:
|
||||
measurement, err = guest.CalcLaunchDigest(guest.SEV, vmi.Config.SMPCount, uint64(cpuid.CpuSigs[ms.qemuCfg.CPU]), vmi.Config.OVMFCodeConfig.File, vmi.Config.KernelFile, vmi.Config.RootFsFile, strconv.Quote(qemu.KernelCommandLine), defGuestFeatures, "", vmmtypes.QEMU, false, "", 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case config.EnableSEVSNP:
|
||||
measurement, err = guest.CalcLaunchDigest(guest.SEV_SNP, config.SMPCount, uint64(cpuid.CpuSigs[config.CPU]), config.OVMFCodeConfig.File, config.KernelFile, config.RootFsFile, strconv.Quote(qemu.KernelCommandLine), defGuestFeatures, "", vmmtypes.QEMU, false, "", 0)
|
||||
case vmi.Config.EnableSEVSNP:
|
||||
measurement, err = guest.CalcLaunchDigest(guest.SEV_SNP, vmi.Config.SMPCount, uint64(cpuid.CpuSigs[vmi.Config.CPU]), vmi.Config.OVMFCodeConfig.File, vmi.Config.KernelFile, vmi.Config.RootFsFile, strconv.Quote(qemu.KernelCommandLine), defGuestFeatures, "", vmmtypes.QEMU, false, "", 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -72,14 +76,16 @@ func (ms *managerService) FetchAttestationPolicy(_ context.Context, computationI
|
||||
attestationPolicy.Policy.Measurement = measurement
|
||||
}
|
||||
|
||||
if config.HostData != "" {
|
||||
hostData, err := base64.StdEncoding.DecodeString(config.HostData)
|
||||
if vmi.Config.HostData != "" {
|
||||
hostData, err := base64.StdEncoding.DecodeString(vmi.Config.HostData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
attestationPolicy.Policy.HostData = hostData
|
||||
}
|
||||
|
||||
attestationPolicy.Policy.MinimumLaunchTcb = vmi.LaunchTCB
|
||||
|
||||
f, err = protojson.Marshal(&attestationPolicy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
"github.com/ultravioletrs/cocos/manager/vm/mocks"
|
||||
)
|
||||
|
||||
func createDummyAttestationPolicyBinary(t *testing.T, behavior string) string {
|
||||
func CreateDummyAttestationPolicyBinary(t *testing.T, behavior string) string {
|
||||
var content []byte
|
||||
switch behavior {
|
||||
case "success":
|
||||
@@ -55,13 +55,16 @@ func TestFetchAttestationPolicy(t *testing.T) {
|
||||
name: "Valid SEV configuration",
|
||||
computationId: "sev-computation",
|
||||
binaryBehavior: "success",
|
||||
vmConfig: qemu.Config{
|
||||
EnableSEV: true,
|
||||
SMPCount: 2,
|
||||
CPU: "EPYC",
|
||||
OVMFCodeConfig: qemu.OVMFCodeConfig{
|
||||
File: "/path/to/OVMF_CODE.fd",
|
||||
vmConfig: qemu.VMInfo{
|
||||
Config: qemu.Config{
|
||||
EnableSEV: true,
|
||||
SMPCount: 2,
|
||||
CPU: "EPYC",
|
||||
OVMFCodeConfig: qemu.OVMFCodeConfig{
|
||||
File: "/path/to/OVMF_CODE.fd",
|
||||
},
|
||||
},
|
||||
LaunchTCB: 0,
|
||||
},
|
||||
expectedError: "open /path/to/OVMF_CODE.fd: no such file or directory",
|
||||
},
|
||||
@@ -69,13 +72,16 @@ func TestFetchAttestationPolicy(t *testing.T) {
|
||||
name: "Valid SEV-SNP configuration",
|
||||
computationId: "sev-snp-computation",
|
||||
binaryBehavior: "success",
|
||||
vmConfig: qemu.Config{
|
||||
EnableSEVSNP: true,
|
||||
SMPCount: 4,
|
||||
CPU: "EPYC-v2",
|
||||
OVMFCodeConfig: qemu.OVMFCodeConfig{
|
||||
File: "/path/to/OVMF_CODE_SNP.fd",
|
||||
vmConfig: qemu.VMInfo{
|
||||
Config: qemu.Config{
|
||||
EnableSEVSNP: true,
|
||||
SMPCount: 4,
|
||||
CPU: "EPYC-v2",
|
||||
OVMFCodeConfig: qemu.OVMFCodeConfig{
|
||||
File: "/path/to/OVMF_CODE_SNP.fd",
|
||||
},
|
||||
},
|
||||
LaunchTCB: 0,
|
||||
},
|
||||
expectedError: "open /path/to/OVMF_CODE_SNP.fd: no such file or director",
|
||||
},
|
||||
@@ -83,7 +89,7 @@ func TestFetchAttestationPolicy(t *testing.T) {
|
||||
name: "Invalid computation ID",
|
||||
computationId: "non-existent",
|
||||
binaryBehavior: "success",
|
||||
vmConfig: qemu.Config{},
|
||||
vmConfig: qemu.VMInfo{Config: qemu.Config{}, LaunchTCB: 0},
|
||||
expectedError: "computationId non-existent not found",
|
||||
},
|
||||
{
|
||||
@@ -91,14 +97,17 @@ func TestFetchAttestationPolicy(t *testing.T) {
|
||||
computationId: "invalid-config",
|
||||
binaryBehavior: "success",
|
||||
vmConfig: struct{}{},
|
||||
expectedError: "failed to cast config to qemu.Config",
|
||||
expectedError: "failed to cast config to qemu.VMInfo",
|
||||
},
|
||||
{
|
||||
name: "Binary execution failure",
|
||||
computationId: "binary-fail",
|
||||
binaryBehavior: "fail",
|
||||
vmConfig: qemu.Config{
|
||||
EnableSEV: true,
|
||||
vmConfig: qemu.VMInfo{
|
||||
Config: qemu.Config{
|
||||
EnableSEV: true,
|
||||
},
|
||||
LaunchTCB: 0,
|
||||
},
|
||||
expectedError: "exit status 1",
|
||||
},
|
||||
@@ -106,8 +115,11 @@ func TestFetchAttestationPolicy(t *testing.T) {
|
||||
name: "JSON file not created",
|
||||
computationId: "no-json",
|
||||
binaryBehavior: "no_json",
|
||||
vmConfig: qemu.Config{
|
||||
EnableSEV: true,
|
||||
vmConfig: qemu.VMInfo{
|
||||
Config: qemu.Config{
|
||||
EnableSEV: true,
|
||||
},
|
||||
LaunchTCB: 0,
|
||||
},
|
||||
expectedError: "no such file or directory",
|
||||
},
|
||||
@@ -115,7 +127,7 @@ func TestFetchAttestationPolicy(t *testing.T) {
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
tempDir := createDummyAttestationPolicyBinary(t, tc.binaryBehavior)
|
||||
tempDir := CreateDummyAttestationPolicyBinary(t, tc.binaryBehavior)
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
ms := &managerService{
|
||||
|
||||
@@ -13,7 +13,7 @@ const jsonExt = ".json"
|
||||
|
||||
type VMState struct {
|
||||
ID string
|
||||
Config Config
|
||||
VMinfo VMInfo
|
||||
PID int
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ func TestSaveVM(t *testing.T) {
|
||||
|
||||
state := VMState{
|
||||
ID: "test-vm",
|
||||
Config: Config{},
|
||||
VMinfo: VMInfo{Config: Config{}},
|
||||
PID: 1234,
|
||||
}
|
||||
|
||||
@@ -50,8 +50,8 @@ func TestLoadVMs(t *testing.T) {
|
||||
|
||||
// Save two VMs
|
||||
states := []VMState{
|
||||
{ID: "vm1", Config: Config{}, PID: 1234},
|
||||
{ID: "vm2", Config: Config{}, PID: 5678},
|
||||
{ID: "vm1", VMinfo: VMInfo{Config: Config{}}, PID: 1234},
|
||||
{ID: "vm2", VMinfo: VMInfo{Config: Config{}}, PID: 5678},
|
||||
}
|
||||
|
||||
for _, state := range states {
|
||||
@@ -82,7 +82,7 @@ func TestDeleteVM(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
fp, _ := NewFilePersistence(tempDir)
|
||||
|
||||
state := VMState{ID: "test-vm", Config: Config{}, PID: 1234}
|
||||
state := VMState{ID: "test-vm", VMinfo: VMInfo{Config: Config{}}, PID: 1234}
|
||||
|
||||
// Save VM
|
||||
if err := fp.SaveVM(state); err != nil {
|
||||
@@ -126,7 +126,7 @@ func TestConcurrentAccess(t *testing.T) {
|
||||
for i := 0; i < numGoroutines; i++ {
|
||||
go func(id int) {
|
||||
defer wg.Done()
|
||||
state := VMState{ID: fmt.Sprintf("vm-%d", id), Config: Config{}, PID: id}
|
||||
state := VMState{ID: fmt.Sprintf("vm-%d", id), VMinfo: VMInfo{Config: Config{}}, PID: id}
|
||||
if err := fp.SaveVM(state); err != nil {
|
||||
t.Errorf("Concurrent SaveVM failed: %v", err)
|
||||
}
|
||||
|
||||
+17
-12
@@ -25,8 +25,13 @@ const (
|
||||
shutdownTimeout = 30 * time.Second
|
||||
)
|
||||
|
||||
type VMInfo struct {
|
||||
Config Config
|
||||
LaunchTCB uint64 `env:"LAUNCH_TCB" envDefault:"0"`
|
||||
}
|
||||
|
||||
type qemuVM struct {
|
||||
config Config
|
||||
vmi VMInfo
|
||||
cmd *exec.Cmd
|
||||
eventsLogsSender vm.EventSender
|
||||
computationId string
|
||||
@@ -35,7 +40,7 @@ type qemuVM struct {
|
||||
|
||||
func NewVM(config interface{}, eventsLogsSender vm.EventSender, computationId string) vm.VM {
|
||||
return &qemuVM{
|
||||
config: config.(Config),
|
||||
vmi: config.(VMInfo),
|
||||
eventsLogsSender: eventsLogsSender,
|
||||
computationId: computationId,
|
||||
StateMachine: vm.NewStateMachine(),
|
||||
@@ -54,18 +59,18 @@ func (v *qemuVM) Start() (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
v.config.NetDevConfig.ID = fmt.Sprintf("%s-%s", v.config.NetDevConfig.ID, id)
|
||||
v.config.SevConfig.ID = fmt.Sprintf("%s-%s", v.config.SevConfig.ID, id)
|
||||
v.vmi.Config.NetDevConfig.ID = fmt.Sprintf("%s-%s", v.vmi.Config.NetDevConfig.ID, id)
|
||||
v.vmi.Config.SevConfig.ID = fmt.Sprintf("%s-%s", v.vmi.Config.SevConfig.ID, id)
|
||||
|
||||
if !v.config.KernelHash {
|
||||
if !v.vmi.Config.KernelHash {
|
||||
// Copy firmware vars file.
|
||||
srcFile := v.config.OVMFVarsConfig.File
|
||||
srcFile := v.vmi.Config.OVMFVarsConfig.File
|
||||
dstFile := fmt.Sprintf("%s/%s-%s.fd", tmpDir, firmwareVars, id)
|
||||
err = internal.CopyFile(srcFile, dstFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.config.OVMFVarsConfig.File = dstFile
|
||||
v.vmi.Config.OVMFVarsConfig.File = dstFile
|
||||
}
|
||||
|
||||
exe, args, err := v.executableAndArgs()
|
||||
@@ -140,14 +145,14 @@ func (v *qemuVM) GetProcess() int {
|
||||
}
|
||||
|
||||
func (v *qemuVM) executableAndArgs() (string, []string, error) {
|
||||
exe, err := exec.LookPath(v.config.QemuBinPath)
|
||||
exe, err := exec.LookPath(v.vmi.Config.QemuBinPath)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
args := v.config.ConstructQemuArgs()
|
||||
args := v.vmi.Config.ConstructQemuArgs()
|
||||
|
||||
if v.config.UseSudo {
|
||||
if v.vmi.Config.UseSudo {
|
||||
args = append([]string{exe}, args...)
|
||||
exe = "sudo"
|
||||
}
|
||||
@@ -191,9 +196,9 @@ func processExists(pid int) bool {
|
||||
}
|
||||
|
||||
func (v *qemuVM) GetCID() int {
|
||||
return v.config.GuestCID
|
||||
return v.vmi.Config.GuestCID
|
||||
}
|
||||
|
||||
func (v *qemuVM) GetConfig() interface{} {
|
||||
return v.config
|
||||
return v.vmi.Config
|
||||
}
|
||||
|
||||
+15
-11
@@ -17,7 +17,7 @@ import (
|
||||
const testComputationID = "test-computation"
|
||||
|
||||
func TestNewVM(t *testing.T) {
|
||||
config := Config{}
|
||||
config := VMInfo{Config: Config{}}
|
||||
|
||||
vm := NewVM(config, func(event interface{}) error { return nil }, testComputationID)
|
||||
|
||||
@@ -31,12 +31,12 @@ func TestStart(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
defer os.Remove(tmpFile.Name())
|
||||
|
||||
config := Config{
|
||||
config := VMInfo{Config: Config{
|
||||
OVMFVarsConfig: OVMFVarsConfig{
|
||||
File: tmpFile.Name(),
|
||||
},
|
||||
QemuBinPath: "echo",
|
||||
}
|
||||
}}
|
||||
|
||||
vm := NewVM(config, func(event interface{}) error { return nil }, testComputationID).(*qemuVM)
|
||||
|
||||
@@ -53,13 +53,13 @@ func TestStartSudo(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
defer os.Remove(tmpFile.Name())
|
||||
|
||||
config := Config{
|
||||
config := VMInfo{Config: Config{
|
||||
OVMFVarsConfig: OVMFVarsConfig{
|
||||
File: tmpFile.Name(),
|
||||
},
|
||||
QemuBinPath: "echo",
|
||||
UseSudo: true,
|
||||
}
|
||||
}}
|
||||
|
||||
vm := NewVM(config, func(event interface{}) error { return nil }, testComputationID).(*qemuVM)
|
||||
|
||||
@@ -113,8 +113,8 @@ func TestStop(t *testing.T) {
|
||||
|
||||
func TestSetProcess(t *testing.T) {
|
||||
vm := &qemuVM{
|
||||
config: Config{
|
||||
QemuBinPath: "echo", // Use 'echo' as a dummy QEMU binary
|
||||
vmi: VMInfo{
|
||||
Config: Config{QemuBinPath: "echo"}, // Use 'echo' as a dummy QEMU binary
|
||||
},
|
||||
}
|
||||
|
||||
@@ -139,9 +139,11 @@ func TestGetProcess(t *testing.T) {
|
||||
func TestGetCID(t *testing.T) {
|
||||
expectedCID := 42
|
||||
vm := &qemuVM{
|
||||
config: Config{
|
||||
VSockConfig: VSockConfig{
|
||||
GuestCID: expectedCID,
|
||||
vmi: VMInfo{
|
||||
Config: Config{
|
||||
VSockConfig: VSockConfig{
|
||||
GuestCID: expectedCID,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -155,7 +157,9 @@ func TestGetConfig(t *testing.T) {
|
||||
QemuBinPath: "echo",
|
||||
}
|
||||
vm := &qemuVM{
|
||||
config: expectedConfig,
|
||||
vmi: VMInfo{
|
||||
Config: expectedConfig,
|
||||
},
|
||||
}
|
||||
|
||||
config := vm.GetConfig()
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
const VsockConfigPort uint32 = 9999
|
||||
|
||||
func (v *qemuVM) SendAgentConfig(ac agent.Computation) error {
|
||||
conn, err := vsock.Dial(uint32(v.config.GuestCID), VsockConfigPort, nil)
|
||||
conn, err := vsock.Dial(uint32(v.vmi.Config.GuestCID), VsockConfigPort, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+56
-12
@@ -10,6 +10,7 @@ import (
|
||||
"log/slog"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"sync"
|
||||
@@ -17,11 +18,13 @@ import (
|
||||
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
"github.com/cenkalti/backoff/v4"
|
||||
"github.com/google/go-sev-guest/proto/check"
|
||||
"github.com/ultravioletrs/cocos/agent"
|
||||
"github.com/ultravioletrs/cocos/manager/qemu"
|
||||
"github.com/ultravioletrs/cocos/manager/vm"
|
||||
"github.com/ultravioletrs/cocos/pkg/manager"
|
||||
"golang.org/x/crypto/sha3"
|
||||
"google.golang.org/protobuf/encoding/protojson"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
@@ -49,6 +52,15 @@ var (
|
||||
|
||||
// ErrFailedToCalculateHash indicates that agent computation returned an error while calculating the hash of the computation.
|
||||
ErrFailedToCalculateHash = errors.New("error while calculating the hash of the computation")
|
||||
|
||||
// ErrFailedToCreateAttestationPolicy indicates that the script to create the attestation policy failed to execute.
|
||||
ErrFailedToCreateAttestationPolicy = errors.New("error while creating attestation policy")
|
||||
|
||||
// ErrFailedToReadPolicy indicates that the file for attestation policy could not be opened.
|
||||
ErrFailedToReadPolicy = errors.New("error while opening file attestation policy")
|
||||
|
||||
// ErrUnmarshalFailed indicates that the file for the attestation policy could not be unmarshaled.
|
||||
ErrUnmarshalFailed = errors.New("error while unmarshaling the attestation policy")
|
||||
)
|
||||
|
||||
// Service specifies an API that must be fulfilled by the domain service
|
||||
@@ -68,6 +80,7 @@ type Service interface {
|
||||
|
||||
type managerService struct {
|
||||
mu sync.Mutex
|
||||
ap sync.Mutex
|
||||
qemuCfg qemu.Config
|
||||
attestationPolicyBinaryPath string
|
||||
logger *slog.Logger
|
||||
@@ -116,9 +129,38 @@ func New(cfg qemu.Config, attestationPolicyBinPath string, logger *slog.Logger,
|
||||
|
||||
func (ms *managerService) Run(ctx context.Context, c *ComputationRunReq) (string, error) {
|
||||
ms.mu.Lock()
|
||||
cfg := ms.qemuCfg
|
||||
cfg := qemu.VMInfo{
|
||||
Config: ms.qemuCfg,
|
||||
LaunchTCB: 0,
|
||||
}
|
||||
ms.mu.Unlock()
|
||||
|
||||
if ms.qemuCfg.EnableSEVSNP || ms.qemuCfg.EnableSEV {
|
||||
cmd := exec.Command("sudo", fmt.Sprintf("%s/attestation_policy", ms.attestationPolicyBinaryPath), "--policy", "196608")
|
||||
|
||||
ms.ap.Lock()
|
||||
_, err := cmd.Output()
|
||||
ms.ap.Unlock()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(ErrFailedToCreateAttestationPolicy, err)
|
||||
}
|
||||
|
||||
ms.ap.Lock()
|
||||
f, err := os.ReadFile("./attestation_policy.json")
|
||||
ms.ap.Unlock()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(ErrFailedToReadPolicy, err)
|
||||
}
|
||||
|
||||
var attestationPolicy check.Config
|
||||
|
||||
if err = protojson.Unmarshal(f, &attestationPolicy); err != nil {
|
||||
return "", errors.Wrap(ErrUnmarshalFailed, err)
|
||||
}
|
||||
|
||||
// Define the TCB that was present at launch of the VM.
|
||||
cfg.LaunchTCB = attestationPolicy.Policy.MinimumLaunchTcb
|
||||
}
|
||||
ms.publishEvent(manager.VmProvision.String(), c.Id, manager.Starting.String(), json.RawMessage{})
|
||||
ac := agent.Computation{
|
||||
ID: c.Id,
|
||||
@@ -159,7 +201,7 @@ func (ms *managerService) Run(ctx context.Context, c *ComputationRunReq) (string
|
||||
ms.publishEvent(manager.VmProvision.String(), c.Id, agent.Failed.String(), json.RawMessage{})
|
||||
return "", errors.Wrap(ErrFailedToAllocatePort, err)
|
||||
}
|
||||
cfg.HostFwdAgent = agentPort
|
||||
cfg.Config.HostFwdAgent = agentPort
|
||||
|
||||
var cid int = qemu.BaseGuestCID
|
||||
for {
|
||||
@@ -175,17 +217,19 @@ func (ms *managerService) Run(ctx context.Context, c *ComputationRunReq) (string
|
||||
}
|
||||
cid++
|
||||
}
|
||||
cfg.VSockConfig.GuestCID = cid
|
||||
cfg.Config.VSockConfig.GuestCID = cid
|
||||
|
||||
ch, err := computationHash(ac)
|
||||
if err != nil {
|
||||
ms.publishEvent(manager.VmProvision.String(), c.Id, agent.Failed.String(), json.RawMessage{})
|
||||
return "", errors.Wrap(ErrFailedToCalculateHash, err)
|
||||
if cfg.Config.EnableSEVSNP {
|
||||
ch, err := computationHash(ac)
|
||||
if err != nil {
|
||||
ms.publishEvent(manager.VmProvision.String(), c.Id, agent.Failed.String(), json.RawMessage{})
|
||||
return "", errors.Wrap(ErrFailedToCalculateHash, err)
|
||||
}
|
||||
|
||||
// Define host-data value of QEMU for SEV-SNP, with a base64 encoding of the computation hash.
|
||||
cfg.Config.SevConfig.HostData = base64.StdEncoding.EncodeToString(ch[:])
|
||||
}
|
||||
|
||||
// Define host-data value of QEMU for SEV-SNP, with a base64 encoding of the computation hash.
|
||||
cfg.SevConfig.HostData = base64.StdEncoding.EncodeToString(ch[:])
|
||||
|
||||
cvm := ms.vmFactory(cfg, ms.eventsLogsSender, c.Id)
|
||||
ms.publishEvent(manager.VmProvision.String(), c.Id, agent.InProgress.String(), json.RawMessage{})
|
||||
if err = cvm.Start(); err != nil {
|
||||
@@ -200,7 +244,7 @@ func (ms *managerService) Run(ctx context.Context, c *ComputationRunReq) (string
|
||||
|
||||
state := qemu.VMState{
|
||||
ID: c.Id,
|
||||
Config: cfg,
|
||||
VMinfo: cfg,
|
||||
PID: pid,
|
||||
}
|
||||
if err := ms.persistence.SaveVM(state); err != nil {
|
||||
@@ -358,7 +402,7 @@ func (ms *managerService) restoreVMs() error {
|
||||
continue
|
||||
}
|
||||
|
||||
cvm := ms.vmFactory(state.Config, ms.eventsLogsSender, state.ID)
|
||||
cvm := ms.vmFactory(state.VMinfo, ms.eventsLogsSender, state.ID)
|
||||
|
||||
if err = cvm.SetProcess(state.PID); err != nil {
|
||||
ms.logger.Warn("Failed to reattach to process", "computation", state.ID, "pid", state.PID, "error", err)
|
||||
|
||||
+43
-19
@@ -45,10 +45,11 @@ func TestRun(t *testing.T) {
|
||||
persistence := new(persistenceMocks.Persistence)
|
||||
vmf.On("Execute", mock.Anything, mock.Anything, mock.Anything).Return(vmMock)
|
||||
tests := []struct {
|
||||
name string
|
||||
req *ComputationRunReq
|
||||
vmStartError error
|
||||
expectedError error
|
||||
name string
|
||||
req *ComputationRunReq
|
||||
binaryBehavior string
|
||||
vmStartError error
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "Successful run",
|
||||
@@ -60,8 +61,9 @@ func TestRun(t *testing.T) {
|
||||
},
|
||||
AgentConfig: &AgentConfig{},
|
||||
},
|
||||
vmStartError: nil,
|
||||
expectedError: nil,
|
||||
binaryBehavior: "success",
|
||||
vmStartError: nil,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "VM start failure",
|
||||
@@ -73,8 +75,9 @@ func TestRun(t *testing.T) {
|
||||
},
|
||||
AgentConfig: &AgentConfig{},
|
||||
},
|
||||
vmStartError: assert.AnError,
|
||||
expectedError: assert.AnError,
|
||||
binaryBehavior: "success",
|
||||
vmStartError: assert.AnError,
|
||||
expectedError: assert.AnError,
|
||||
},
|
||||
{
|
||||
name: "Invalid algorithm hash",
|
||||
@@ -86,8 +89,9 @@ func TestRun(t *testing.T) {
|
||||
},
|
||||
AgentConfig: &AgentConfig{},
|
||||
},
|
||||
vmStartError: nil,
|
||||
expectedError: errInvalidHashLength,
|
||||
binaryBehavior: "success",
|
||||
vmStartError: nil,
|
||||
expectedError: errInvalidHashLength,
|
||||
},
|
||||
{
|
||||
name: "Invalid dataset hash",
|
||||
@@ -104,8 +108,23 @@ func TestRun(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
vmStartError: nil,
|
||||
expectedError: errInvalidHashLength,
|
||||
binaryBehavior: "success",
|
||||
vmStartError: nil,
|
||||
expectedError: errInvalidHashLength,
|
||||
},
|
||||
{
|
||||
name: "Invalid attestation policy",
|
||||
req: &ComputationRunReq{
|
||||
Id: "test-computation",
|
||||
Name: "Test Computation",
|
||||
Algorithm: &Algorithm{
|
||||
Hash: make([]byte, hashLength),
|
||||
},
|
||||
AgentConfig: &AgentConfig{},
|
||||
},
|
||||
binaryBehavior: "fail",
|
||||
vmStartError: nil,
|
||||
expectedError: ErrFailedToCreateAttestationPolicy,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -124,6 +143,7 @@ func TestRun(t *testing.T) {
|
||||
persistence.On("SaveVM", mock.Anything).Return(nil)
|
||||
|
||||
qemuCfg := qemu.Config{
|
||||
EnableSEVSNP: true,
|
||||
VSockConfig: qemu.VSockConfig{
|
||||
GuestCID: 3,
|
||||
},
|
||||
@@ -131,13 +151,17 @@ func TestRun(t *testing.T) {
|
||||
logger := slog.Default()
|
||||
eventsChan := make(chan *ClientStreamMessage, 10)
|
||||
|
||||
tempDir := CreateDummyAttestationPolicyBinary(t, tt.binaryBehavior)
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
ms := &managerService{
|
||||
qemuCfg: qemuCfg,
|
||||
logger: logger,
|
||||
vms: make(map[string]vm.VM),
|
||||
eventsChan: eventsChan,
|
||||
vmFactory: vmf.Execute,
|
||||
persistence: persistence,
|
||||
qemuCfg: qemuCfg,
|
||||
attestationPolicyBinaryPath: tempDir,
|
||||
logger: logger,
|
||||
vms: make(map[string]vm.VM),
|
||||
eventsChan: eventsChan,
|
||||
vmFactory: vmf.Execute,
|
||||
persistence: persistence,
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
@@ -146,7 +170,7 @@ func TestRun(t *testing.T) {
|
||||
|
||||
if tt.expectedError != nil {
|
||||
assert.Error(t, err)
|
||||
assert.ErrorIs(t, err, tt.expectedError)
|
||||
assert.Contains(t, err.Error(), tt.expectedError.Error())
|
||||
assert.Empty(t, port)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
|
||||
Reference in New Issue
Block a user