Memory corruption/double free related to xml parsing

Software environment

  • Operating system: arch linux
  • Architecture: x86-64
  • kernel version: 6.4.4-arch1-1
  • libvirt version: master
  • Hypervisor and version: lxc 1:5.0.2

Description of problem

Any unprivileged lxc domain (see below) fails to start on my machine since commit d4b6496f with:

internal error: guest failed to start: Failure in libvirt_lxc startup: unsupported configuration: Unsupported root filesystem type (null)
double free or corruption (out)

In later revisions, including master, it still fails but with a different error:

error : virLXCProcessReportStartupLogError:1129 : internal error: guest failed to start: munmap_chunk(): invalid pointer

Steps to reproduce

  1. define an lxc domain with idmap. The rootfs need not exist for this bug to reproduce.
  2. start the domain

Additional notes

I tried some modification to the source code. In function virXMLParseHelper at line 1134, replacing

g_autoptr(xmlParserCtxt) pctxt = NULL;

with

xmlParserCtxt* pctxt = NULL;

prevents this issue from showing up (but leaks memory, i guess).

Instead, if one omits the &ctxt out-parameter to virXMLParse and retrieves it manually, the issue does not show up:

virDomainObj *
virDomainObjParseFile(const char *filename,
                      virDomainXMLOption *xmlopt,
                      unsigned int flags)
{
    g_autoptr(xmlDoc) xml = NULL;
    g_autoptr(xmlXPathContext) ctxt = NULL;
    int keepBlanksDefault = xmlKeepBlanksDefault(0);

    xml = virXMLParse(filename, NULL, NULL, "domstatus", NULL /* CHANGED HERE: WAS &ctxt */, NULL, false); 
    xmlNodePtr root = xmlDocGetRootElement(xml);     // these 4 lines copied from old versions
    if (!(ctxt = virXMLXPathContextNew(xml)))        //
        return NULL;                                 //
    ctxt->node = root;                               //
    xmlKeepBlanksDefault(keepBlanksDefault);

    if (!xml)
        return NULL;

    return virDomainObjParseXML(ctxt, xmlopt, flags);
}

Furthermore if one does pass &ctxt to virXMLParse maintaining the 4 inserted lines (which effectively overwrite ctxt) the issue is still present. This seems to suggests that it is quite tricky to reproduce, and maybe was present, albeit dormant, before commit d4b6496f.

EDIT: i can only reproduce this if the xml contains the <idmap>.

Additional information

domain xml:

<domain type="lxc">
  <name>debian12</name>
  <uuid>4eb681a8-9fb0-454e-9d30-ef55b0aa4d16</uuid>
  <memory unit="KiB">524288</memory>
  <currentMemory unit="KiB">524288</currentMemory>
  <vcpu placement="static">1</vcpu>
  <resource>
    <partition>/machine</partition>
  </resource>
  <os>
    <type arch="x86_64">exe</type>
    <init>/sbin/init</init>
  </os>
  <idmap>
    <uid start="0" target="165536" count="65536"/>
    <gid start="0" target="165536" count="65536"/>
  </idmap>
  <features>
    <privnet/>
  </features>
  <clock offset="utc"/>
  <on_poweroff>destroy</on_poweroff>
  <on_reboot>restart</on_reboot>
  <on_crash>destroy</on_crash>
  <devices>
    <emulator>/usr/locallibvirt/libexec/libvirt_lxc</emulator>
    <filesystem type="mount" accessmode="mapped">
      <source dir="/path/to/rootfs"/>
      <target dir="/"/>
    </filesystem>
    <console type="pty">
      <target type="lxc" port="0"/>
    </console>
  </devices>
</domain>
Edited by pietro