Blame SOURCES/0001-red_channel-prevent-adding-and-pushing-pipe-items-af.patch

20333d
From a8c04050adea390fa183a117a8c092fb2ca70620 Mon Sep 17 00:00:00 2001
4c08dd
From: Yonit Halperin <yhalperi@redhat.com>
4c08dd
Date: Wed, 24 Jul 2013 14:54:23 -0400
20333d
Subject: [PATCH] red_channel: prevent adding and pushing pipe items after a
20333d
 channel_client has diconnected
4c08dd
4c08dd
Fixes: leaks of pipe items & "red_client_destroy: assertion `rcc->send_data.size == 0'"
4c08dd
4c08dd
red_channel_disconnect clears the pipe. It is called only once. After,
4c08dd
it was called, not items should be added to the pipe.
4c08dd
4c08dd
An example of when this assert can occur:
4c08dd
on_new_cursor_channel (red_worker.c), pushes 2 pipe items.
4c08dd
When it pushes the first pipe item, if the client has disconnected,
4c08dd
it can hit a socket error, and then, red_channel_client_disconnect is called.
4c08dd
The second call to adding a pipe item, will add the item to
4c08dd
the pipe. red_channel_client_pipe_add_type also calls
4c08dd
red_channel_client_push, which will update the send_data.size.
4c08dd
Then, the push will also hit a socket error, but red_channel_client_disconnect
4c08dd
won't clear the pending pipe item again, since it was already called.
4c08dd
When red_client_destory is called, we hit assertion `rcc->send_data.size
4c08dd
== 0'.
4c08dd
Note that if a pipe item is added to the pipe after
4c08dd
red_channel_client_disconnect was called, but without pushing it,
4c08dd
we should hit "spice_assert(rcc->pipe_size == 0)".
4c08dd
---
4c08dd
 server/red_channel.c | 30 ++++++++++++++++++++++++------
4c08dd
 1 file changed, 24 insertions(+), 6 deletions(-)
4c08dd
4c08dd
diff --git a/server/red_channel.c b/server/red_channel.c
20333d
index 85d7ebc..fa4db7b 100644
4c08dd
--- a/server/red_channel.c
4c08dd
+++ b/server/red_channel.c
20333d
@@ -1515,9 +1515,23 @@ void red_channel_pipe_item_init(RedChannel *channel, PipeItem *item, int type)
4c08dd
     item->type = type;
4c08dd
 }
4c08dd
 
4c08dd
-void red_channel_client_pipe_add(RedChannelClient *rcc, PipeItem *item)
4c08dd
+static inline int validate_pipe_add(RedChannelClient *rcc, PipeItem *item)
4c08dd
 {
4c08dd
     spice_assert(rcc && item);
4c08dd
+    if (SPICE_UNLIKELY(!red_channel_client_is_connected(rcc))) {
4c08dd
+        spice_debug("rcc is disconnected %p", rcc);
4c08dd
+        red_channel_client_release_item(rcc, item, FALSE);
4c08dd
+        return FALSE;
4c08dd
+    }
4c08dd
+    return TRUE;
4c08dd
+}
4c08dd
+
4c08dd
+void red_channel_client_pipe_add(RedChannelClient *rcc, PipeItem *item)
4c08dd
+{
4c08dd
+
4c08dd
+    if (!validate_pipe_add(rcc, item)) {
4c08dd
+        return;
4c08dd
+    }
4c08dd
     rcc->pipe_size++;
4c08dd
     ring_add(&rcc->pipe, &item->link);
4c08dd
 }
20333d
@@ -1531,10 +1545,10 @@ void red_channel_client_pipe_add_push(RedChannelClient *rcc, PipeItem *item)
4c08dd
 void red_channel_client_pipe_add_after(RedChannelClient *rcc,
4c08dd
                                        PipeItem *item, PipeItem *pos)
4c08dd
 {
4c08dd
-    spice_assert(rcc);
4c08dd
     spice_assert(pos);
4c08dd
-    spice_assert(item);
4c08dd
-
4c08dd
+    if (!validate_pipe_add(rcc, item)) {
4c08dd
+        return;
4c08dd
+    }
4c08dd
     rcc->pipe_size++;
4c08dd
     ring_add_after(&item->link, &pos->link);
4c08dd
 }
20333d
@@ -1548,14 +1562,18 @@ int red_channel_client_pipe_item_is_linked(RedChannelClient *rcc,
4c08dd
 void red_channel_client_pipe_add_tail_no_push(RedChannelClient *rcc,
4c08dd
                                               PipeItem *item)
4c08dd
 {
4c08dd
-    spice_assert(rcc);
4c08dd
+    if (!validate_pipe_add(rcc, item)) {
4c08dd
+        return;
4c08dd
+    }
4c08dd
     rcc->pipe_size++;
4c08dd
     ring_add_before(&item->link, &rcc->pipe);
4c08dd
 }
4c08dd
 
4c08dd
 void red_channel_client_pipe_add_tail(RedChannelClient *rcc, PipeItem *item)
4c08dd
 {
4c08dd
-    spice_assert(rcc);
4c08dd
+    if (!validate_pipe_add(rcc, item)) {
4c08dd
+        return;
4c08dd
+    }
4c08dd
     rcc->pipe_size++;
4c08dd
     ring_add_before(&item->link, &rcc->pipe);
4c08dd
     red_channel_client_push(rcc);