This is an automated email from the ASF dual-hosted git repository.
nvazquez pushed a commit to branch 4.22
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/4.22 by this push:
new 250695ec331 Escape snapshot names in libvirt XML (#14201)
250695ec331 is described below
commit 250695ec331328e9fec08a5422d27e91fd4cdf87
Author: Suresh Kumar Anaparti <[email protected]>
AuthorDate: Tue Sep 29 18:43:57 2026 +0530
Escape snapshot names in libvirt XML (#14201)
Co-authored-by: mprokopchuk <[email protected]>
---
.../LibvirtCreateVMSnapshotCommandWrapper.java | 3 ++-
.../LibvirtManageSnapshotCommandWrapper.java | 3 ++-
.../resource/wrapper/LibvirtUtilitiesHelper.java | 5 ++--
.../wrapper/LibvirtUtilitiesHelperTest.java | 27 ++++++++++++++++++++++
4 files changed, 34 insertions(+), 4 deletions(-)
diff --git
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtCreateVMSnapshotCommandWrapper.java
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtCreateVMSnapshotCommandWrapper.java
index de95f785d44..e3b5c0363f1 100644
---
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtCreateVMSnapshotCommandWrapper.java
+++
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtCreateVMSnapshotCommandWrapper.java
@@ -19,6 +19,7 @@
package com.cloud.hypervisor.kvm.resource.wrapper;
+import org.apache.commons.lang.StringEscapeUtils;
import org.libvirt.Connect;
import org.libvirt.Domain;
import org.libvirt.DomainInfo.DomainState;
@@ -57,7 +58,7 @@ public final class LibvirtCreateVMSnapshotCommandWrapper
extends CommandWrapper<
"Create Instance Snapshot Failed due to Instance is
not running: " + vmName + " with domainState = " + domainState);
}
- String vmSnapshotXML = "<domainsnapshot>" + " <name>" +
vmSnapshotName + "</name>"
+ String vmSnapshotXML = "<domainsnapshot>" + " <name>" +
StringEscapeUtils.escapeXml(vmSnapshotName) + "</name>"
+ " <memory snapshot='internal' />" + "</domainsnapshot>";
dm.snapshotCreateXML(vmSnapshotXML);
diff --git
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtManageSnapshotCommandWrapper.java
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtManageSnapshotCommandWrapper.java
index ec900e9981e..53813a0ed1b 100644
---
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtManageSnapshotCommandWrapper.java
+++
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtManageSnapshotCommandWrapper.java
@@ -22,6 +22,7 @@ package com.cloud.hypervisor.kvm.resource.wrapper;
import java.io.File;
import java.text.MessageFormat;
+import org.apache.commons.lang.StringEscapeUtils;
import org.libvirt.Connect;
import org.libvirt.Domain;
import org.libvirt.DomainInfo.DomainState;
@@ -79,7 +80,7 @@ public final class LibvirtManageSnapshotCommandWrapper
extends CommandWrapper<Ma
+ " <uuid>{1}</uuid>" + " </domain>"
+ " </domainsnapshot>");
final String vmUuid = vm.getUUIDString();
- final Object[] args = new Object[] {snapshotName, vmUuid};
+ final Object[] args = new Object[]
{StringEscapeUtils.escapeXml(snapshotName), vmUuid};
final String snapshot = snapshotXML.format(args);
logger.debug(snapshot);
if
(command.getCommandSwitch().equalsIgnoreCase(ManageSnapshotCommand.CREATE_SNAPSHOT))
{
diff --git
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtUtilitiesHelper.java
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtUtilitiesHelper.java
index 70e7f074c87..0a37c971a57 100644
---
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtUtilitiesHelper.java
+++
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtUtilitiesHelper.java
@@ -26,6 +26,7 @@ import com.cloud.agent.api.to.DataTO;
import com.cloud.hypervisor.kvm.storage.KVMStoragePool;
import com.cloud.hypervisor.kvm.storage.KVMStoragePoolManager;
import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
+import org.apache.commons.lang.StringEscapeUtils;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.libvirt.Connect;
@@ -112,9 +113,9 @@ public class LibvirtUtilitiesHelper {
}
public String generateVMSnapshotXML(VMSnapshotTO snapshot, VMSnapshotTO
parent, String domainXmlDesc) {
- String parentName = (parent == null)? "": (" <parent><name>" +
parent.getSnapshotName() + "</name></parent>\n");
+ String parentName = (parent == null)? "": (" <parent><name>" +
StringEscapeUtils.escapeXml(parent.getSnapshotName()) + "</name></parent>\n");
String vmSnapshotXML = "<domainsnapshot>\n"
- + " <name>" + snapshot.getSnapshotName() + "</name>\n"
+ + " <name>" +
StringEscapeUtils.escapeXml(snapshot.getSnapshotName()) + "</name>\n"
+ " <state>running</state>\n"
+ parentName
+ " <creationTime>" + (int)
Math.rint(snapshot.getCreateTime()/1000) + "</creationTime>\n"
diff --git
a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtUtilitiesHelperTest.java
b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtUtilitiesHelperTest.java
index f18f3f83a12..5b9c91fb20a 100644
---
a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtUtilitiesHelperTest.java
+++
b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtUtilitiesHelperTest.java
@@ -25,6 +25,7 @@ import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
+import com.cloud.agent.api.VMSnapshotTO;
import com.cloud.utils.Pair;
import junit.framework.TestCase;
@@ -75,4 +76,30 @@ public class LibvirtUtilitiesHelperTest extends TestCase {
Assert.assertEquals(String.valueOf(libvirtVersion), result.first());
Assert.assertTrue(result.second());
}
+
+ @Test
+ public void generateVMSnapshotXMLEscapesSnapshotName() {
+ VMSnapshotTO snapshot = Mockito.mock(VMSnapshotTO.class);
+ Mockito.doReturn("i-2-3-VM_VS_</name><disks><disk
name='vda'/></disks><name>x").when(snapshot).getSnapshotName();
+ Mockito.doReturn(1000L).when(snapshot).getCreateTime();
+
+ String xml = libvirtUtilitiesHelperSpy.generateVMSnapshotXML(snapshot,
null, "<domain/>");
+
+
Assert.assertTrue(xml.contains("<name>i-2-3-VM_VS_</name><disks><disk
name='vda'/></disks><name>x</name>"));
+ Assert.assertFalse(xml.contains("<disks>"));
+ }
+
+ @Test
+ public void generateVMSnapshotXMLEscapesParentSnapshotName() {
+ VMSnapshotTO snapshot = Mockito.mock(VMSnapshotTO.class);
+ Mockito.doReturn("child").when(snapshot).getSnapshotName();
+ Mockito.doReturn(1000L).when(snapshot).getCreateTime();
+ VMSnapshotTO parent = Mockito.mock(VMSnapshotTO.class);
+
Mockito.doReturn("parent</name><disks/>").when(parent).getSnapshotName();
+
+ String xml = libvirtUtilitiesHelperSpy.generateVMSnapshotXML(snapshot,
parent, "<domain/>");
+
+
Assert.assertTrue(xml.contains("<parent><name>parent</name><disks/></name></parent>"));
+ Assert.assertFalse(xml.contains("<disks/>"));
+ }
}