Skip to content

Commit 9ea77b9

Browse files
author
Zhang Wenhao
committed
<fix>[kvm]: mark TPM VM host files changed on start/shutdown
When a VM with TPM starts or shuts down, NvRam/TpmState data must have changed. Preemptively set changeDate on the corresponding VmHostFileVO so the periodic tracker knows to sync them, even if the direct sync fails. Also add ResourceDestinationMaker check to all VM canonical event handlers in KvmSecureBootManager to ensure only the owning management node processes each event. Resolves: ZSV-11779 Related: ZSV-11310 Change-Id: I6e6d6c6c647175716669756b75756a6f72657277
1 parent 449ef01 commit 9ea77b9

3 files changed

Lines changed: 130 additions & 41 deletions

File tree

plugin/kvm/src/main/java/org/zstack/kvm/efi/KvmSecureBootExtensions.java

Lines changed: 16 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import org.apache.commons.lang.StringUtils;
44
import org.springframework.beans.factory.annotation.Autowired;
55
import org.zstack.compute.vm.VmGlobalConfig;
6-
import org.zstack.compute.vm.VmSystemTags;
76
import org.zstack.compute.vm.devices.VmTpmManager;
87
import org.zstack.core.Platform;
98
import org.zstack.core.cloudbus.CloudBus;
@@ -23,8 +22,6 @@
2322
import org.zstack.header.errorcode.ErrorCode;
2423
import org.zstack.header.exception.CloudRuntimeException;
2524
import org.zstack.header.message.MessageReply;
26-
import org.zstack.header.tpm.entity.TpmVO;
27-
import org.zstack.header.tpm.entity.TpmVO_;
2825
import org.zstack.header.vm.DiskAO;
2926
import org.zstack.header.vm.PreVmInstantiateResourceExtensionPoint;
3027
import org.zstack.header.vm.VmInstanceVO;
@@ -79,14 +76,14 @@
7976
import java.util.Map;
8077
import java.util.Objects;
8178

82-
import static org.zstack.compute.vm.VmGlobalConfig.ENABLE_UEFI_SECURE_BOOT;
8379
import static org.zstack.core.Platform.operr;
8480
import static org.zstack.header.vm.additions.VmHostFileSyncReason.PostMigration;
8581
import static org.zstack.header.vm.additions.VmHostFileSyncReason.BeforeHaStart;
8682
import static org.zstack.header.vm.additions.VmHostFileSyncReason.PrepareReRead;
8783
import static org.zstack.header.vm.additions.VmHostFileSyncReason.PrepareRead;
8884
import static org.zstack.header.vm.additions.VmHostFileSyncReason.ResourceRelease;
8985
import static org.zstack.header.vm.additions.VmHostFileSyncReason.SnapshotGroupOnlineBackup;
86+
import static org.zstack.header.vm.additions.VmHostFileType.NvRam;
9087
import static org.zstack.kvm.KVMConstant.*;
9188
import static org.zstack.utils.CollectionDSL.list;
9289

@@ -107,6 +104,8 @@ public class KvmSecureBootExtensions implements KVMStartVmExtensionPoint,
107104
private ResourceConfigFacade resourceConfigFacade;
108105
@Autowired
109106
private DatabaseFacade databaseFacade;
107+
@Autowired
108+
private KvmVmHostFileFactory vmHostFileFactory;
110109

111110
private final Object hostFileLock = new Object();
112111

@@ -141,15 +140,15 @@ private void prepareNvRamToStartVmCmd(KVMAgentCommands.StartVmCmd cmd, NvRamSpec
141140
final Timestamp now = Timestamp.from(Instant.now());
142141
VmHostFileVO nvRamFile = Q.New(VmHostFileVO.class)
143142
.eq(VmHostFileVO_.vmInstanceUuid, cmd.getVmInstanceUuid())
144-
.eq(VmHostFileVO_.type, VmHostFileType.NvRam)
143+
.eq(VmHostFileVO_.type, NvRam)
145144
.eq(VmHostFileVO_.hostUuid, host.getUuid())
146145
.find();
147146
if (nvRamFile == null) {
148147
nvRamFile = new VmHostFileVO();
149148
nvRamFile.setUuid(Platform.getUuid());
150149
nvRamFile.setHostUuid(host.getUuid());
151150
nvRamFile.setVmInstanceUuid(cmd.getVmInstanceUuid());
152-
nvRamFile.setType(VmHostFileType.NvRam);
151+
nvRamFile.setType(NvRam);
153152
nvRamFile.setPath(volume.getInstallPath());
154153
nvRamFile.setCreateDate(now);
155154
nvRamFile.setResourceName("NvRam file for " + cmd.getVmInstanceUuid());
@@ -180,29 +179,17 @@ private void prepareNvRamBeforeMigration(VmInstanceInventory vm, String dstHostU
180179
return;
181180
}
182181

183-
String tpmUuid = Q.New(TpmVO.class)
184-
.eq(TpmVO_.vmInstanceUuid, vm.getUuid())
185-
.select(TpmVO_.uuid)
186-
.findValue();
187-
boolean needRegisterNvRam = tpmUuid != null;
182+
boolean needRegisterNvRam = vmHostFileFactory.needRegister(NvRam, vm.getUuid());
188183
if (!needRegisterNvRam) {
189-
String bootMode = VmSystemTags.BOOT_MODE.getTokenByResourceUuid(vm.getUuid(), VmSystemTags.BOOT_MODE_TOKEN);
190-
if (isUefiBootMode(bootMode)) {
191-
ResourceConfig resourceConfig = resourceConfigFacade.getResourceConfig(ENABLE_UEFI_SECURE_BOOT.getIdentity());
192-
needRegisterNvRam = resourceConfig.getResourceConfigValue(vm.getUuid(), Boolean.class) == Boolean.TRUE;
193-
}
194-
195-
if (!needRegisterNvRam) {
196-
completion.success();
197-
return;
198-
}
184+
completion.success();
185+
return;
199186
}
200187

201188
SimpleFlowChain.of("prepare-nvram-before-vm-" + vm.getUuid() + "-migrate")
202189
.then("prepare-nvram-folder-on-dest-host", trigger -> {
203190
VmHostFileTO to = new VmHostFileTO();
204191
to.setPath(buildNvramFilePath(vm.getUuid()));
205-
to.setType(VmHostFileType.NvRam.toString());
192+
to.setType(NvRam.toString());
206193
to.setOperation(VmHostFileOperation.Prepare.toString());
207194

208195
RewriteVmHostFilesContext context = new RewriteVmHostFilesContext();
@@ -290,7 +277,7 @@ public void preInstantiateVmResource(VmInstanceSpec spec, Completion completion)
290277
PrepareHostFileContext context = new PrepareHostFileContext();
291278
context.hostUuid = spec.getDestHost().getUuid();
292279
context.vmUuid = spec.getVmInventory().getUuid();
293-
context.type = VmHostFileType.NvRam;
280+
context.type = NvRam;
294281
context.backupUuid = nvRamSpec.getBackupFileUuid();
295282
context.syncReason = "pre-instantiate VM resource";
296283
prepareHostFileOnHost(context, completion);
@@ -349,7 +336,7 @@ public void run(FlowTrigger trigger, Map data) {
349336
syncMsg.setVmUuid(context.vmUuid);
350337
syncMsg.setSyncReason(PrepareRead.reason(context.syncReason));
351338

352-
if (vmHostFile.getType() == VmHostFileType.NvRam) {
339+
if (vmHostFile.getType() == NvRam) {
353340
context.path = vmHostFile.getPath();
354341
syncMsg.setNvRamPath(context.path);
355342
} else if (vmHostFile.getType() == VmHostFileType.TpmState) {
@@ -471,7 +458,7 @@ public void run(FlowTrigger trigger, Map data) {
471458
syncMsg.setVmUuid(context.vmUuid);
472459
syncMsg.setSyncReason(PrepareReRead.reason(context.syncReason));
473460

474-
if (context.type == VmHostFileType.NvRam) {
461+
if (context.type == NvRam) {
475462
syncMsg.setNvRamPath(context.path);
476463
} else if (context.type == VmHostFileType.TpmState) {
477464
syncMsg.setTpmStateFolder(context.path);
@@ -574,7 +561,7 @@ public void releaseVmResource(VmInstanceSpec spec, Completion completion) {
574561
syncMsg.setSyncReason(ResourceRelease.reason());
575562

576563
for (VmHostFileVO file : vmHostFiles) {
577-
if (file.getType() == VmHostFileType.NvRam) {
564+
if (file.getType() == NvRam) {
578565
syncMsg.setNvRamPath(file.getPath());
579566
} else if (file.getType() == VmHostFileType.TpmState) {
580567
syncMsg.setTpmStateFolder(file.getPath());
@@ -633,7 +620,7 @@ public void beforeHaStartVmInstance(String vmUuid, String judgerClassName, List<
633620
syncMsg.setSyncReason(BeforeHaStart.reason());
634621

635622
for (VmHostFileVO file : vmHostFiles) {
636-
if (file.getType() == VmHostFileType.NvRam) {
623+
if (file.getType() == NvRam) {
637624
syncMsg.setNvRamPath(file.getPath());
638625
} else if (file.getType() == VmHostFileType.TpmState) {
639626
syncMsg.setTpmStateFolder(file.getPath());
@@ -699,7 +686,7 @@ public void afterMigrateVm(VmInstanceInventory inv, String srcHostUuid, NoErrorC
699686
syncMsg.setSyncReason(PostMigration.reason());
700687

701688
for (VmHostFileVO file : vmHostFiles) {
702-
if (file.getType() == VmHostFileType.NvRam) {
689+
if (file.getType() == NvRam) {
703690
syncMsg.setNvRamPath(file.getPath());
704691
} else if (file.getType() == VmHostFileType.TpmState) {
705692
syncMsg.setTpmStateFolder(file.getPath());
@@ -759,7 +746,7 @@ public void afterVolumeLiveSnapshotGroupCreatedOnBackend(CreateVolumesSnapshotOv
759746
syncMsg.setHostUuid(hostUuid);
760747

761748
for (VmHostFileVO file : hostFiles) {
762-
if (file.getType() == VmHostFileType.NvRam) {
749+
if (file.getType() == NvRam) {
763750
syncMsg.setNvRamPath(buildNvramSnapshotBackupFilePath(vmUuid));
764751
} else if (file.getType() == VmHostFileType.TpmState) {
765752
syncMsg.setTpmStateFolder(buildTpmStateSnapshotBackupFilePath(vmUuid));

plugin/kvm/src/main/java/org/zstack/kvm/efi/KvmSecureBootManager.java

Lines changed: 74 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import org.zstack.core.cloudbus.EventCallback;
99
import org.zstack.core.cloudbus.EventFacadeImpl;
1010
import org.zstack.core.cloudbus.MessageSafe;
11+
import org.zstack.core.cloudbus.ResourceDestinationMaker;
1112
import org.zstack.core.db.DatabaseFacade;
1213
import org.zstack.core.db.Q;
1314
import org.zstack.core.db.SQL;
@@ -27,8 +28,6 @@
2728
import org.zstack.header.exception.CloudRuntimeException;
2829
import org.zstack.header.message.Message;
2930
import org.zstack.header.message.MessageReply;
30-
import org.zstack.header.tpm.entity.TpmVO;
31-
import org.zstack.header.tpm.entity.TpmVO_;
3231
import org.zstack.header.vm.VmCanonicalEvents;
3332
import org.zstack.header.vm.VmInstanceConstant;
3433
import org.zstack.header.vm.VmInstanceVO;
@@ -76,7 +75,6 @@
7675
import java.util.Set;
7776
import java.util.function.Function;
7877

79-
import static org.zstack.compute.vm.VmGlobalConfig.ENABLE_UEFI_SECURE_BOOT;
8078
import static org.zstack.compute.vm.VmGlobalConfig.RESET_TPM_AFTER_VM_CLONE;
8179
import static org.zstack.core.Platform.operr;
8280
import static org.zstack.header.vm.additions.VmHostFileSyncReason.PostClone;
@@ -104,6 +102,8 @@ public class KvmSecureBootManager extends AbstractService {
104102
private KvmVmHostFileFactory vmHostFileFactory;
105103
@Autowired
106104
private TimeHelper timeHelper;
105+
@Autowired
106+
private ResourceDestinationMaker resourceDestinationMaker;
107107

108108
@Override
109109
public boolean start() {
@@ -118,10 +118,27 @@ public boolean stop() {
118118

119119
@SuppressWarnings("rawtypes")
120120
private void setupCanonicalEvents() {
121+
eventFacade.on(VmCanonicalEvents.VM_LIBVIRT_REPORT_START, new EventCallback<Object>() {
122+
@Override
123+
protected void run(Map tokens, Object data) {
124+
String vmUuid = (String) data;
125+
boolean managedByMe = resourceDestinationMaker.isManagedByUs(vmUuid);
126+
if (!managedByMe) {
127+
return;
128+
}
129+
markVmHostFilesChanged(vmUuid);
130+
}
131+
});
132+
121133
eventFacade.on(VmCanonicalEvents.VM_LIBVIRT_REPORT_SHUTDOWN, new EventCallback<Object>() {
122134
@Override
123135
protected void run(Map tokens, Object data) {
124136
String vmUuid = (String) data;
137+
boolean managedByMe = resourceDestinationMaker.isManagedByUs(vmUuid);
138+
if (!managedByMe) {
139+
return;
140+
}
141+
125142
Tuple tuple = Q.New(VmInstanceVO.class)
126143
.select(VmInstanceVO_.hostUuid, VmInstanceVO_.lastHostUuid)
127144
.eq(VmInstanceVO_.uuid, vmUuid)
@@ -134,6 +151,7 @@ protected void run(Map tokens, Object data) {
134151
if (hostUuid == null) {
135152
hostUuid = (String) tuple.get(1);
136153
}
154+
markVmHostFilesChanged(vmUuid, hostUuid);
137155

138156
List<VmHostFileVO> hostFiles = Q.New(VmHostFileVO.class)
139157
.eq(VmHostFileVO_.vmInstanceUuid, vmUuid)
@@ -173,6 +191,51 @@ public void run(MessageReply reply) {
173191
});
174192
}
175193

194+
/**
195+
* Preemptive judgment: when a VM with TPM (or enabled secure boot) starts or shuts down,
196+
* the NvRam/TpmState data must have changed, so mark the corresponding
197+
* VmHostFileVO.changeDate to current time.
198+
*/
199+
private void markVmHostFilesChanged(String vmUuid) {
200+
Tuple tuple = Q.New(VmInstanceVO.class)
201+
.select(VmInstanceVO_.hostUuid, VmInstanceVO_.lastHostUuid)
202+
.eq(VmInstanceVO_.uuid, vmUuid)
203+
.findTuple();
204+
if (tuple == null) {
205+
return;
206+
}
207+
208+
String hostUuid = (String) tuple.get(0);
209+
if (hostUuid == null) {
210+
hostUuid = (String) tuple.get(1);
211+
}
212+
if (hostUuid == null) {
213+
return;
214+
}
215+
216+
markVmHostFilesChanged(vmUuid, hostUuid);
217+
}
218+
219+
private void markVmHostFilesChanged(String vmUuid, String hostUuid) {
220+
final Set<VmHostFileType> types = vmHostFileFactory.vmHostFileTypeNeedRegisterForVm(vmUuid);
221+
if (types.isEmpty()) {
222+
return;
223+
}
224+
225+
Timestamp now = new Timestamp(timeHelper.getCurrentTimeMillis());
226+
long updated = SQL.New(VmHostFileVO.class)
227+
.eq(VmHostFileVO_.vmInstanceUuid, vmUuid)
228+
.eq(VmHostFileVO_.hostUuid, hostUuid)
229+
.in(VmHostFileVO_.type, types)
230+
.set(VmHostFileVO_.changeDate, now)
231+
.update();
232+
233+
if (updated > 0) {
234+
logger.debug(String.format("preemptively marked VmHostFiles as changed for VM[uuid:%s] on host[uuid:%s], %d records updated",
235+
vmUuid, hostUuid, updated));
236+
}
237+
}
238+
176239
@Override
177240
public String getId() {
178241
return bus.makeLocalServiceId(VmInstanceConstant.SECURE_BOOT_SERVICE_ID);
@@ -473,22 +536,21 @@ protected void scripts() {
473536
private void handle(CloneVmHostFileMsg msg) {
474537
CloneVmHostFileReply reply = new CloneVmHostFileReply();
475538

476-
boolean hasTpm = Q.New(TpmVO.class)
477-
.eq(TpmVO_.vmInstanceUuid, msg.getSrcVmUuid())
478-
.isExists();
479-
ResourceConfig resourceConfig = resourceConfigFacade.getResourceConfig(ENABLE_UEFI_SECURE_BOOT.getIdentity());
480-
boolean secureBoot = resourceConfig.getResourceConfigValue(msg.getSrcVmUuid(), Boolean.class);
481-
if (!hasTpm && !secureBoot) {
539+
final Set<VmHostFileType> types = vmHostFileFactory.vmHostFileTypeNeedRegisterForVm(msg.getSrcVmUuid());
540+
if (types.isEmpty()) {
482541
bus.reply(msg, reply);
483542
return;
484543
}
485544

486545
CloneVmHostFileContext context = new CloneVmHostFileContext();
487-
context.typesNeedClone.add(VmHostFileType.NvRam);
488-
if (hasTpm) {
546+
if (types.contains(VmHostFileType.NvRam)) {
547+
context.typesNeedClone.add(VmHostFileType.NvRam);
548+
}
549+
550+
if (types.contains(VmHostFileType.TpmState)) {
489551
boolean resetTpm;
490552
if (msg.getResetTpm() == null) {
491-
resourceConfig = resourceConfigFacade.getResourceConfig(RESET_TPM_AFTER_VM_CLONE.getIdentity());
553+
ResourceConfig resourceConfig = resourceConfigFacade.getResourceConfig(RESET_TPM_AFTER_VM_CLONE.getIdentity());
492554
resetTpm = resourceConfig.getResourceConfigValue(msg.getSrcVmUuid(), Boolean.class);
493555
} else {
494556
resetTpm = msg.getResetTpm();

plugin/kvm/src/main/java/org/zstack/kvm/efi/KvmVmHostFileFactory.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,35 @@
11
package org.zstack.kvm.efi;
22

3+
import org.springframework.beans.factory.annotation.Autowired;
4+
import org.zstack.compute.vm.devices.VmTpmManager;
5+
import org.zstack.core.db.Q;
6+
import org.zstack.header.tpm.entity.TpmVO;
7+
import org.zstack.header.tpm.entity.TpmVO_;
38
import org.zstack.header.vm.additions.VmHostBackupFileVO;
9+
import org.zstack.header.vm.additions.VmHostFileType;
410
import org.zstack.header.vm.additions.VmHostFileVO;
511
import org.zstack.kvm.tpm.TpmStateVmHostBackupFileBase;
612
import org.zstack.kvm.tpm.TpmStateVmHostFileBase;
713
import org.zstack.kvm.vmfiles.AbstractVmHostBackupFileBase;
814
import org.zstack.kvm.vmfiles.AbstractVmHostFileBase;
15+
import org.zstack.resourceconfig.ResourceConfig;
16+
import org.zstack.resourceconfig.ResourceConfigFacade;
917

18+
import java.util.Collections;
19+
import java.util.HashSet;
20+
import java.util.Set;
21+
22+
import static org.zstack.compute.vm.VmGlobalConfig.ENABLE_UEFI_SECURE_BOOT;
1023
import static org.zstack.core.Platform.operr;
24+
import static org.zstack.header.vm.additions.VmHostFileType.*;
25+
import static org.zstack.utils.CollectionDSL.list;
1126

1227
public class KvmVmHostFileFactory {
28+
@Autowired
29+
private ResourceConfigFacade resourceConfigFacade;
30+
@Autowired
31+
private VmTpmManager vmTpmManager;
32+
1333
public AbstractVmHostFileBase createBase(VmHostFileVO file) {
1434
switch (file.getType()) {
1535
case NvRam: return new NvRamVmHostFileBase(file);
@@ -25,4 +45,24 @@ public AbstractVmHostBackupFileBase createBackupBase(VmHostBackupFileVO backupFi
2545
default: throw operr("invalid VM host file type: " + backupFile.getType()).toException();
2646
}
2747
}
48+
49+
public Set<VmHostFileType> vmHostFileTypeNeedRegisterForVm(String vmUuid) {
50+
if (!vmTpmManager.needRegisterNvRam(vmUuid)) {
51+
return Collections.emptySet();
52+
}
53+
54+
boolean hasTpm = Q.New(TpmVO.class)
55+
.eq(TpmVO_.vmInstanceUuid, vmUuid)
56+
.isExists();
57+
if (hasTpm) {
58+
return new HashSet<>(list(NvRam, TpmState));
59+
}
60+
ResourceConfig resourceConfig = resourceConfigFacade.getResourceConfig(ENABLE_UEFI_SECURE_BOOT.getIdentity());
61+
return resourceConfig.getResourceConfigValue(vmUuid, Boolean.class) == Boolean.TRUE ?
62+
new HashSet<>(list(NvRam)) : Collections.emptySet();
63+
}
64+
65+
public boolean needRegister(VmHostFileType type, String vmUuid) {
66+
return vmHostFileTypeNeedRegisterForVm(vmUuid).contains(type);
67+
}
2868
}

0 commit comments

Comments
 (0)