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