[libvirt] [PATCH] xml: print uuids or shell-escaped names in the warning

Ján Tomko jtomko at redhat.com
Thu Oct 25 13:41:56 UTC 2012


In the XML warning, this prints uuids for domain names with special
characters in them and shell-escaped names for other elements (like
snapshosts and networks) with special names.
---
When saving snapshots, the domain name is appended to the
"snapshot-edit" command, so using a domain name that needs escaping
would lead to something that can't be just fed to the shell.

diff to v1: xml: shell-escape domain name in comment
The function was changed to shell-escape ']>' instead of '--' as the
latter is more likely to happen.

Domain names don't get escaped, UUIDs are preferred.
---
 src/conf/domain_conf.c   |    6 +++-
 src/libvirt_private.syms |    2 +
 src/qemu/qemu_domain.c   |    3 +-
 src/util/buf.c           |   66 ++++++++++++++++++++++++++++++++++++++++++++++
 src/util/buf.h           |    1 +
 src/util/xml.c           |   61 +++++++++++++++++++++---------------------
 src/util/xml.h           |    1 +
 7 files changed, 108 insertions(+), 32 deletions(-)

diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 0933c08..342bf2c 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -14252,6 +14252,7 @@ int virDomainSaveXML(const char *configDir,
                      virDomainDefPtr def,
                      const char *xml)
 {
+    char uuidstr[VIR_UUID_STRING_BUFLEN];
     char *configFile = NULL;
     int ret = -1;
 
@@ -14265,7 +14266,10 @@ int virDomainSaveXML(const char *configDir,
         goto cleanup;
     }
 
-    ret = virXMLSaveFile(configFile, def->name, "edit", xml);
+    virUUIDFormat(def->uuid, uuidstr);
+    ret = virXMLSaveFile(configFile,
+                         virXMLPickShellSafeCDATA(def->name,uuidstr), "edit",
+                         xml);
 
  cleanup:
     VIR_FREE(configFile);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 699c9a3..4c0b8ca 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -37,6 +37,7 @@ virBufferError;
 virBufferEscape;
 virBufferEscapeSexpr;
 virBufferEscapeShell;
+virBufferEscapeShellXMLCDATA;
 virBufferEscapeString;
 virBufferFreeAndReset;
 virBufferGetIndent;
@@ -1816,6 +1817,7 @@ virURIParse;
 # xml.h
 virXMLChildElementCount;
 virXMLParseHelper;
+virXMLPickShellSafeCDATA;
 virXMLPropString;
 virXMLSaveFile;
 virXPathBoolean;
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 4e6a5e9..1522dec 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -1622,7 +1622,8 @@ qemuDomainSnapshotWriteMetadata(virDomainObjPtr vm,
         goto cleanup;
     }
 
-    if (virAsprintf(&tmp, "snapshot-edit %s", vm->def->name) < 0) {
+    if (virAsprintf(&tmp, "snapshot-edit %s",
+                    virXMLPickShellSafeCDATA(vm->def->name, uuidstr)) < 0) {
         virReportOOMError();
         goto cleanup;
     }
diff --git a/src/util/buf.c b/src/util/buf.c
index 030dc97..7ae52f2 100644
--- a/src/util/buf.c
+++ b/src/util/buf.c
@@ -623,6 +623,72 @@ virBufferEscapeShell(virBufferPtr buf, const char *str)
 }
 
 /**
+ * virBufferEscapeShellXMLCDATA:
+ * @buf: the buffer to append to
+ * @str: an unquoted string
+ *
+ * Quotes a string so that the shell (/bin/sh) will interpret the
+ * quoted string to mean str.  Auto indentation may be applied.
+ * It also escapes any "]]>" so that the string can be used in XML CDATA.
+ */
+void virBufferEscapeShellXMLCDATA(virBufferPtr buf, const char *str)
+{
+    int len;
+    char *escaped, *out;
+    const char *cur;
+    char prev = '\0';
+
+    if ((buf == NULL) || (str == NULL))
+        return;
+
+    if (buf->error)
+        return;
+
+    /* Only quote if str includes shell metacharacters.
+     * This also catches ]]> */
+    if (*str && !strpbrk(str, "\r\t\n !\"#$&'()*;<>?[\\]^`{|}~")) {
+        virBufferAdd(buf, str, -1);
+        return;
+    }
+
+    if (*str) {
+        len = strlen(str);
+        if (xalloc_oversized(4, len) ||
+            VIR_ALLOC_N(escaped, 4 * len + 3) < 0) {
+            virBufferSetError(buf, errno);
+            return;
+        }
+    } else {
+        virBufferAddChar(buf, '\'');
+        return;
+    }
+
+    cur = str;
+    out = escaped;
+
+    *out++ = '\'';
+    while (*cur != 0) {
+        if (*cur == '\'') {
+            *out++ = '\'';
+            /* Replace literal ' with a close ', a \', and a open ' */
+            *out++ = '\\';
+            *out++ = '\'';
+        } else if (prev == ']' && *cur == '>') {
+            /* Replace ]> with ]''> */
+            *out++ = '\'';
+            *out++ = '\'';
+        }
+        prev = *cur;
+        *out++ = *cur++;
+    }
+    *out++ = '\'';
+    *out = 0;
+
+    virBufferAdd(buf, escaped, -1);
+    VIR_FREE(escaped);
+}
+
+/**
  * virBufferStrcat:
  * @buf: the buffer to append to
  * @...:  the variable list of strings, the last argument must be NULL
diff --git a/src/util/buf.h b/src/util/buf.h
index c3a498d..d20b37f 100644
--- a/src/util/buf.h
+++ b/src/util/buf.h
@@ -69,6 +69,7 @@ void virBufferEscapeString(virBufferPtr buf, const char *format,
 void virBufferEscapeSexpr(virBufferPtr buf, const char *format,
                           const char *str);
 void virBufferEscapeShell(virBufferPtr buf, const char *str);
+void virBufferEscapeShellXMLCDATA(virBufferPtr buf, const char *str);
 void virBufferURIEncodeString(virBufferPtr buf, const char *str);
 
 # define virBufferAddLit(buf_, literal_string_) \
diff --git a/src/util/xml.c b/src/util/xml.c
index f3dc256..1cfc15e 100644
--- a/src/util/xml.c
+++ b/src/util/xml.c
@@ -780,49 +780,50 @@ error:
     goto cleanup;
 }
 
+const char *virXMLPickShellSafeCDATA(const char *str1, const char *str2)
+{
+    /* this catches shell metacharacters as well as ]]> */
+    if(str1 && !strpbrk(str1, "\r\t\n !\"#$&'()*;<>?[\\]^`{|}~"))
+        return str1;
+    if(str2 && !strpbrk(str2, "\r\t\n !\"#$&'()*;<>?[\\]^`{|}~"))
+        return str2;
+    return NULL;
+}
 
 static int virXMLEmitWarning(int fd,
                              const char *name,
                              const char *cmd)
 {
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+    char *str = NULL;
     size_t len;
-    const char *prologue = "<!--\n\
-WARNING: THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE \n\
-OVERWRITTEN AND LOST. Changes to this xml configuration should be made using:\n\
-  virsh ";
-    const char *epilogue = "\n\
-or other application using the libvirt API.\n\
--->\n\n";
 
     if (fd < 0 || !name || !cmd) {
         errno = EINVAL;
         return -1;
     }
 
-    len = strlen(prologue);
-    if (safewrite(fd, prologue, len) != len)
-        return -1;
-
-    len = strlen(cmd);
-    if (safewrite(fd, cmd, len) != len)
-        return -1;
-
-    /* Omit the domain name if it contains a double hyphen
-     * because they aren't allowed in XML comments */
-    if (!strstr(name, "--")) {
-        if (safewrite(fd, " ", 1) != 1)
-            return -1;
-
-        len = strlen(name);
-        if (safewrite(fd, name, len) != len)
-            return -1;
-    }
-
-    len = strlen(epilogue);
-    if (safewrite(fd, epilogue, len) != len)
-        return -1;
+    virBufferAddLit(&buf, "<!-- <![CDATA[\n"
+"WARNING: THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE\n"
+"OVERWRITTEN AND LOST. Changes to this xml configuration should be made using:\n"
+"  virsh ");
+    virBufferEscapeShellXMLCDATA(&buf, cmd);
+    virBufferAddChar(&buf,' ');
+    virBufferEscapeShellXMLCDATA(&buf, name);
+    virBufferAddLit(&buf, "\n"
+"or other application using the libvirt API.\n"
+"]]> -->\n\n");
+
+    str = virBufferContentAndReset(&buf);
+    len = strlen(str);
+    if (str)
+        if (safewrite(fd, str, len) == len) {
+            VIR_FREE(str);
+            return 0;
+        }
 
-    return 0;
+    VIR_FREE(str);
+    return -1;
 }
 
 
diff --git a/src/util/xml.h b/src/util/xml.h
index a3750fa..cb6789b 100644
--- a/src/util/xml.h
+++ b/src/util/xml.h
@@ -61,6 +61,7 @@ xmlDocPtr      virXMLParseHelper(int domcode,
                                  const char *url,
                                  xmlXPathContextPtr *pctxt);
 
+const char *virXMLPickShellSafeCDATA(const char *str1, const char *str2);
 /**
  * virXMLParse:
  * @filename: file to parse, or NULL for string parsing
-- 
1.7.8.6




More information about the libvir-list mailing list