Accepting request 459243 from home:michals:boo1012215

Add endian swapping to run on BE guests (boo#1012215).

OBS-URL: https://build.opensuse.org/request/show/459243
OBS-URL: https://build.opensuse.org/package/show/Virtualization/spice-vdagent?expand=0&rev=19
This commit is contained in:
Cédric Bosdonnat 2017-03-07 15:00:43 +00:00 committed by Git OBS Bridge
parent ecc6f57b61
commit ca67a006d4
3 changed files with 727 additions and 1 deletions

View File

@ -1,3 +1,8 @@
-------------------------------------------------------------------
Mon Feb 20 13:56:35 UTC 2017 - msuchanek@suse.com
- Add endian swapping to run on BE guests (boo#1012215).
------------------------------------------------------------------- -------------------------------------------------------------------
Fri Nov 25 18:53:15 UTC 2016 - zaitor@opensuse.org Fri Nov 25 18:53:15 UTC 2016 - zaitor@opensuse.org

View File

@ -1,7 +1,7 @@
# #
# spec file for package spice-vdagent # spec file for package spice-vdagent
# #
# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany. # Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
# Copyright (c) 2014 B1 Systems GmbH, Vohburg, Germany. # Copyright (c) 2014 B1 Systems GmbH, Vohburg, Germany.
# #
# All modifications and additions to the file contributed by third parties # All modifications and additions to the file contributed by third parties
@ -26,6 +26,7 @@ Group: Applications/System
Url: http://spice-space.org/ Url: http://spice-space.org/
Source0: http://spice-space.org/download/releases/%{name}-%{version}.tar.bz2 Source0: http://spice-space.org/download/releases/%{name}-%{version}.tar.bz2
Patch0: spice-vdagent-var_run.patch Patch0: spice-vdagent-var_run.patch
Patch1: vdagentd-do-endian-swapping.patch
BuildRequires: alsa-devel >= 1.0.22 BuildRequires: alsa-devel >= 1.0.22
BuildRequires: desktop-file-utils BuildRequires: desktop-file-utils
BuildRequires: glib2-devel BuildRequires: glib2-devel
@ -57,6 +58,7 @@ Features:
%prep %prep
%setup -q %setup -q
%patch0 -p1 %patch0 -p1
%patch1 -p1
%build %build
%configure \ %configure \

View File

@ -0,0 +1,719 @@
From 1c0c3a0d32d71f2b3890b39b245981c3f32777c5 Mon Sep 17 00:00:00 2001
From: Michal Suchanek <msuchanek@suse.de>
Date: Mon, 23 Jan 2017 14:53:53 +0100
Subject: [PATCH] Move mouse-specific handling out of virtio_port_read_complete
Move some mouse-specific code from the start of
virtio_port_read_complete to a separate helper
as is the case with other message types.
Signed-off-by: Michal Suchanek <msuchanek@suse.de>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
---
src/vdagentd.c | 43 ++++++++++++++++++++++++-------------------
1 file changed, 24 insertions(+), 19 deletions(-)
diff --git a/src/vdagentd.c b/src/vdagentd.c
index a699681..4d587d1 100644
--- a/src/vdagentd.c
+++ b/src/vdagentd.c
@@ -118,6 +118,29 @@ static void do_client_disconnect(void)
}
}
+void do_client_mouse(struct vdagentd_uinput **uinputp, VDAgentMouseState *mouse)
+{
+ vdagentd_uinput_do_mouse(uinputp, mouse);
+ if (!*uinputp) {
+ /* Try to re-open the tablet */
+ struct agent_data *agent_data =
+ udscs_get_user_data(active_session_conn);
+ if (agent_data)
+ *uinputp = vdagentd_uinput_create(uinput_device,
+ agent_data->width,
+ agent_data->height,
+ agent_data->screen_info,
+ agent_data->screen_count,
+ debug > 1,
+ uinput_fake);
+ if (!*uinputp) {
+ syslog(LOG_CRIT, "Fatal uinput error");
+ retval = 1;
+ quit = 1;
+ }
+ }
+}
+
static void do_client_monitors(struct vdagent_virtio_port *vport, int port_nr,
VDAgentMessage *message_header, VDAgentMonitorsConfig *new_monitors)
{
@@ -333,25 +356,7 @@ static int virtio_port_read_complete(
case VD_AGENT_MOUSE_STATE:
if (message_header->size != sizeof(VDAgentMouseState))
goto size_error;
- vdagentd_uinput_do_mouse(&uinput, (VDAgentMouseState *)data);
- if (!uinput) {
- /* Try to re-open the tablet */
- struct agent_data *agent_data =
- udscs_get_user_data(active_session_conn);
- if (agent_data)
- uinput = vdagentd_uinput_create(uinput_device,
- agent_data->width,
- agent_data->height,
- agent_data->screen_info,
- agent_data->screen_count,
- debug > 1,
- uinput_fake);
- if (!uinput) {
- syslog(LOG_CRIT, "Fatal uinput error");
- retval = 1;
- quit = 1;
- }
- }
+ do_client_mouse(&uinput, (VDAgentMouseState *)data);
break;
case VD_AGENT_MONITORS_CONFIG:
if (message_header->size < sizeof(VDAgentMonitorsConfig))
--
2.10.2
From a430acfb779f9cfcc01aaa18a656c8d5a7042a27 Mon Sep 17 00:00:00 2001
From: Michal Suchanek <msuchanek@suse.de>
Date: Fri, 27 Jan 2017 18:53:38 +0100
Subject: [PATCH] vdagentd: Quiet uninitialized variable warning.
With gcc 6.2.1 I cannot build vdagentd because gcc detects msg_type as
potentially uninitialized and vdagentd is built with -Werror.
gcc 4.8.5 does not detect the issue and gcc 7 should be able to tell
that do_client_file_xfer is called only with values of
message_header->type handled in the switch.
Signed-off-by: Michal Suchanek <msuchanek@suse.de>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
---
src/vdagentd.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/vdagentd.c b/src/vdagentd.c
index 4d587d1..0e0d4a3 100644
--- a/src/vdagentd.c
+++ b/src/vdagentd.c
@@ -328,6 +328,8 @@ static void do_client_file_xfer(struct vdagent_virtio_port *vport,
id = d->id;
break;
}
+ default:
+ g_return_if_reached(); /* quiet uninitialized variable warning */
}
conn = g_hash_table_lookup(active_xfers, GUINT_TO_POINTER(id));
--
2.10.2
From dd8ac5e041ab3f8d8c9b3f53e7564566ee183c20 Mon Sep 17 00:00:00 2001
From: Victor Toso <me@victortoso.com>
Date: Mon, 23 Jan 2017 14:53:54 +0100
Subject: [PATCH] vdagentd: early return on bad message size
The payload size for each message should be the size of the expected
struct or bigger when it contain arrays of no fixed size.
This patch creates:
* vdagent_message_min_size[] static array with the expected size for
each message;
* vdagent_message_check_size() which checks the size of message's
payload based on the type of message and by using
vdagent_message_min_size[] as reference"
Signed-off-by: Victor Toso <victortoso@redhat.com>
Signed-off-by: Michal Suchanek <msuchanek@suse.de>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
---
src/vdagentd.c | 133 +++++++++++++++++++++++++++++++++++++++------------------
1 file changed, 91 insertions(+), 42 deletions(-)
diff --git a/src/vdagentd.c b/src/vdagentd.c
index 0e0d4a3..579446a 100644
--- a/src/vdagentd.c
+++ b/src/vdagentd.c
@@ -341,34 +341,109 @@ static void do_client_file_xfer(struct vdagent_virtio_port *vport,
udscs_write(conn, msg_type, 0, 0, data, message_header->size);
}
+static gsize vdagent_message_min_size[] =
+{
+ -1, /* Does not exist */
+ sizeof(VDAgentMouseState), /* VD_AGENT_MOUSE_STATE */
+ sizeof(VDAgentMonitorsConfig), /* VD_AGENT_MONITORS_CONFIG */
+ sizeof(VDAgentReply), /* VD_AGENT_REPLY */
+ sizeof(VDAgentClipboard), /* VD_AGENT_CLIPBOARD */
+ sizeof(VDAgentDisplayConfig), /* VD_AGENT_DISPLAY_CONFIG */
+ sizeof(VDAgentAnnounceCapabilities), /* VD_AGENT_ANNOUNCE_CAPABILITIES */
+ sizeof(VDAgentClipboardGrab), /* VD_AGENT_CLIPBOARD_GRAB */
+ sizeof(VDAgentClipboardRequest), /* VD_AGENT_CLIPBOARD_REQUEST */
+ sizeof(VDAgentClipboardRelease), /* VD_AGENT_CLIPBOARD_RELEASE */
+ sizeof(VDAgentFileXferStartMessage), /* VD_AGENT_FILE_XFER_START */
+ sizeof(VDAgentFileXferStatusMessage), /* VD_AGENT_FILE_XFER_STATUS */
+ sizeof(VDAgentFileXferDataMessage), /* VD_AGENT_FILE_XFER_DATA */
+ 0, /* VD_AGENT_CLIENT_DISCONNECTED */
+ sizeof(VDAgentMaxClipboard), /* VD_AGENT_MAX_CLIPBOARD */
+ sizeof(VDAgentAudioVolumeSync), /* VD_AGENT_AUDIO_VOLUME_SYNC */
+};
+
+static gboolean vdagent_message_check_size(const VDAgentMessage *message_header)
+{
+ uint32_t min_size = 0;
+
+ if (message_header->protocol != VD_AGENT_PROTOCOL) {
+ syslog(LOG_ERR, "message with wrong protocol version ignoring");
+ return FALSE;
+ }
+
+ if (!message_header->type ||
+ message_header->type >= G_N_ELEMENTS(vdagent_message_min_size)) {
+ syslog(LOG_WARNING, "unknown message type %d, ignoring",
+ message_header->type);
+ return FALSE;
+ }
+
+ min_size = vdagent_message_min_size[message_header->type];
+ if (VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
+ VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
+ switch (message_header->type) {
+ case VD_AGENT_CLIPBOARD_GRAB:
+ case VD_AGENT_CLIPBOARD_REQUEST:
+ case VD_AGENT_CLIPBOARD:
+ case VD_AGENT_CLIPBOARD_RELEASE:
+ min_size += 4;
+ }
+ }
+
+ switch (message_header->type) {
+ case VD_AGENT_MONITORS_CONFIG:
+ case VD_AGENT_CLIPBOARD:
+ case VD_AGENT_CLIPBOARD_GRAB:
+ case VD_AGENT_CLIPBOARD_REQUEST:
+ case VD_AGENT_CLIPBOARD_RELEASE:
+ case VD_AGENT_AUDIO_VOLUME_SYNC:
+ case VD_AGENT_ANNOUNCE_CAPABILITIES:
+ if (message_header->size < min_size) {
+ syslog(LOG_ERR, "read: invalid message size: %u for message type: %u",
+ message_header->size, message_header->type);
+ return FALSE;
+ }
+ break;
+ case VD_AGENT_MOUSE_STATE:
+ case VD_AGENT_MAX_CLIPBOARD:
+ if (message_header->size != min_size) {
+ syslog(LOG_ERR, "read: invalid message size: %u for message type: %u",
+ message_header->size, message_header->type);
+ return FALSE;
+ }
+ break;
+ case VD_AGENT_FILE_XFER_START:
+ case VD_AGENT_FILE_XFER_DATA:
+ case VD_AGENT_FILE_XFER_STATUS:
+ case VD_AGENT_CLIENT_DISCONNECTED:
+ /* No size checks for these at the moment */
+ break;
+ case VD_AGENT_DISPLAY_CONFIG:
+ case VD_AGENT_REPLY:
+ default:
+ g_warn_if_reached();
+ return FALSE;
+ }
+ return TRUE;
+}
+
static int virtio_port_read_complete(
struct vdagent_virtio_port *vport,
int port_nr,
VDAgentMessage *message_header,
uint8_t *data)
{
- uint32_t min_size = 0;
-
- if (message_header->protocol != VD_AGENT_PROTOCOL) {
- syslog(LOG_ERR, "message with wrong protocol version ignoring");
+ if (!vdagent_message_check_size(message_header))
return 0;
- }
switch (message_header->type) {
case VD_AGENT_MOUSE_STATE:
- if (message_header->size != sizeof(VDAgentMouseState))
- goto size_error;
do_client_mouse(&uinput, (VDAgentMouseState *)data);
break;
case VD_AGENT_MONITORS_CONFIG:
- if (message_header->size < sizeof(VDAgentMonitorsConfig))
- goto size_error;
do_client_monitors(vport, port_nr, message_header,
(VDAgentMonitorsConfig *)data);
break;
case VD_AGENT_ANNOUNCE_CAPABILITIES:
- if (message_header->size < sizeof(VDAgentAnnounceCapabilities))
- goto size_error;
do_client_capabilities(vport, message_header,
(VDAgentAnnounceCapabilities *)data);
break;
@@ -376,21 +451,6 @@ static int virtio_port_read_complete(
case VD_AGENT_CLIPBOARD_REQUEST:
case VD_AGENT_CLIPBOARD:
case VD_AGENT_CLIPBOARD_RELEASE:
- switch (message_header->type) {
- case VD_AGENT_CLIPBOARD_GRAB:
- min_size = sizeof(VDAgentClipboardGrab); break;
- case VD_AGENT_CLIPBOARD_REQUEST:
- min_size = sizeof(VDAgentClipboardRequest); break;
- case VD_AGENT_CLIPBOARD:
- min_size = sizeof(VDAgentClipboard); break;
- }
- if (VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
- VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
- min_size += 4;
- }
- if (message_header->size < min_size) {
- goto size_error;
- }
do_client_clipboard(vport, message_header, data);
break;
case VD_AGENT_FILE_XFER_START:
@@ -402,31 +462,20 @@ static int virtio_port_read_complete(
vdagent_virtio_port_reset(vport, VDP_CLIENT_PORT);
do_client_disconnect();
break;
- case VD_AGENT_MAX_CLIPBOARD:
- if (message_header->size != sizeof(VDAgentMaxClipboard))
- goto size_error;
- VDAgentMaxClipboard *msg = (VDAgentMaxClipboard *)data;
- syslog(LOG_DEBUG, "Set max clipboard: %d", msg->max);
- max_clipboard = msg->max;
+ case VD_AGENT_MAX_CLIPBOARD: {
+ max_clipboard = ((VDAgentMaxClipboard *)data)->max;
+ syslog(LOG_DEBUG, "Set max clipboard: %d", max_clipboard);
break;
+ }
case VD_AGENT_AUDIO_VOLUME_SYNC:
- if (message_header->size < sizeof(VDAgentAudioVolumeSync))
- goto size_error;
-
do_client_volume_sync(vport, port_nr, message_header,
(VDAgentAudioVolumeSync *)data);
break;
default:
- syslog(LOG_WARNING, "unknown message type %d, ignoring",
- message_header->type);
+ g_warn_if_reached();
}
return 0;
-
-size_error:
- syslog(LOG_ERR, "read: invalid message size: %u for message type: %u",
- message_header->size, message_header->type);
- return 0;
}
static void virtio_write_clipboard(uint8_t selection, uint32_t msg_type,
--
2.10.2
From 3102dca497aae947c29455876cad5ba882613224 Mon Sep 17 00:00:00 2001
From: Christophe Fergeau <cfergeau@redhat.com>
Date: Mon, 30 Jan 2017 12:57:55 +0100
Subject: [PATCH] vdagentd: Add missing size checks
Acked-by: Victor Toso <victortoso@redhat.com>
---
src/vdagentd.c | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/src/vdagentd.c b/src/vdagentd.c
index 579446a..ffafba9 100644
--- a/src/vdagentd.c
+++ b/src/vdagentd.c
@@ -391,6 +391,8 @@ static gboolean vdagent_message_check_size(const VDAgentMessage *message_header)
switch (message_header->type) {
case VD_AGENT_MONITORS_CONFIG:
+ case VD_AGENT_FILE_XFER_START:
+ case VD_AGENT_FILE_XFER_DATA:
case VD_AGENT_CLIPBOARD:
case VD_AGENT_CLIPBOARD_GRAB:
case VD_AGENT_CLIPBOARD_REQUEST:
@@ -404,21 +406,17 @@ static gboolean vdagent_message_check_size(const VDAgentMessage *message_header)
}
break;
case VD_AGENT_MOUSE_STATE:
+ case VD_AGENT_FILE_XFER_STATUS:
+ case VD_AGENT_DISPLAY_CONFIG:
+ case VD_AGENT_REPLY:
case VD_AGENT_MAX_CLIPBOARD:
+ case VD_AGENT_CLIENT_DISCONNECTED:
if (message_header->size != min_size) {
syslog(LOG_ERR, "read: invalid message size: %u for message type: %u",
message_header->size, message_header->type);
return FALSE;
}
break;
- case VD_AGENT_FILE_XFER_START:
- case VD_AGENT_FILE_XFER_DATA:
- case VD_AGENT_FILE_XFER_STATUS:
- case VD_AGENT_CLIENT_DISCONNECTED:
- /* No size checks for these at the moment */
- break;
- case VD_AGENT_DISPLAY_CONFIG:
- case VD_AGENT_REPLY:
default:
g_warn_if_reached();
return FALSE;
--
2.10.2
From 1b59bd11ebc3edce1957bfaaaeb90e559171e4ad Mon Sep 17 00:00:00 2001
From: Christophe Fergeau <cfergeau@redhat.com>
Date: Mon, 30 Jan 2017 12:58:06 +0100
Subject: [PATCH] vdagentd: Adjust size checks
Acked-by: Victor Toso <victortoso@redhat.com>
---
src/vdagentd.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/vdagentd.c b/src/vdagentd.c
index ffafba9..a1bbf71 100644
--- a/src/vdagentd.c
+++ b/src/vdagentd.c
@@ -395,8 +395,6 @@ static gboolean vdagent_message_check_size(const VDAgentMessage *message_header)
case VD_AGENT_FILE_XFER_DATA:
case VD_AGENT_CLIPBOARD:
case VD_AGENT_CLIPBOARD_GRAB:
- case VD_AGENT_CLIPBOARD_REQUEST:
- case VD_AGENT_CLIPBOARD_RELEASE:
case VD_AGENT_AUDIO_VOLUME_SYNC:
case VD_AGENT_ANNOUNCE_CAPABILITIES:
if (message_header->size < min_size) {
@@ -409,6 +407,8 @@ static gboolean vdagent_message_check_size(const VDAgentMessage *message_header)
case VD_AGENT_FILE_XFER_STATUS:
case VD_AGENT_DISPLAY_CONFIG:
case VD_AGENT_REPLY:
+ case VD_AGENT_CLIPBOARD_REQUEST:
+ case VD_AGENT_CLIPBOARD_RELEASE:
case VD_AGENT_MAX_CLIPBOARD:
case VD_AGENT_CLIENT_DISCONNECTED:
if (message_header->size != min_size) {
--
2.10.2
From 44b2511b2dd621ca6267f73c4f29fccfb0302bc6 Mon Sep 17 00:00:00 2001
From: Michal Suchanek <msuchanek@suse.de>
Date: Fri, 27 Jan 2017 18:53:40 +0100
Subject: [PATCH] vdagentd: Do endian swapping.
This allows running big endian and little endian guest side by side using
cut & paste between them.
There is a general design idea that swapping should come as close to
virtio_read/virtio_write as possible. In particular, the protocol
between vdagent and vdagentd is guest-specific and in native endian.
With muliple layers of headers this is a bit tricky. A few message types
have to be swapped fully before passing through vdagentd.
Signed-off-by: Michal Suchanek <msuchanek@suse.de>
Signed-off-by: Victor Toso <me@victortoso.com>
---
src/vdagent-virtio-port.c | 36 +++++++++------
src/vdagentd.c | 109 +++++++++++++++++++++++++++++++++++++++++-----
2 files changed, 120 insertions(+), 25 deletions(-)
diff --git a/src/vdagent-virtio-port.c b/src/vdagent-virtio-port.c
index 6267c74..2d1ee5b 100644
--- a/src/vdagent-virtio-port.c
+++ b/src/vdagent-virtio-port.c
@@ -28,6 +28,7 @@
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/un.h>
+#include <glib.h>
#include "vdagent-virtio-port.h"
@@ -216,16 +217,16 @@ int vdagent_virtio_port_write_start(
return -1;
}
- chunk_header.port = port_nr;
- chunk_header.size = sizeof(message_header) + data_size;
+ chunk_header.port = GUINT32_TO_LE(port_nr);
+ chunk_header.size = GUINT32_TO_LE(sizeof(message_header) + data_size);
memcpy(new_wbuf->buf + new_wbuf->write_pos, &chunk_header,
sizeof(chunk_header));
new_wbuf->write_pos += sizeof(chunk_header);
- message_header.protocol = VD_AGENT_PROTOCOL;
- message_header.type = message_type;
- message_header.opaque = message_opaque;
- message_header.size = data_size;
+ message_header.protocol = GUINT32_TO_LE(VD_AGENT_PROTOCOL);
+ message_header.type = GUINT32_TO_LE(message_type);
+ message_header.opaque = GUINT64_TO_LE(message_opaque);
+ message_header.size = GUINT32_TO_LE(data_size);
memcpy(new_wbuf->buf + new_wbuf->write_pos, &message_header,
sizeof(message_header));
new_wbuf->write_pos += sizeof(message_header);
@@ -309,13 +310,20 @@ static void vdagent_virtio_port_do_chunk(struct vdagent_virtio_port **vportp)
memcpy((uint8_t *)&port->message_header + port->message_header_read,
vport->chunk_data, read);
port->message_header_read += read;
- if (port->message_header_read == sizeof(port->message_header) &&
- port->message_header.size) {
- port->message_data = malloc(port->message_header.size);
- if (!port->message_data) {
- syslog(LOG_ERR, "out of memory, disconnecting virtio");
- vdagent_virtio_port_destroy(vportp);
- return;
+ if (port->message_header_read == sizeof(port->message_header)) {
+
+ port->message_header.protocol = GUINT32_FROM_LE(port->message_header.protocol);
+ port->message_header.type = GUINT32_FROM_LE(port->message_header.type);
+ port->message_header.opaque = GUINT64_FROM_LE(port->message_header.opaque);
+ port->message_header.size = GUINT32_FROM_LE(port->message_header.size);
+
+ if (port->message_header.size) {
+ port->message_data = malloc(port->message_header.size);
+ if (!port->message_data) {
+ syslog(LOG_ERR, "out of memory, disconnecting virtio");
+ vdagent_virtio_port_destroy(vportp);
+ return;
+ }
}
}
pos = read;
@@ -420,6 +428,8 @@ static void vdagent_virtio_port_do_read(struct vdagent_virtio_port **vportp)
if (vport->chunk_header_read < sizeof(vport->chunk_header)) {
vport->chunk_header_read += n;
if (vport->chunk_header_read == sizeof(vport->chunk_header)) {
+ vport->chunk_header.size = GUINT32_FROM_LE(vport->chunk_header.size);
+ vport->chunk_header.port = GUINT32_FROM_LE(vport->chunk_header.port);
if (vport->chunk_header.size > VD_AGENT_MAX_DATA_SIZE) {
syslog(LOG_ERR, "chunk size %u too large",
vport->chunk_header.size);
diff --git a/src/vdagentd.c b/src/vdagentd.c
index a1bbf71..5ea98eb 100644
--- a/src/vdagentd.c
+++ b/src/vdagentd.c
@@ -78,6 +78,34 @@ static int client_connected = 0;
static int max_clipboard = -1;
/* utility functions */
+static void virtio_msg_uint32_to_le(uint8_t *_msg, uint32_t size, uint32_t offset)
+{
+ uint32_t i, *msg = (uint32_t *)(_msg + offset);
+
+ /* offset - size % 4 should be 0 - extra bytes are ignored */
+ for (i = 0; i < (size - offset) / 4; i++)
+ msg[i] = GUINT32_TO_LE(msg[i]);
+}
+
+static void virtio_msg_uint32_from_le(uint8_t *_msg, uint32_t size, uint32_t offset)
+{
+ uint32_t i, *msg = (uint32_t *)(_msg + offset);
+
+ /* offset - size % 4 should be 0 - extra bytes are ignored */
+ for (i = 0; i < (size - offset) / 4; i++)
+ msg[i] = GUINT32_FROM_LE(msg[i]);
+}
+
+static void virtio_msg_uint16_from_le(uint8_t *_msg, uint32_t size, uint32_t offset)
+{
+ uint32_t i;
+ uint16_t *msg = (uint16_t *)(_msg + offset);
+
+ /* offset - size % 2 should be 0 - extra bytes are ignored */
+ for (i = 0; i < (size - offset) / 2; i++)
+ msg[i] = GUINT16_FROM_LE(msg[i]);
+}
+
/* vdagentd <-> spice-client communication handling */
static void send_capabilities(struct vdagent_virtio_port *vport,
uint32_t request)
@@ -102,6 +130,7 @@ static void send_capabilities(struct vdagent_virtio_port *vport,
VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_GUEST_LINEEND_LF);
VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_MAX_CLIPBOARD);
VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_AUDIO_VOLUME_SYNC);
+ virtio_msg_uint32_to_le((uint8_t *)caps, size, 0);
vdagent_virtio_port_write(vport, VDP_CLIENT_PORT,
VD_AGENT_ANNOUNCE_CAPABILITIES, 0,
@@ -174,8 +203,8 @@ static void do_client_monitors(struct vdagent_virtio_port *vport, int port_nr,
(uint8_t *)mon_config, size);
/* Acknowledge reception of monitors config to spice server / client */
- reply.type = VD_AGENT_MONITORS_CONFIG;
- reply.error = VD_AGENT_SUCCESS;
+ reply.type = GUINT32_TO_LE(VD_AGENT_MONITORS_CONFIG);
+ reply.error = GUINT32_TO_LE(VD_AGENT_SUCCESS);
vdagent_virtio_port_write(vport, port_nr, VD_AGENT_REPLY, 0,
(uint8_t *)&reply, sizeof(reply));
}
@@ -278,8 +307,8 @@ static void send_file_xfer_status(struct vdagent_virtio_port *vport,
const char *msg, uint32_t id, uint32_t xfer_status)
{
VDAgentFileXferStatusMessage status = {
- .id = id,
- .result = xfer_status,
+ .id = GUINT32_TO_LE(id),
+ .result = GUINT32_TO_LE(xfer_status),
};
syslog(LOG_WARNING, msg, id);
if (vport)
@@ -361,6 +390,50 @@ static gsize vdagent_message_min_size[] =
sizeof(VDAgentAudioVolumeSync), /* VD_AGENT_AUDIO_VOLUME_SYNC */
};
+static void vdagent_message_clipboard_from_le(VDAgentMessage *message_header,
+ uint8_t *data)
+{
+ gsize min_size = vdagent_message_min_size[message_header->type];
+ uint32_t *data_type = (uint32_t *) data;
+
+ if (VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
+ VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
+ min_size += 4;
+ data_type++;
+ }
+
+ switch (message_header->type) {
+ case VD_AGENT_CLIPBOARD_REQUEST:
+ case VD_AGENT_CLIPBOARD:
+ *data_type = GUINT32_FROM_LE(*data_type);
+ break;
+ case VD_AGENT_CLIPBOARD_GRAB:
+ virtio_msg_uint32_from_le(data, message_header->size, min_size);
+ break;
+ default:
+ g_warn_if_reached();
+ }
+}
+
+static void vdagent_message_file_xfer_from_le(VDAgentMessage *message_header,
+ uint8_t *data)
+{
+ uint32_t *id = (uint32_t *)data;
+ *id = GUINT32_FROM_LE(*id);
+ id++; /* status */
+
+ switch (message_header->type) {
+ case VD_AGENT_FILE_XFER_DATA: {
+ VDAgentFileXferDataMessage *msg = (VDAgentFileXferDataMessage *)data;
+ msg->size = GUINT64_FROM_LE(msg->size);
+ break;
+ }
+ case VD_AGENT_FILE_XFER_STATUS:
+ *id = GUINT32_FROM_LE(*id); /* status */
+ break;
+ }
+}
+
static gboolean vdagent_message_check_size(const VDAgentMessage *message_header)
{
uint32_t min_size = 0;
@@ -435,13 +508,16 @@ static int virtio_port_read_complete(
switch (message_header->type) {
case VD_AGENT_MOUSE_STATE:
+ virtio_msg_uint32_from_le(data, message_header->size, 0);
do_client_mouse(&uinput, (VDAgentMouseState *)data);
break;
case VD_AGENT_MONITORS_CONFIG:
+ virtio_msg_uint32_from_le(data, message_header->size, 0);
do_client_monitors(vport, port_nr, message_header,
(VDAgentMonitorsConfig *)data);
break;
case VD_AGENT_ANNOUNCE_CAPABILITIES:
+ virtio_msg_uint32_from_le(data, message_header->size, 0);
do_client_capabilities(vport, message_header,
(VDAgentAnnounceCapabilities *)data);
break;
@@ -449,11 +525,13 @@ static int virtio_port_read_complete(
case VD_AGENT_CLIPBOARD_REQUEST:
case VD_AGENT_CLIPBOARD:
case VD_AGENT_CLIPBOARD_RELEASE:
+ vdagent_message_clipboard_from_le(message_header, data);
do_client_clipboard(vport, message_header, data);
break;
case VD_AGENT_FILE_XFER_START:
case VD_AGENT_FILE_XFER_STATUS:
case VD_AGENT_FILE_XFER_DATA:
+ vdagent_message_file_xfer_from_le(message_header, data);
do_client_file_xfer(vport, message_header, data);
break;
case VD_AGENT_CLIENT_DISCONNECTED:
@@ -461,14 +539,18 @@ static int virtio_port_read_complete(
do_client_disconnect();
break;
case VD_AGENT_MAX_CLIPBOARD: {
- max_clipboard = ((VDAgentMaxClipboard *)data)->max;
+ max_clipboard = GUINT32_FROM_LE(((VDAgentMaxClipboard *)data)->max);
syslog(LOG_DEBUG, "Set max clipboard: %d", max_clipboard);
break;
}
- case VD_AGENT_AUDIO_VOLUME_SYNC:
- do_client_volume_sync(vport, port_nr, message_header,
- (VDAgentAudioVolumeSync *)data);
+ case VD_AGENT_AUDIO_VOLUME_SYNC: {
+ VDAgentAudioVolumeSync *vdata = (VDAgentAudioVolumeSync *)data;
+ virtio_msg_uint16_from_le((uint8_t *)vdata, message_header->size,
+ offsetof(VDAgentAudioVolumeSync, volume));
+
+ do_client_volume_sync(vport, port_nr, message_header, vdata);
break;
+ }
default:
g_warn_if_reached();
}
@@ -477,7 +559,7 @@ static int virtio_port_read_complete(
}
static void virtio_write_clipboard(uint8_t selection, uint32_t msg_type,
- uint32_t data_type, const uint8_t *data, uint32_t data_size)
+ uint32_t data_type, uint8_t *data, uint32_t data_size)
{
uint32_t size = data_size;
@@ -498,15 +580,18 @@ static void virtio_write_clipboard(uint8_t selection, uint32_t msg_type,
vdagent_virtio_port_write_append(virtio_port, sel, 4);
}
if (data_type != -1) {
+ data_type = GUINT32_TO_LE(data_type);
vdagent_virtio_port_write_append(virtio_port, (uint8_t*)&data_type, 4);
}
+ if (msg_type == VD_AGENT_CLIPBOARD_GRAB)
+ virtio_msg_uint32_to_le(data, data_size, 0);
vdagent_virtio_port_write_append(virtio_port, data, data_size);
}
/* vdagentd <-> vdagent communication handling */
static int do_agent_clipboard(struct udscs_connection *conn,
- struct udscs_message_header *header, const uint8_t *data)
+ struct udscs_message_header *header, uint8_t *data)
{
uint8_t selection = header->arg1;
uint32_t msg_type = 0, data_type = -1, size = header->size;
@@ -820,8 +905,8 @@ static void agent_read_complete(struct udscs_connection **connp,
break;
case VDAGENTD_FILE_XFER_STATUS:{
VDAgentFileXferStatusMessage status;
- status.id = header->arg1;
- status.result = header->arg2;
+ status.id = GUINT32_TO_LE(header->arg1);
+ status.result = GUINT32_TO_LE(header->arg2);
vdagent_virtio_port_write(virtio_port, VDP_CLIENT_PORT,
VD_AGENT_FILE_XFER_STATUS, 0,
(uint8_t *)&status, sizeof(status));
--
2.10.2