From b8e990d96f340de2ce36da77c76043a9b43e6da2 Mon Sep 17 00:00:00 2001 From: mprokopchuk Date: Fri, 4 Sep 2026 00:29:53 -0700 Subject: [PATCH] Escape snapshot names in libvirt XML --- ...LibvirtCreateVMSnapshotCommandWrapper.java | 3 ++- .../LibvirtManageSnapshotCommandWrapper.java | 3 ++- .../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 de95f785d44b..e3b5c0363f1e 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 Answer execute(final CreateVMSnapshotCommand cmd, final LibvirtComputingR "Create Instance Snapshot Failed due to Instance is not running: " + vmName + " with domainState = " + domainState); } - String vmSnapshotXML = "" + " " + vmSnapshotName + "" + String vmSnapshotXML = "" + " " + StringEscapeUtils.escapeXml(vmSnapshotName) + "" + " " + ""; 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 ec900e9981e0..53813a0ed1bc 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 @@ 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 Answer execute(final ManageSnapshotCommand command, final LibvirtComputin + " {1}" + " " + " "); 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 70e7f074c879..0a37c971a571 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.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 Script buildScript(final String scriptPath) { } public String generateVMSnapshotXML(VMSnapshotTO snapshot, VMSnapshotTO parent, String domainXmlDesc) { - String parentName = (parent == null)? "": (" " + parent.getSnapshotName() + "\n"); + String parentName = (parent == null)? "": (" " + StringEscapeUtils.escapeXml(parent.getSnapshotName()) + "\n"); String vmSnapshotXML = "\n" - + " " + snapshot.getSnapshotName() + "\n" + + " " + StringEscapeUtils.escapeXml(snapshot.getSnapshotName()) + "\n" + " running\n" + parentName + " " + (int) Math.rint(snapshot.getCreateTime()/1000) + "\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 f18f3f83a12f..5b9c91fb20aa 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.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 void validateIsLibvirtVersionEqualOrHigherThanVersionInParameterLibvirtVe 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_x").when(snapshot).getSnapshotName(); + Mockito.doReturn(1000L).when(snapshot).getCreateTime(); + + String xml = libvirtUtilitiesHelperSpy.generateVMSnapshotXML(snapshot, null, ""); + + Assert.assertTrue(xml.contains("i-2-3-VM_VS_</name><disks><disk name='vda'/></disks><name>x")); + Assert.assertFalse(xml.contains("")); + } + + @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").when(parent).getSnapshotName(); + + String xml = libvirtUtilitiesHelperSpy.generateVMSnapshotXML(snapshot, parent, ""); + + Assert.assertTrue(xml.contains("parent</name><disks/>")); + Assert.assertFalse(xml.contains("")); + } }