From d28d5e97f08097fec6b3367ba87960810a742649 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 14c5be1a524f..861dc8acd75f 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)
 {
@@ -324,25 +347,7 @@ 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 9902d90a31351e2c0a7e3305b2dbf77902a87848 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 861dc8acd75f..dc805547e5b1 100644
--- a/src/vdagentd.c
+++ b/src/vdagentd.c
@@ -319,6 +319,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 cece232bbb019244a4fede21e4c04f380bdbab70 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 dc805547e5b1..ffdffa888d74 100644
--- a/src/vdagentd.c
+++ b/src/vdagentd.c
@@ -332,34 +332,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;
+}
+
 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;
@@ -367,21 +442,6 @@ 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:
@@ -393,31 +453,20 @@ 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 c1116d3e86d5b6a7f60fd1a79f973dfcd5e3821c 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 ffdffa888d74..8b3d5021c8d0 100644
--- a/src/vdagentd.c
+++ b/src/vdagentd.c
@@ -382,6 +382,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:
@@ -395,21 +397,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 bb355bd687d311bbfbc551ee6e47b9774e7df771 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 8b3d5021c8d0..f7ae7f9e6fff 100644
--- a/src/vdagentd.c
+++ b/src/vdagentd.c
@@ -386,8 +386,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) {
@@ -400,6 +398,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 5219e8a7cff04267d0553d4d3ac36458d30edd52 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 |  38 ++++++++++------
 src/vdagentd.c            | 109 +++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 121 insertions(+), 26 deletions(-)

diff --git a/src/vdagent-virtio-port.c b/src/vdagent-virtio-port.c
index b04d55bc2b3b..9b66d25b5310 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"
 
@@ -217,16 +218,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);
@@ -310,13 +311,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;
@@ -421,6 +429,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 f7ae7f9e6fff..17a588d597cd 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));
 }
@@ -276,8 +305,8 @@ static void cancel_file_xfer(struct vdagent_virtio_port *vport,
                              const char *msg, uint32_t id)
 {
     VDAgentFileXferStatusMessage status = {
-        .id = id,
-        .result = VD_AGENT_FILE_XFER_STATUS_CANCELLED,
+        .id = GUINT32_TO_LE(id),
+        .result = GUINT32_TO_LE(VD_AGENT_FILE_XFER_STATUS_CANCELLED),
     };
     syslog(LOG_WARNING, msg, id);
     if (vport)
@@ -352,6 +381,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;
@@ -426,13 +499,16 @@ 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;
@@ -440,11 +516,13 @@ 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:
@@ -452,14 +530,18 @@ 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();
     }
@@ -468,7 +550,7 @@ 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;
 
@@ -489,15 +571,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 */
 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;
@@ -799,8 +884,8 @@ 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

From cb6c141c4621c4bcb4d5bf3e7a8064c513ce32b5 Mon Sep 17 00:00:00 2001
From: Pavel Grunt <pgrunt@redhat.com>
Date: Thu, 23 Mar 2017 12:26:28 +0100
Subject: [PATCH] vdagentd: Handle VD_AGENT_CLIPBOARD_RELEASE

In fact do nothing but avoid a runtime warning
 vdagent_message_clipboard_from_le: code should not be reached

Introduced in 99d9d3583143aef7143ec986cebe2980fdeeb776

Acked-by: Victor Toso <victortoso@redhat.com>
---
 src/vdagentd.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/vdagentd.c b/src/vdagentd.c
index 17a588d597cd..ad28e5d46bf0 100644
--- a/src/vdagentd.c
+++ b/src/vdagentd.c
@@ -401,6 +401,8 @@ static void vdagent_message_clipboard_from_le(VDAgentMessage *message_header,
     case VD_AGENT_CLIPBOARD_GRAB:
         virtio_msg_uint32_from_le(data, message_header->size, min_size);
         break;
+    case VD_AGENT_CLIPBOARD_RELEASE:
+        break;
     default:
         g_warn_if_reached();
     }
-- 
2.10.2

