c5b0b3
From: =?UTF-8?q?J=C3=A1n=20Tomko?= <jtomko@redhat.com>
c5b0b3
Date: Mon, 30 Mar 2015 12:41:40 +0200
c5b0b3
Subject: [PATCH] Strip control codes in virBufferEscapeString
c5b0b3
c5b0b3
These cannot be represented in XML.
c5b0b3
c5b0b3
We have been stripping them, but only if the string had
c5b0b3
characters that needed escaping: <>"'&
c5b0b3
c5b0b3
Extend the strcspn check to include control codes, and strip
c5b0b3
them even if we don't do any escaping.
c5b0b3
c5b0b3
https://bugzilla.redhat.com/show_bug.cgi?id=1184131
c5b0b3
https://bugzilla.redhat.com/show_bug.cgi?id=1066564
c5b0b3
(cherry picked from commit aeb5262e4397528d582682471cb8075141189465)
c5b0b3
---
c5b0b3
 src/util/virbuffer.c | 14 +++++++++++---
c5b0b3
 tests/virbuftest.c   | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
c5b0b3
 2 files changed, 60 insertions(+), 3 deletions(-)
c5b0b3
c5b0b3
diff --git a/src/util/virbuffer.c b/src/util/virbuffer.c
c5b0b3
index 706dbfa..3d13c90 100644
c5b0b3
--- a/src/util/virbuffer.c
c5b0b3
+++ b/src/util/virbuffer.c
c5b0b3
@@ -438,6 +438,13 @@ virBufferEscapeString(virBufferPtr buf, const char *format, const char *str)
c5b0b3
     int len;
c5b0b3
     char *escaped, *out;
c5b0b3
     const char *cur;
c5b0b3
+    const char forbidden_characters[] = {
c5b0b3
+        0x01,   0x02,   0x03,   0x04,   0x05,   0x06,   0x07,   0x08,
c5b0b3
+        /*\t*/  /*\n*/  0x0B,   0x0C,   /*\r*/  0x0E,   0x0F,   0x10,
c5b0b3
+        0x11,   0x12,   0x13,   0x14,   0x15,   0x16,   0x17,   0x18,
c5b0b3
+        0x19,   '"',    '&',    '\'',   '<',    '>',
c5b0b3
+        '\0'
c5b0b3
+    };
c5b0b3
 
c5b0b3
     if ((format == NULL) || (buf == NULL) || (str == NULL))
c5b0b3
         return;
c5b0b3
@@ -446,7 +453,7 @@ virBufferEscapeString(virBufferPtr buf, const char *format, const char *str)
c5b0b3
         return;
c5b0b3
 
c5b0b3
     len = strlen(str);
c5b0b3
-    if (strcspn(str, "<>&'\"") == len) {
c5b0b3
+    if (strcspn(str, forbidden_characters) == len) {
c5b0b3
         virBufferAsprintf(buf, format, str);
c5b0b3
         return;
c5b0b3
     }
c5b0b3
@@ -490,8 +497,7 @@ virBufferEscapeString(virBufferPtr buf, const char *format, const char *str)
c5b0b3
             *out++ = 'o';
c5b0b3
             *out++ = 's';
c5b0b3
             *out++ = ';';
c5b0b3
-        } else if (((unsigned char)*cur >= 0x20) || (*cur == '\n') || (*cur == '\t') ||
c5b0b3
-                   (*cur == '\r')) {
c5b0b3
+        } else if (!strchr(forbidden_characters, *cur)) {
c5b0b3
             /*
c5b0b3
              * default case, just copy !
c5b0b3
              * Note that character over 0x80 are likely to give problem
c5b0b3
@@ -499,6 +505,8 @@ virBufferEscapeString(virBufferPtr buf, const char *format, const char *str)
c5b0b3
              * it's hard to handle properly we have to assume it's UTF-8 too
c5b0b3
              */
c5b0b3
             *out++ = *cur;
c5b0b3
+        } else {
c5b0b3
+            /* silently ignore control characters */
c5b0b3
         }
c5b0b3
         cur++;
c5b0b3
     }
c5b0b3
diff --git a/tests/virbuftest.c b/tests/virbuftest.c
c5b0b3
index 21cb18b..10398d5 100644
c5b0b3
--- a/tests/virbuftest.c
c5b0b3
+++ b/tests/virbuftest.c
c5b0b3
@@ -349,6 +349,39 @@ testBufAddStr(const void *opaque ATTRIBUTE_UNUSED)
c5b0b3
 
c5b0b3
 
c5b0b3
 static int
c5b0b3
+testBufEscapeStr(const void *opaque ATTRIBUTE_UNUSED)
c5b0b3
+{
c5b0b3
+    const struct testBufAddStrData *data = opaque;
c5b0b3
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
c5b0b3
+    char *actual;
c5b0b3
+    int ret = -1;
c5b0b3
+
c5b0b3
+    virBufferAddLit(&buf, "<c>\n");
c5b0b3
+    virBufferAdjustIndent(&buf, 2);
c5b0b3
+    virBufferEscapeString(&buf, "<el>%s</el>\n", data->data);
c5b0b3
+    virBufferAdjustIndent(&buf, -2);
c5b0b3
+    virBufferAddLit(&buf, "</c>");
c5b0b3
+
c5b0b3
+    if (!(actual = virBufferContentAndReset(&buf))) {
c5b0b3
+        TEST_ERROR("buf is empty");
c5b0b3
+        goto cleanup;
c5b0b3
+    }
c5b0b3
+
c5b0b3
+    if (STRNEQ_NULLABLE(actual, data->expect)) {
c5b0b3
+        TEST_ERROR("testBufEscapeStr(): Strings don't match:\n");
c5b0b3
+        virtTestDifference(stderr, data->expect, actual);
c5b0b3
+        goto cleanup;
c5b0b3
+    }
c5b0b3
+
c5b0b3
+    ret = 0;
c5b0b3
+
c5b0b3
+ cleanup:
c5b0b3
+    VIR_FREE(actual);
c5b0b3
+    return ret;
c5b0b3
+}
c5b0b3
+
c5b0b3
+
c5b0b3
+static int
c5b0b3
 mymain(void)
c5b0b3
 {
c5b0b3
     int ret = 0;
c5b0b3
@@ -379,6 +412,22 @@ mymain(void)
c5b0b3
     DO_TEST_ADD_STR("\n", "<c>\n  \n</c>");
c5b0b3
     DO_TEST_ADD_STR("\n  \n\n", "<c>\n  \n    \n  \n</c>");
c5b0b3
 
c5b0b3
+#define DO_TEST_ESCAPE(data, expect)                                   \
c5b0b3
+    do {                                                               \
c5b0b3
+        struct testBufAddStrData info = { data, expect };              \
c5b0b3
+        if (virtTestRun("Buf: EscapeStr", testBufEscapeStr, &info) < 0)   \
c5b0b3
+            ret = -1;                                                  \
c5b0b3
+    } while (0)
c5b0b3
+
c5b0b3
+    DO_TEST_ESCAPE("",
c5b0b3
+                   "<c>\n  <el><td></td><td></td></el>\n</c>");
c5b0b3
+    DO_TEST_ESCAPE("\007\"&&\"\x15",
c5b0b3
+                   "<c>\n  <el>"&&"</el>\n</c>");
c5b0b3
+    DO_TEST_ESCAPE(",,'..',,",
c5b0b3
+                   "<c>\n  <el>,,'..',,</el>\n</c>");
c5b0b3
+    DO_TEST_ESCAPE("\x01\x01\x02\x03\x05\x08",
c5b0b3
+                   "<c>\n  <el></el>\n</c>");
c5b0b3
+
c5b0b3
     return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
c5b0b3
 }
c5b0b3