|
|
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 |
|