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