[PATCH v6 3/6] winedbg: Escape XML special characters in qXfer reply.

Jinoh Kang jinoh.kang.kr at gmail.com
Mon Nov 22 08:59:50 CST 2021


Some dynamic strings (e.g. loaded image paths) may contain XML special
characters which breaks parsing.

Fix this by escaping all dynamic strings (i.e. character data and
attribute values) that go into the XML replies.

Signed-off-by: Jinoh Kang <jinoh.kang.kr at gmail.com>
---

Notes:
    On XML special character escaping code:
    
    strcspn() uses lookup tables as well, but as of Wine 6.22
    msvcrt!strcspn allocates 1024 bytes (sizeof(BOOL)*256) of table
    on the stack and populates it on the fly.  It would be slower and
    less cache-friendly than a preallocated, tiny static lookup table.
    
    v5 -> v6: Edit commit message

 programs/winedbg/gdbproxy.c | 63 ++++++++++++++++++++++++++++++++-----
 1 file changed, 56 insertions(+), 7 deletions(-)

diff --git a/programs/winedbg/gdbproxy.c b/programs/winedbg/gdbproxy.c
index 8cc6fac65a6..025f8ed2ffc 100644
--- a/programs/winedbg/gdbproxy.c
+++ b/programs/winedbg/gdbproxy.c
@@ -279,6 +279,55 @@ static inline void reply_buffer_append_uinthex(struct reply_buffer* reply, ULONG
     reply_buffer_append(reply, ptr, len * 2);
 }
 
+static const unsigned char xml_special_chars_lookup_table[16] = {
+    /* The characters should be sorted by its value modulo table length. */
+
+    0x00,       /* NUL */
+    0,
+    0x22,       /* ": 0010|0010 */
+    0, 0, 0,
+    0x26,       /* &: 0010|0110 */
+    0x27,       /* ': 0010|0111 */
+    0, 0, 0, 0,
+    0x3C,       /* <: 0011|1100 */
+    0,
+    0x3E,       /* >: 0011|1110 */
+    0
+};
+
+static inline BOOL is_nul_or_xml_special_char(unsigned char val)
+{
+    const size_t length = ARRAY_SIZE(xml_special_chars_lookup_table);
+    return xml_special_chars_lookup_table[val % length] == val;
+}
+
+static void reply_buffer_append_xmlstr(struct reply_buffer* reply, const char* str)
+{
+    const char *ptr = str, *curr;
+
+    for (;;)
+    {
+        curr = ptr;
+
+        while (!is_nul_or_xml_special_char((unsigned char)*ptr))
+            ptr++;
+
+        reply_buffer_append(reply, curr, ptr - curr);
+
+        switch (*ptr++)
+        {
+        case '"': reply_buffer_append_str(reply, """); break;
+        case '&': reply_buffer_append_str(reply, "&"); break;
+        case '\'': reply_buffer_append_str(reply, "'"); break;
+        case '<': reply_buffer_append_str(reply, "<"); break;
+        case '>': reply_buffer_append_str(reply, ">"); break;
+        case '\0':
+        default:
+            return;
+        }
+    }
+}
+
 static unsigned char checksum(const void* data, int len)
 {
     unsigned cksum = 0;
@@ -1617,9 +1666,9 @@ static BOOL CALLBACK packet_query_libraries_cb(PCSTR mod_name, DWORD64 base, PVO
 
     reply_buffer_append_str(reply, "<library name=\"");
     if (strcmp(mod.LoadedImageName, "[vdso].so") == 0)
-        reply_buffer_append_str(reply, "linux-vdso.so.1");
+        reply_buffer_append_xmlstr(reply, "linux-vdso.so.1");
     else if (mod.LoadedImageName[0] == '/')
-        reply_buffer_append_str(reply, mod.LoadedImageName);
+        reply_buffer_append_xmlstr(reply, mod.LoadedImageName);
     else
     {
         UNICODE_STRING nt_name;
@@ -1634,10 +1683,10 @@ static BOOL CALLBACK packet_query_libraries_cb(PCSTR mod_name, DWORD64 base, PVO
             if (IsWow64Process(gdbctx->process->handle, &is_wow64) &&
                 is_wow64 && (tmp = strstr(unix_path, "system32")))
                 memcpy(tmp, "syswow64", 8);
-            reply_buffer_append_str(reply, unix_path);
+            reply_buffer_append_xmlstr(reply, unix_path);
         }
         else
-            reply_buffer_append_str(reply, mod.LoadedImageName);
+            reply_buffer_append_xmlstr(reply, mod.LoadedImageName);
 
         HeapFree(GetProcessHeap(), 0, unix_path);
         RtlFreeUnicodeString(&nt_name);
@@ -1754,8 +1803,8 @@ static void packet_query_target_xml(struct gdb_context* gdbctx, struct backend_c
             feature = cpu->gdb_register_map[i].feature;
 
             reply_buffer_append_str(reply, "<feature name=\"");
-            if (feature_prefix) reply_buffer_append_str(reply, feature_prefix);
-            reply_buffer_append_str(reply, feature);
+            if (feature_prefix) reply_buffer_append_xmlstr(reply, feature_prefix);
+            reply_buffer_append_xmlstr(reply, feature);
             reply_buffer_append_str(reply, "\">");
 
             if (strcmp(feature_prefix, "org.gnu.gdb.i386.") == 0 &&
@@ -1822,7 +1871,7 @@ static void packet_query_target_xml(struct gdb_context* gdbctx, struct backend_c
         if (cpu->gdb_register_map[i].type)
         {
             reply_buffer_append_str(reply, " type=\"");
-            reply_buffer_append_str(reply, cpu->gdb_register_map[i].type);
+            reply_buffer_append_xmlstr(reply, cpu->gdb_register_map[i].type);
             reply_buffer_append_str(reply, "\"");
         }
 
-- 
2.31.1




More information about the wine-devel mailing list