[libvirt] [PATCH 4/4] xend: Escape reserved sexpr characters

Cole Robinson crobinso at redhat.com
Fri Nov 19 16:15:39 UTC 2010


If we don't escape ' or \ xend can't parse the generated sexpr. This
might over apply the EscapeSexpr routine, but it shouldn't hurt.

Signed-off-by: Cole Robinson <crobinso at redhat.com>
---
 src/util/buf.c                             |   79 +++++++++++++++++++
 src/util/buf.h                             |    1 +
 src/xen/xend_internal.c                    |  115 +++++++++++++++-------------
 tests/xml2sexprdata/xml2sexpr-escape.sexpr |    1 +
 tests/xml2sexprdata/xml2sexpr-escape.xml   |   24 ++++++
 tests/xml2sexprtest.c                      |    1 +
 6 files changed, 169 insertions(+), 52 deletions(-)
 create mode 100644 tests/xml2sexprdata/xml2sexpr-escape.sexpr
 create mode 100644 tests/xml2sexprdata/xml2sexpr-escape.xml

diff --git a/src/util/buf.c b/src/util/buf.c
index 553e2a0..90034ad 100644
--- a/src/util/buf.c
+++ b/src/util/buf.c
@@ -379,6 +379,85 @@ err:
 }
 
 /**
+ * virBufferEscapeSexpr:
+ * @buf:  the buffer to dump
+ * @format: a printf like format string but with only one %s parameter
+ * @str:  the string argument which need to be escaped
+ *
+ * Do a formatted print with a single string to an sexpr buffer. The string
+ * is escaped to avoid generating a sexpr that xen will choke on. This
+ * doesn't fully escape the sexpr, just enough for our code to work.
+ */
+void
+virBufferEscapeSexpr(const virBufferPtr buf,
+                     const char *format,
+                     const char *str)
+{
+    int size, count, len, grow_size;
+    char *escaped, *out;
+    const char *cur;
+
+    if ((format == NULL) || (buf == NULL) || (str == NULL))
+        return;
+
+    if (buf->error)
+        return;
+
+    len = strlen(str);
+    if (VIR_ALLOC_N(escaped, 2 * len + 1) < 0) {
+        virBufferNoMemory(buf);
+        return;
+    }
+
+    cur = str;
+    out = escaped;
+    while (*cur != 0) {
+        switch (*cur) {
+        case '\\':
+        case '\'':
+            *out++ = '\\';
+            /* fallthrough */
+        default:
+            *out++ = *cur;
+        }
+        cur++;
+    }
+    *out = 0;
+
+    if ((buf->use >= buf->size) &&
+        virBufferGrow(buf, 100) < 0) {
+        goto err;
+    }
+
+    size = buf->size - buf->use;
+    if ((count = snprintf(&buf->content[buf->use], size,
+                          format, (char *)escaped)) < 0) {
+            buf->error = 1;
+        goto err;
+    }
+
+    /* Grow buffer if necessary and retry */
+    if (count >= size) {
+        buf->content[buf->use] = 0;
+        grow_size = (count + 1 > 1000) ? count + 1 : 1000;
+        if (virBufferGrow(buf, grow_size) < 0) {
+            goto err;
+        }
+        size = buf->size - buf->use;
+
+        if ((count = snprintf(&buf->content[buf->use], size,
+                              format, (char *)escaped)) < 0) {
+            buf->error = 1;
+            goto err;
+        }
+    }
+    buf->use += count;
+
+err:
+    VIR_FREE(escaped);
+}
+
+/**
  * virBufferURIEncodeString:
  * @buf:  the buffer to append to
  * @str:  the string argument which will be URI-encoded
diff --git a/src/util/buf.h b/src/util/buf.h
index 6616898..54f4de5 100644
--- a/src/util/buf.h
+++ b/src/util/buf.h
@@ -45,6 +45,7 @@ void virBufferVSprintf(const virBufferPtr buf, const char *format, ...)
 void virBufferStrcat(const virBufferPtr buf, ...)
   ATTRIBUTE_SENTINEL;
 void virBufferEscapeString(const virBufferPtr buf, const char *format, const char *str);
+void virBufferEscapeSexpr(const virBufferPtr buf, const char *format, const char *str);
 void virBufferURIEncodeString (const virBufferPtr buf, const char *str);
 
 # define virBufferAddLit(buf_, literal_string_) \
diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c
index 3ccadde..7a36fb0 100644
--- a/src/xen/xend_internal.c
+++ b/src/xen/xend_internal.c
@@ -522,6 +522,7 @@ xend_op_ext(virConnectPtr xend, const char *path, const char *key, va_list ap)
     }
 
     content = virBufferContentAndReset(&buf);
+    DEBUG("xend op: %s\n", content);
     ret = http2unix(xend_post(xend, path, content));
     VIR_FREE(content);
 
@@ -4605,8 +4606,6 @@ virDomainPtr xenDaemonDomainDefineXML(virConnectPtr conn, const char *xmlDesc) {
         goto error;
     }
 
-    DEBUG("Defining w/ sexpr: \n%s", sexpr);
-
     ret = xend_op(conn, "", "op", "new", "config", sexpr, NULL);
     VIR_FREE(sexpr);
     if (ret != 0) {
@@ -5297,11 +5296,12 @@ xenDaemonFormatSxprChr(virDomainChrDefPtr def,
 
     case VIR_DOMAIN_CHR_TYPE_FILE:
     case VIR_DOMAIN_CHR_TYPE_PIPE:
-        virBufferVSprintf(buf, "%s:%s", type, def->data.file.path);
+        virBufferVSprintf(buf, "%s:", type);
+        virBufferEscapeSexpr(buf, "%s", def->data.file.path);
         break;
 
     case VIR_DOMAIN_CHR_TYPE_DEV:
-        virBufferVSprintf(buf, "%s", def->data.file.path);
+        virBufferEscapeSexpr(buf, "%s", def->data.file.path);
         break;
 
     case VIR_DOMAIN_CHR_TYPE_TCP:
@@ -5322,8 +5322,9 @@ xenDaemonFormatSxprChr(virDomainChrDefPtr def,
         break;
 
     case VIR_DOMAIN_CHR_TYPE_UNIX:
-        virBufferVSprintf(buf, "%s:%s%s", type,
-                          def->data.nix.path,
+        virBufferVSprintf(buf, "%s:", type);
+        virBufferEscapeSexpr(buf, "%s", def->data.nix.path);
+        virBufferVSprintf(buf, "%s",
                           def->data.nix.listen ? ",server,nowait" : "");
         break;
     }
@@ -5400,39 +5401,42 @@ xenDaemonFormatSxprDisk(virConnectPtr conn ATTRIBUTE_UNUSED,
 
     if (hvm) {
         /* Xend <= 3.0.2 wants a ioemu: prefix on devices for HVM */
-        if (xendConfigVersion == 1)
-            virBufferVSprintf(buf, "(dev 'ioemu:%s')", def->dst);
-        else                    /* But newer does not */
-            virBufferVSprintf(buf, "(dev '%s:%s')", def->dst,
-                              def->device == VIR_DOMAIN_DISK_DEVICE_CDROM ?
-                              "cdrom" : "disk");
+        if (xendConfigVersion == 1) {
+            virBufferEscapeSexpr(buf, "(dev 'ioemu:%s')", def->dst);
+        } else {
+            /* But newer does not */
+            virBufferEscapeSexpr(buf, "(dev '%s:", def->dst);
+            virBufferEscapeSexpr(buf, "%s')",
+                                 def->device == VIR_DOMAIN_DISK_DEVICE_CDROM ?
+                                 "cdrom" : "disk");
+        }
     } else if (def->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
-        virBufferVSprintf(buf, "(dev '%s:cdrom')", def->dst);
+        virBufferEscapeSexpr(buf, "(dev '%s:cdrom')", def->dst);
     } else {
-        virBufferVSprintf(buf, "(dev '%s')", def->dst);
+        virBufferEscapeSexpr(buf, "(dev '%s')", def->dst);
     }
 
     if (def->src) {
         if (def->driverName) {
             if (STREQ(def->driverName, "tap") ||
                 STREQ(def->driverName, "tap2")) {
-                virBufferVSprintf(buf, "(uname '%s:%s:%s')",
-                                  def->driverName,
-                                  def->driverType ? def->driverType : "aio",
-                                  def->src);
+                virBufferEscapeSexpr(buf, "(uname '%s:", def->driverName);
+                virBufferEscapeSexpr(buf, "%s:",
+                                     def->driverType ? def->driverType : "aio");
+                virBufferEscapeSexpr(buf, "%s')", def->src);
             } else {
-                virBufferVSprintf(buf, "(uname '%s:%s')",
-                                  def->driverName,
-                                  def->src);
+                virBufferEscapeSexpr(buf, "(uname '%s:", def->driverName);
+                virBufferEscapeSexpr(buf, "%s')", def->src);
             }
         } else {
             if (def->type == VIR_DOMAIN_DISK_TYPE_FILE) {
-                virBufferVSprintf(buf, "(uname 'file:%s')", def->src);
+                virBufferEscapeSexpr(buf, "(uname 'file:%s')", def->src);
             } else if (def->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
                 if (def->src[0] == '/')
-                    virBufferVSprintf(buf, "(uname 'phy:%s')", def->src);
+                    virBufferEscapeSexpr(buf, "(uname 'phy:%s')", def->src);
                 else
-                    virBufferVSprintf(buf, "(uname 'phy:/dev/%s')", def->src);
+                    virBufferEscapeSexpr(buf, "(uname 'phy:/dev/%s')",
+                                         def->src);
             } else {
                 virXendError(VIR_ERR_CONFIG_UNSUPPORTED,
                              _("unsupported disk type %s"),
@@ -5501,13 +5505,13 @@ xenDaemonFormatSxprNet(virConnectPtr conn,
 
     switch (def->type) {
     case VIR_DOMAIN_NET_TYPE_BRIDGE:
-        virBufferVSprintf(buf, "(bridge '%s')", def->data.bridge.brname);
+        virBufferEscapeSexpr(buf, "(bridge '%s')", def->data.bridge.brname);
         if (def->data.bridge.script)
             script = def->data.bridge.script;
 
-        virBufferVSprintf(buf, "(script '%s')", script);
+        virBufferEscapeSexpr(buf, "(script '%s')", script);
         if (def->data.bridge.ipaddr != NULL)
-            virBufferVSprintf(buf, "(ip '%s')", def->data.bridge.ipaddr);
+            virBufferEscapeSexpr(buf, "(ip '%s')", def->data.bridge.ipaddr);
         break;
 
     case VIR_DOMAIN_NET_TYPE_NETWORK:
@@ -5530,17 +5534,18 @@ xenDaemonFormatSxprNet(virConnectPtr conn,
                          def->data.network.name);
             return -1;
         }
-        virBufferVSprintf(buf, "(bridge '%s')", bridge);
-        virBufferVSprintf(buf, "(script '%s')", script);
+        virBufferEscapeSexpr(buf, "(bridge '%s')", bridge);
+        virBufferEscapeSexpr(buf, "(script '%s')", script);
         VIR_FREE(bridge);
     }
     break;
 
     case VIR_DOMAIN_NET_TYPE_ETHERNET:
         if (def->data.ethernet.script)
-            virBufferVSprintf(buf, "(script '%s')", def->data.ethernet.script);
+            virBufferEscapeSexpr(buf, "(script '%s')",
+                                 def->data.ethernet.script);
         if (def->data.ethernet.ipaddr != NULL)
-            virBufferVSprintf(buf, "(ip '%s')", def->data.ethernet.ipaddr);
+            virBufferEscapeSexpr(buf, "(ip '%s')", def->data.ethernet.ipaddr);
         break;
 
     case VIR_DOMAIN_NET_TYPE_USER:
@@ -5555,11 +5560,11 @@ xenDaemonFormatSxprNet(virConnectPtr conn,
 
     if (def->ifname != NULL &&
         !STRPREFIX(def->ifname, "vif"))
-        virBufferVSprintf(buf, "(vifname '%s')", def->ifname);
+        virBufferEscapeSexpr(buf, "(vifname '%s')", def->ifname);
 
     if (!hvm) {
         if (def->model != NULL)
-            virBufferVSprintf(buf, "(model '%s')", def->model);
+            virBufferEscapeSexpr(buf, "(model '%s')", def->model);
     }
     else if (def->model == NULL) {
         /*
@@ -5573,7 +5578,7 @@ xenDaemonFormatSxprNet(virConnectPtr conn,
         virBufferAddLit(buf, "(type netfront)");
     }
     else {
-        virBufferVSprintf(buf, "(model '%s')", def->model);
+        virBufferEscapeSexpr(buf, "(model '%s')", def->model);
         virBufferAddLit(buf, "(type ioemu)");
     }
 
@@ -5680,7 +5685,8 @@ xenDaemonFormatSxprSound(virDomainDefPtr def,
                          def->sounds[i]->model);
             return -1;
         }
-        virBufferVSprintf(buf, "%s%s", i ? "," : "", str);
+        virBufferVSprintf(buf, "%s", i ? "," : "");
+        virBufferEscapeSexpr(buf, "%s", str);
     }
 
     if (virBufferError(buf)) {
@@ -5737,10 +5743,13 @@ xenDaemonFormatSxpr(virConnectPtr conn,
     virBuffer buf = VIR_BUFFER_INITIALIZER;
     char uuidstr[VIR_UUID_STRING_BUFLEN];
     const char *tmp;
+    char *bufout;
     int hvm = 0, i;
 
+    DEBUG0("Formatting domain sexpr");
+
     virBufferAddLit(&buf, "(vm ");
-    virBufferVSprintf(&buf, "(name '%s')", def->name);
+    virBufferEscapeSexpr(&buf, "(name '%s')", def->name);
     virBufferVSprintf(&buf, "(memory %lu)(maxmem %lu)",
                       def->mem.cur_balloon/1024, def->mem.max_balloon/1024);
     virBufferVSprintf(&buf, "(vcpus %u)", def->maxvcpus);
@@ -5753,7 +5762,7 @@ xenDaemonFormatSxpr(virConnectPtr conn,
         char *ranges = virDomainCpuSetFormat(def->cpumask, def->cpumasklen);
         if (ranges == NULL)
             goto error;
-        virBufferVSprintf(&buf, "(cpus '%s')", ranges);
+        virBufferEscapeSexpr(&buf, "(cpus '%s')", ranges);
         VIR_FREE(ranges);
     }
 
@@ -5761,16 +5770,16 @@ xenDaemonFormatSxpr(virConnectPtr conn,
     virBufferVSprintf(&buf, "(uuid '%s')", uuidstr);
 
     if (def->description)
-        virBufferVSprintf(&buf, "(description '%s')", def->description);
+        virBufferEscapeSexpr(&buf, "(description '%s')", def->description);
 
     if (def->os.bootloader) {
         if (def->os.bootloader[0])
-            virBufferVSprintf(&buf, "(bootloader '%s')", def->os.bootloader);
+            virBufferEscapeSexpr(&buf, "(bootloader '%s')", def->os.bootloader);
         else
             virBufferAddLit(&buf, "(bootloader)");
 
         if (def->os.bootloaderArgs)
-            virBufferVSprintf(&buf, "(bootloader_args '%s')", def->os.bootloaderArgs);
+            virBufferEscapeSexpr(&buf, "(bootloader_args '%s')", def->os.bootloaderArgs);
     }
 
     if (!(tmp = virDomainLifecycleTypeToString(def->onPoweroff))) {
@@ -5827,20 +5836,20 @@ xenDaemonFormatSxpr(virConnectPtr conn,
         }
 
         if (def->os.kernel)
-            virBufferVSprintf(&buf, "(kernel '%s')", def->os.kernel);
+            virBufferEscapeSexpr(&buf, "(kernel '%s')", def->os.kernel);
         if (def->os.initrd)
-            virBufferVSprintf(&buf, "(ramdisk '%s')", def->os.initrd);
+            virBufferEscapeSexpr(&buf, "(ramdisk '%s')", def->os.initrd);
         if (def->os.root)
-            virBufferVSprintf(&buf, "(root '%s')", def->os.root);
+            virBufferEscapeSexpr(&buf, "(root '%s')", def->os.root);
         if (def->os.cmdline)
-            virBufferVSprintf(&buf, "(args '%s')", def->os.cmdline);
+            virBufferEscapeSexpr(&buf, "(args '%s')", def->os.cmdline);
 
         if (hvm) {
             char bootorder[VIR_DOMAIN_BOOT_LAST+1];
             if (def->os.kernel)
-                virBufferVSprintf(&buf, "(loader '%s')", def->os.loader);
+                virBufferEscapeSexpr(&buf, "(loader '%s')", def->os.loader);
             else
-                virBufferVSprintf(&buf, "(kernel '%s')", def->os.loader);
+                virBufferEscapeSexpr(&buf, "(kernel '%s')", def->os.loader);
 
             virBufferVSprintf(&buf, "(vcpus %u)", def->maxvcpus);
             if (def->vcpus < def->maxvcpus)
@@ -5883,14 +5892,14 @@ xenDaemonFormatSxpr(virConnectPtr conn,
                         def->disks[i]->src == NULL)
                         break;
 
-                    virBufferVSprintf(&buf, "(cdrom '%s')",
-                                      def->disks[i]->src);
+                    virBufferEscapeSexpr(&buf, "(cdrom '%s')",
+                                         def->disks[i]->src);
                     break;
 
                 case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
                     /* all xend versions define floppies here */
-                    virBufferVSprintf(&buf, "(%s '%s')", def->disks[i]->dst,
-                        def->disks[i]->src);
+                    virBufferEscapeSexpr(&buf, "(%s ", def->disks[i]->dst);
+                    virBufferEscapeSexpr(&buf, "'%s')", def->disks[i]->src);
                     break;
 
                 default:
@@ -5942,7 +5951,7 @@ xenDaemonFormatSxpr(virConnectPtr conn,
 
         /* get the device emulation model */
         if (def->emulator && (hvm || xendConfigVersion >= 3))
-            virBufferVSprintf(&buf, "(device_model '%s')", def->emulator);
+            virBufferEscapeSexpr(&buf, "(device_model '%s')", def->emulator);
 
 
         /* PV graphics for xen <= 3.0.4, or HVM graphics for xen <= 3.1.0 */
@@ -5986,7 +5995,9 @@ xenDaemonFormatSxpr(virConnectPtr conn,
         goto error;
     }
 
-    return virBufferContentAndReset(&buf);
+    bufout = virBufferContentAndReset(&buf);
+    DEBUG("Formatted sexpr: \n%s", bufout);
+    return bufout;
 
 error:
     virBufferFreeAndReset(&buf);
diff --git a/tests/xml2sexprdata/xml2sexpr-escape.sexpr b/tests/xml2sexprdata/xml2sexpr-escape.sexpr
new file mode 100644
index 0000000..efb0344
--- /dev/null
+++ b/tests/xml2sexprdata/xml2sexpr-escape.sexpr
@@ -0,0 +1 @@
+(vm (name 'fvtest')(memory 420)(maxmem 420)(vcpus 2)(uuid '596a5d21-71f4-8fb2-e068-e2386a5c413e')(on_poweroff 'destroy')(on_reboot 'destroy')(on_crash 'destroy')(image (hvm (kernel '/var/lib/xen/vmlinuz.2Dn2YT')(ramdisk '/var/lib/xen/initrd.img.0u-Vhq')(args ' method=http://&""download.fedora.devel.redhat.com/pub/fedora/linux/core/test/5.91/x86_64/os  ')(loader '/usr/lib/xen/boot/hvmloader')(vcpus 2)(boot c)(usb 1)(parallel none)(serial pty)(device_model '/usr/lib/xen/bin/qemu-dm')))(device (vbd (dev 'ioemu:xvda')(uname 'file:/root/\'\\some.img')(mode 'w'))))
\ No newline at end of file
diff --git a/tests/xml2sexprdata/xml2sexpr-escape.xml b/tests/xml2sexprdata/xml2sexpr-escape.xml
new file mode 100644
index 0000000..73beb6b
--- /dev/null
+++ b/tests/xml2sexprdata/xml2sexpr-escape.xml
@@ -0,0 +1,24 @@
+<domain type='xen' id='15'>
+  <name>fvtest</name>
+  <uuid>596a5d2171f48fb2e068e2386a5c413e</uuid>
+  <os>
+    <type>hvm</type>
+    <kernel>/var/lib/xen/vmlinuz.2Dn2YT</kernel>
+    <initrd>/var/lib/xen/initrd.img.0u-Vhq</initrd>
+    <cmdline> method=http://&""download.fedora.devel.redhat.com/pub/fedora/linux/core/test/5.91/x86_64/os  </cmdline>
+    <loader>/usr/lib/xen/boot/hvmloader</loader>
+  </os>
+  <memory>430080</memory>
+  <vcpu>2</vcpu>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>destroy</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/lib/xen/bin/qemu-dm</emulator>
+    <disk type='file' device='disk'>
+      <source file='/root/'\some.img'/>
+      <target dev='xvda'/>
+    </disk>
+    <console tty='/dev/pts/4'/>
+  </devices>
+</domain>
diff --git a/tests/xml2sexprtest.c b/tests/xml2sexprtest.c
index 9cf8d39..8a5d115 100644
--- a/tests/xml2sexprtest.c
+++ b/tests/xml2sexprtest.c
@@ -163,6 +163,7 @@ mymain(int argc, char **argv)
     DO_TEST("fv-net-netfront", "fv-net-netfront", "fvtest", 1);
 
     DO_TEST("boot-grub", "boot-grub", "fvtest", 1);
+    DO_TEST("escape", "escape", "fvtest", 1);
 
     virCapabilitiesFree(caps);
 
-- 
1.7.3.2




More information about the libvir-list mailing list