[Libvir] XML escaping patch

Daniel Veillard veillard at redhat.com
Fri Jul 6 13:49:46 UTC 2007


  This is related to bug #206653
    https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=206653
basically we are very optimistic when generating the XML files, and
sometimes this can break. The most common case is if some string inherited
from the user input or some other config file embeds one of > < or & ,
another one would be if the strings are containing character outside of 
ACSII range and not encoded in UTF-8. We can at least cope with the
easy case of escaping the 3 characters.
This patch adds a simple buffer printing routing working with a simple
string argument, and use it for the 2 cases where I think it's most likely
to be needed i.e. cmdline and bootloader_args. There is a number of places
where paths are used and the user might use weird character names, but since
those cases can't be handled properly (you can't change that path or try
to convert encoding on the fly since we can't guess reliably which one is
used) I didn't tried to change those.
This makes for a relatively simple patch which should IMHO cover most case
where we may break while we really should not.

Daniel


-- 
Red Hat Virtualization group http://redhat.com/virtualization/
Daniel Veillard      | virtualization library  http://libvirt.org/
veillard at redhat.com  | libxml GNOME XML XSLT toolkit  http://xmlsoft.org/
http://veillard.com/ | Rpmfind RPM search engine  http://rpmfind.net/
-------------- next part --------------
Index: src/buf.c
===================================================================
RCS file: /data/cvs/libxen/src/buf.c,v
retrieving revision 1.2
diff -u -p -r1.2 buf.c
--- src/buf.c	29 Jun 2007 13:23:13 -0000	1.2
+++ src/buf.c	6 Jul 2007 13:31:34 -0000
@@ -185,6 +185,82 @@ virBufferVSprintf(virBufferPtr buf, cons
 }
 
 /**
+ * virBufferEscapeString:
+ * @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 XML buffer. The string
+ * is escaped to avoid generating a not well-formed XML instance.
+ *
+ * Returns 0 successful, -1 in case of internal or API error.
+ */
+int
+virBufferEscapeString(virBufferPtr buf, const char *format, const char *str)
+{
+    int size, count, len;
+    char *escaped, *out;
+    const char *cur;
+
+    if ((format == NULL) || (buf == NULL) || (str == NULL)) {
+        return (-1);
+    }
+
+    len = strlen(str);
+    escaped = malloc(5 * len + 1);
+    if (escaped == NULL) {
+        return (-1);
+    }
+    cur = str;
+    out = escaped;
+    while (*cur != 0) {
+        if (*cur == '<') {
+	    *out++ = '&';
+	    *out++ = 'l';
+	    *out++ = 'l';
+	    *out++ = ';';
+	} else if (*cur == '>') {
+	    *out++ = '&';
+	    *out++ = 'g';
+	    *out++ = 't';
+	    *out++ = ';';
+	} else if (*cur == '&') {
+	    *out++ = '&';
+	    *out++ = 'a';
+	    *out++ = 'm';
+	    *out++ = 'p';
+	    *out++ = ';';
+	} else if ((*cur >= 0x20) || (*cur == '\n') || (*cur == '\t') ||
+	           (*cur == '\r')) {
+	    /*
+	     * default case, just copy !
+	     * Note that character over 0x80 are likely to give problem
+	     * with UTF-8 XML, but since our string don't have an encoding
+	     * it's hard to handle properly we have to assume it's UTF-8 too
+	     */
+	    *out++ = *cur;
+	}
+	cur++;
+    }
+    *out = 0;
+
+    size = buf->size - buf->use - 1;
+    while (((count = snprintf(&buf->content[buf->use], size, format,
+                              (char *)escaped)) < 0) || (count >= size - 1)) {
+        buf->content[buf->use] = 0;
+        if (virBufferGrow(buf, 1000) < 0) {
+	    free(escaped);
+            return (-1);
+        }
+        size = buf->size - buf->use - 1;
+    }
+    buf->use += count;
+    buf->content[buf->use] = 0;
+    free(escaped);
+    return (0);
+}
+
+/**
  * virBufferStrcat:
  * @buf:  the buffer to dump
  * @...:  the variable list of strings, the last argument must be NULL
Index: src/buf.h
===================================================================
RCS file: /data/cvs/libxen/src/buf.h,v
retrieving revision 1.1
diff -u -p -r1.1 buf.h
--- src/buf.h	26 Jun 2007 22:33:22 -0000	1.1
+++ src/buf.h	6 Jul 2007 13:31:34 -0000
@@ -33,5 +33,6 @@ int virBufferAdd(virBufferPtr buf, const
 int virBufferVSprintf(virBufferPtr buf, const char *format, ...)
   ATTRIBUTE_FORMAT(printf, 2, 3);
 int virBufferStrcat(virBufferPtr buf, ...);
+int virBufferEscapeString(virBufferPtr buf, const char *format, const char *str);
 
 #endif /* __VIR_BUFFER_H__ */
Index: src/xend_internal.c
===================================================================
RCS file: /data/cvs/libxen/src/xend_internal.c,v
retrieving revision 1.126
diff -u -p -r1.126 xend_internal.c
--- src/xend_internal.c	5 Jul 2007 16:04:12 -0000	1.126
+++ src/xend_internal.c	6 Jul 2007 13:31:34 -0000
@@ -1337,7 +1337,7 @@ xend_parse_sexp_desc_os(virConnectPtr xe
            virBufferVSprintf(buf, "    <root>%s</root>\n", tmp);
         tmp = sexpr_node(node, "domain/image/linux/args");
         if ((tmp != NULL) && (tmp[0] != 0))
-           virBufferVSprintf(buf, "    <cmdline>%s</cmdline>\n", tmp);
+           virBufferEscapeString(buf, "    <cmdline>%s</cmdline>\n", tmp);
     }
 
     virBufferAdd(buf, "  </os>\n", 8);
@@ -1423,7 +1423,7 @@ xend_parse_sexp_desc(virConnectPtr conn,
         /*
          * Only insert bootloader_args if there is also a bootloader param
          */
-        virBufferVSprintf(&buf, "  <bootloader_args>%s</bootloader_args>\n", tmp);
+        virBufferEscapeString(&buf, "  <bootloader_args>%s</bootloader_args>\n", tmp);
     }
 
     if (domid != 0) {
Index: src/xm_internal.c
===================================================================
RCS file: /data/cvs/libxen/src/xm_internal.c,v
retrieving revision 1.34
diff -u -p -r1.34 xm_internal.c
--- src/xm_internal.c	4 Jul 2007 13:16:57 -0000	1.34
+++ src/xm_internal.c	6 Jul 2007 13:31:34 -0000
@@ -663,7 +663,7 @@ char *xenXMDomainFormatXML(virConnectPtr
         if (xenXMConfigGetString(conf, "bootloader", &str) == 0)
             virBufferVSprintf(buf, "  <bootloader>%s</bootloader>\n", str);
         if (xenXMConfigGetString(conf, "bootargs", &str) == 0)
-            virBufferVSprintf(buf, "  <bootloader_args>%s</bootloader_args>\n", str);
+            virBufferEscapeString(buf, "  <bootloader_args>%s</bootloader_args>\n", str);
         if (xenXMConfigGetString(conf, "kernel", &str) == 0) {
             virBufferAdd(buf, "  <os>\n", -1);
             virBufferAdd(buf, "    <type>linux</type>\n", -1);
@@ -671,7 +671,7 @@ char *xenXMDomainFormatXML(virConnectPtr
             if (xenXMConfigGetString(conf, "ramdisk", &str) == 0)
                 virBufferVSprintf(buf, "    <initrd>%s</initrd>\n", str);
             if (xenXMConfigGetString(conf, "extra", &str) == 0)
-                virBufferVSprintf(buf, "    <cmdline>%s</cmdline>\n", str);
+                virBufferEscapeString(buf, "    <cmdline>%s</cmdline>\n", str);
             virBufferAdd(buf, "  </os>\n", -1);
         }
     }


More information about the libvir-list mailing list