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@xxxxxxxxxx | libxml GNOME XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | Rpmfind RPM search engine http://rpmfind.net/
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); } }
-- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list