1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-09 03:36:48 +00:00

fix(instances): add_network escapes posted values

add_network built the interface XML with f-strings, so a posted model
or nwfilter could add arbitrary devices to the domain. It is built with
lxml now; a missing MAC is left to libvirt instead of address='None'.
This commit is contained in:
catborise 2026-10-03 17:56:47 +03:00
parent e94d69a524
commit c789406edf
2 changed files with 34 additions and 13 deletions

View file

@ -1709,23 +1709,21 @@ class wvmInstance(wvmConnect):
else:
interface_type = "direct"
# network modes not handled: default is bridge
xml_iface = f"""
<interface type='{interface_type}'>
<mac address='{mac_address}'/>"""
# Built with lxml so posted values are escaped, never parsed as XML.
iface = etree.Element("interface", type=interface_type)
if mac_address: # otherwise libvirt generates one
etree.SubElement(iface, "mac", address=mac_address)
if interface_type == "network":
xml_iface += f"""<source network='{source}'/>"""
etree.SubElement(iface, "source", network=source)
elif interface_type == "direct":
xml_iface += f"""<source dev='{source}' mode='bridge'/>"""
elif interface_type == "bridge":
xml_iface += f"""<source bridge='{source}'/>"""
etree.SubElement(iface, "source", dev=source, mode="bridge")
else:
raise libvirtError(f"'{interface_type}' is an unexpected interface type.")
xml_iface += f"""<model type='{model}'/>"""
etree.SubElement(iface, "source", bridge=source)
if model:
etree.SubElement(iface, "model", type=model)
if nwfilter:
xml_iface += f"""<filterref filter='{nwfilter}'/>"""
xml_iface += """</interface>"""
etree.SubElement(iface, "filterref", filter=nwfilter)
xml_iface = etree.tostring(iface).decode()
if self.get_status() == 1:
self.instance.attachDeviceFlags(xml_iface, VIR_DOMAIN_AFFECT_LIVE)

View file

@ -52,5 +52,28 @@ class TestChangeNetwork(unittest.TestCase):
self.assertEqual(flags, VIR_DOMAIN_AFFECT_CONFIG)
class TestAddNetworkXml(unittest.TestCase):
def attached(self, **kwargs):
from lxml import etree
inst = stopped_instance()
inst.add_network(**kwargs)
return etree.fromstring(inst.instance.attachDeviceFlags.call_args[0][0])
def test_posted_values_cannot_inject_elements(self):
iface = self.attached(
mac_address="52:54:00:00:00:05",
source="default",
model="virtio'/><filesystem type='mount'/><model type='x",
nwfilter="f'/><evil/>",
)
self.assertEqual([el.tag for el in iface], ["mac", "source", "model", "filterref"])
self.assertEqual(iface.find("model").get("type"), "virtio'/><filesystem type='mount'/><model type='x")
def test_missing_mac_is_left_to_libvirt(self):
iface = self.attached(mac_address="", source="default")
self.assertIsNone(iface.find("mac"))
if __name__ == "__main__":
unittest.main()