Blame SOURCES/0001-usbredirparser-Fix-unserialize-on-pristine-check.patch

51f7ab
From 6bf41a231b445ac5190c32e281b698b1ee5379b4 Mon Sep 17 00:00:00 2001
51f7ab
From: Victor Toso <victortoso@redhat.com>
51f7ab
Date: Fri, 24 Jun 2022 23:29:08 +0200
51f7ab
Subject: [PATCH 1/2] usbredirparser: Fix unserialize on pristine check
51f7ab
Content-type: text/plain
51f7ab
51f7ab
As mentioned in the bug below, the user is trying to migrate QEMU and
51f7ab
it is failing on the unserialization of usbredirparser at the target
51f7ab
host. The user does not have USB attached to the VM at all.
51f7ab
51f7ab
I've added a test that shows that serialization is currently broken.
51f7ab
It fails at the 'pristine' check in usbredirparser_unserialize().
51f7ab
51f7ab
This check was added with e37d86c "Skip empty write buffers when
51f7ab
unserializing parser" and restricted further with 186c4c7 "Avoid
51f7ab
memory leak from ill-formatted serialization data"
51f7ab
51f7ab
The issue here is that usbredirparser's initialization sets some
51f7ab
fields and thus it isn't guaranteed to be pristine.
51f7ab
51f7ab
The parser's basic data is:
51f7ab
51f7ab
  | write_buf_count ... : 1
51f7ab
  | write_buf  ........ : 0xbc03e0
51f7ab
  | write_buf_total_size: 80
51f7ab
  | data  ............. : (nil)
51f7ab
  | header_read: ...... : 0
51f7ab
  | type_header_read .. : 0
51f7ab
  | data_read: ........ : 0
51f7ab
51f7ab
The current fix is to to ignore write_buf checks as, again, they are
51f7ab
not guaranteed to be pristine. usbredirparser library should properly
51f7ab
overwrite them when unserializing the data and if there were pending
51f7ab
buffers, they should be freed.
51f7ab
51f7ab
Related: https://bugzilla.redhat.com/show_bug.cgi?id=2096008
51f7ab
51f7ab
Signed-off-by: Victor Toso <victortoso@redhat.com>
51f7ab
---
51f7ab
 tests/meson.build               |   1 +
51f7ab
 tests/serializer.c              | 113 ++++++++++++++++++++++++++++++++
51f7ab
 usbredirparser/usbredirparser.c |   4 +-
51f7ab
 3 files changed, 115 insertions(+), 3 deletions(-)
51f7ab
 create mode 100644 tests/serializer.c
51f7ab
51f7ab
diff --git a/tests/meson.build b/tests/meson.build
51f7ab
index 0d4397b..2a179c9 100644
51f7ab
--- a/tests/meson.build
51f7ab
+++ b/tests/meson.build
51f7ab
@@ -1,5 +1,6 @@
51f7ab
 tests = [
51f7ab
     'filter',
51f7ab
+    'serializer',
51f7ab
 ]
51f7ab
 
51f7ab
 deps = dependency('glib-2.0')
51f7ab
diff --git a/tests/serializer.c b/tests/serializer.c
51f7ab
new file mode 100644
51f7ab
index 0000000..4bd669e
51f7ab
--- /dev/null
51f7ab
+++ b/tests/serializer.c
51f7ab
@@ -0,0 +1,113 @@
51f7ab
+/*
51f7ab
+ * Copyright 2022 Red Hat, Inc.
51f7ab
+ *
51f7ab
+ * This library is free software; you can redistribute it and/or
51f7ab
+ * modify it under the terms of the GNU Lesser General Public
51f7ab
+ * License as published by the Free Software Foundation; either
51f7ab
+ * version 2.1 of the License, or (at your option) any later version.
51f7ab
+ *
51f7ab
+ * This library is distributed in the hope that it will be useful,
51f7ab
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
51f7ab
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
51f7ab
+ * Lesser General Public License for more details.
51f7ab
+ *
51f7ab
+ * You should have received a copy of the GNU Lesser General Public
51f7ab
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
51f7ab
+*/
51f7ab
+#include "config.h"
51f7ab
+
51f7ab
+#define G_LOG_DOMAIN "serializer"
51f7ab
+#define G_LOG_USE_STRUCTURED
51f7ab
+
51f7ab
+#include "usbredirparser.h"
51f7ab
+
51f7ab
+#include <errno.h>
51f7ab
+#include <locale.h>
51f7ab
+#include <glib.h>
51f7ab
+#include <stdlib.h>
51f7ab
+
51f7ab
+
51f7ab
+static void
51f7ab
+log_cb(void *priv, int level, const char *msg)
51f7ab
+{
51f7ab
+    GLogLevelFlags glog_level;
51f7ab
+
51f7ab
+    switch(level) {
51f7ab
+    case usbredirparser_error:
51f7ab
+        glog_level = G_LOG_LEVEL_ERROR;
51f7ab
+        break;
51f7ab
+    case usbredirparser_warning:
51f7ab
+        glog_level = G_LOG_LEVEL_WARNING;
51f7ab
+        break;
51f7ab
+    case usbredirparser_info:
51f7ab
+        glog_level = G_LOG_LEVEL_INFO;
51f7ab
+        break;
51f7ab
+    case usbredirparser_debug:
51f7ab
+    case usbredirparser_debug_data:
51f7ab
+        glog_level = G_LOG_LEVEL_DEBUG;
51f7ab
+        break;
51f7ab
+    default:
51f7ab
+        g_warn_if_reached();
51f7ab
+        return;
51f7ab
+    }
51f7ab
+    g_log_structured(G_LOG_DOMAIN, glog_level, "MESSAGE", msg);
51f7ab
+}
51f7ab
+
51f7ab
+static struct usbredirparser *
51f7ab
+get_usbredirparser(void)
51f7ab
+{
51f7ab
+    struct usbredirparser *parser = usbredirparser_create();
51f7ab
+    g_assert_nonnull(parser);
51f7ab
+
51f7ab
+    uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, };
51f7ab
+    /* Typical caps set by usbredirhost */
51f7ab
+    usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version);
51f7ab
+    usbredirparser_caps_set_cap(caps, usb_redir_cap_filter);
51f7ab
+    usbredirparser_caps_set_cap(caps, usb_redir_cap_device_disconnect_ack);
51f7ab
+    usbredirparser_caps_set_cap(caps, usb_redir_cap_ep_info_max_packet_size);
51f7ab
+    usbredirparser_caps_set_cap(caps, usb_redir_cap_64bits_ids);
51f7ab
+    usbredirparser_caps_set_cap(caps, usb_redir_cap_32bits_bulk_length);
51f7ab
+    usbredirparser_caps_set_cap(caps, usb_redir_cap_bulk_receiving);
51f7ab
+#if LIBUSBX_API_VERSION >= 0x01000103
51f7ab
+    usbredirparser_caps_set_cap(caps, usb_redir_cap_bulk_streams);
51f7ab
+#endif
51f7ab
+    int parser_flags = usbredirparser_fl_usb_host;
51f7ab
+
51f7ab
+    parser->log_func = log_cb;
51f7ab
+    usbredirparser_init(parser,
51f7ab
+                        PACKAGE_STRING,
51f7ab
+                        caps,
51f7ab
+                        USB_REDIR_CAPS_SIZE,
51f7ab
+                        parser_flags);
51f7ab
+    return parser;
51f7ab
+}
51f7ab
+
51f7ab
+static void
51f7ab
+simple (gconstpointer user_data)
51f7ab
+{
51f7ab
+    uint8_t *state = NULL;
51f7ab
+    int ret, len = -1;
51f7ab
+
51f7ab
+    struct usbredirparser *source = get_usbredirparser();
51f7ab
+    ret = usbredirparser_serialize(source, &state, &len;;
51f7ab
+    g_assert_cmpint(ret, ==, 0);
51f7ab
+
51f7ab
+    struct usbredirparser *target = get_usbredirparser();
51f7ab
+    ret = usbredirparser_unserialize(target, state, len);
51f7ab
+    g_assert_cmpint(ret, ==, 0);
51f7ab
+
51f7ab
+    g_clear_pointer(&state, free);
51f7ab
+    usbredirparser_destroy(source);
51f7ab
+    usbredirparser_destroy(target);
51f7ab
+}
51f7ab
+
51f7ab
+int
51f7ab
+main(int argc, char **argv)
51f7ab
+{
51f7ab
+    setlocale(LC_ALL, "");
51f7ab
+    g_test_init(&argc, &argv, NULL);
51f7ab
+
51f7ab
+    g_test_add_data_func("/serializer/serialize-and-unserialize", NULL, simple);
51f7ab
+
51f7ab
+    return g_test_run();
51f7ab
+}
51f7ab
diff --git a/usbredirparser/usbredirparser.c b/usbredirparser/usbredirparser.c
51f7ab
index cd1136b..a5dd0e7 100644
51f7ab
--- a/usbredirparser/usbredirparser.c
51f7ab
+++ b/usbredirparser/usbredirparser.c
51f7ab
@@ -1816,9 +1816,7 @@ int usbredirparser_unserialize(struct usbredirparser *parser_pub,
51f7ab
         return -1;
51f7ab
     }
51f7ab
 
51f7ab
-    if (!(parser->write_buf_count == 0 && parser->write_buf == NULL &&
51f7ab
-          parser->write_buf_total_size == 0 &&
51f7ab
-          parser->data == NULL && parser->header_read == 0 &&
51f7ab
+    if (!(parser->data == NULL && parser->header_read == 0 &&
51f7ab
           parser->type_header_read == 0 && parser->data_read == 0)) {
51f7ab
         ERROR("unserialization must use a pristine parser");
51f7ab
         usbredirparser_assert_invariants(parser);
51f7ab
-- 
51f7ab
2.37.1
51f7ab