diff --git a/.spice.metadata b/.spice.metadata new file mode 100644 index 0000000..d2692cd --- /dev/null +++ b/.spice.metadata @@ -0,0 +1 @@ +5825cfcf8a786697e45a43aaf372f23b5c441336 SOURCES/spice-0.12.4.tar.bz2 diff --git a/README.md b/README.md deleted file mode 100644 index 0e7897f..0000000 --- a/README.md +++ /dev/null @@ -1,5 +0,0 @@ -The master branch has no content - -Look at the c7 branch if you are working with CentOS-7, or the c4/c5/c6 branch for CentOS-4, 5 or 6 - -If you find this file in a distro specific branch, it means that no content has been checked in yet diff --git a/SOURCES/0001-red_channel-prevent-adding-and-pushing-pipe-items-af.patch b/SOURCES/0001-red_channel-prevent-adding-and-pushing-pipe-items-af.patch new file mode 100644 index 0000000..aab0d8e --- /dev/null +++ b/SOURCES/0001-red_channel-prevent-adding-and-pushing-pipe-items-af.patch @@ -0,0 +1,96 @@ +From 47e722b85ccd0b6876ca189a3d6f6f05289fe3c3 Mon Sep 17 00:00:00 2001 +From: Yonit Halperin +Date: Wed, 24 Jul 2013 14:54:23 -0400 +Subject: [PATCH 1/8] red_channel: prevent adding and pushing pipe items after + a channel_client has diconnected + +Fixes: leaks of pipe items & "red_client_destroy: assertion `rcc->send_data.size == 0'" + +red_channel_disconnect clears the pipe. It is called only once. After, +it was called, not items should be added to the pipe. + +An example of when this assert can occur: +on_new_cursor_channel (red_worker.c), pushes 2 pipe items. +When it pushes the first pipe item, if the client has disconnected, +it can hit a socket error, and then, red_channel_client_disconnect is called. +The second call to adding a pipe item, will add the item to +the pipe. red_channel_client_pipe_add_type also calls +red_channel_client_push, which will update the send_data.size. +Then, the push will also hit a socket error, but red_channel_client_disconnect +won't clear the pending pipe item again, since it was already called. +When red_client_destory is called, we hit assertion `rcc->send_data.size +== 0'. +Note that if a pipe item is added to the pipe after +red_channel_client_disconnect was called, but without pushing it, +we should hit "spice_assert(rcc->pipe_size == 0)". +--- + server/red_channel.c | 30 ++++++++++++++++++++++++------ + 1 file changed, 24 insertions(+), 6 deletions(-) + +diff --git a/server/red_channel.c b/server/red_channel.c +index 33af388..0d74413 100644 +--- a/server/red_channel.c ++++ b/server/red_channel.c +@@ -1527,9 +1527,23 @@ void red_channel_pipe_item_init(RedChannel *channel, PipeItem *item, int type) + item->type = type; + } + +-void red_channel_client_pipe_add(RedChannelClient *rcc, PipeItem *item) ++static inline int validate_pipe_add(RedChannelClient *rcc, PipeItem *item) + { + spice_assert(rcc && item); ++ if (SPICE_UNLIKELY(!red_channel_client_is_connected(rcc))) { ++ spice_debug("rcc is disconnected %p", rcc); ++ red_channel_client_release_item(rcc, item, FALSE); ++ return FALSE; ++ } ++ return TRUE; ++} ++ ++void red_channel_client_pipe_add(RedChannelClient *rcc, PipeItem *item) ++{ ++ ++ if (!validate_pipe_add(rcc, item)) { ++ return; ++ } + rcc->pipe_size++; + ring_add(&rcc->pipe, &item->link); + } +@@ -1543,10 +1557,10 @@ void red_channel_client_pipe_add_push(RedChannelClient *rcc, PipeItem *item) + void red_channel_client_pipe_add_after(RedChannelClient *rcc, + PipeItem *item, PipeItem *pos) + { +- spice_assert(rcc); + spice_assert(pos); +- spice_assert(item); +- ++ if (!validate_pipe_add(rcc, item)) { ++ return; ++ } + rcc->pipe_size++; + ring_add_after(&item->link, &pos->link); + } +@@ -1560,14 +1574,18 @@ int red_channel_client_pipe_item_is_linked(RedChannelClient *rcc, + void red_channel_client_pipe_add_tail_no_push(RedChannelClient *rcc, + PipeItem *item) + { +- spice_assert(rcc); ++ if (!validate_pipe_add(rcc, item)) { ++ return; ++ } + rcc->pipe_size++; + ring_add_before(&item->link, &rcc->pipe); + } + + void red_channel_client_pipe_add_tail(RedChannelClient *rcc, PipeItem *item) + { +- spice_assert(rcc); ++ if (!validate_pipe_add(rcc, item)) { ++ return; ++ } + rcc->pipe_size++; + ring_add_before(&item->link, &rcc->pipe); + red_channel_client_push(rcc); +-- +1.8.3.1 + diff --git a/SOURCES/0002-red_channel-add-ref-count-to-RedClient.patch b/SOURCES/0002-red_channel-add-ref-count-to-RedClient.patch new file mode 100644 index 0000000..10e24b9 --- /dev/null +++ b/SOURCES/0002-red_channel-add-ref-count-to-RedClient.patch @@ -0,0 +1,96 @@ +From aab45618cc12799d5f7351ef8832ae73b33057c7 Mon Sep 17 00:00:00 2001 +From: Yonit Halperin +Date: Fri, 26 Jul 2013 13:45:16 -0400 +Subject: [PATCH 2/8] red_channel: add ref count to RedClient + +--- + server/red_channel.c | 23 ++++++++++++++++++++--- + server/red_channel.h | 17 +++++++++++++++-- + 2 files changed, 35 insertions(+), 5 deletions(-) + +diff --git a/server/red_channel.c b/server/red_channel.c +index 0d74413..9168b8a 100644 +--- a/server/red_channel.c ++++ b/server/red_channel.c +@@ -1932,10 +1932,29 @@ RedClient *red_client_new(int migrated) + pthread_mutex_init(&client->lock, NULL); + client->thread_id = pthread_self(); + client->during_target_migrate = migrated; ++ client->refs = 1; + + return client; + } + ++RedClient *red_client_ref(RedClient *client) ++{ ++ spice_assert(client); ++ client->refs++; ++ return client; ++} ++ ++RedClient *red_client_unref(RedClient *client) ++{ ++ if (!--client->refs) { ++ spice_debug("release client=%p", client); ++ pthread_mutex_destroy(&client->lock); ++ free(client); ++ return NULL; ++ } ++ return client; ++} ++ + /* client mutex should be locked before this call */ + static void red_channel_client_set_migration_seamless(RedChannelClient *rcc) + { +@@ -2012,9 +2031,7 @@ void red_client_destroy(RedClient *client) + spice_assert(rcc->send_data.size == 0); + red_channel_client_destroy(rcc); + } +- +- pthread_mutex_destroy(&client->lock); +- free(client); ++ red_client_unref(client); + } + + /* client->lock should be locked */ +diff --git a/server/red_channel.h b/server/red_channel.h +index ba299b6..0dd73ea 100644 +--- a/server/red_channel.h ++++ b/server/red_channel.h +@@ -561,10 +561,25 @@ struct RedClient { + is called */ + int seamless_migrate; + int num_migrated_channels; /* for seamless - number of channels that wait for migrate data*/ ++ int refs; + }; + + RedClient *red_client_new(int migrated); + ++/* ++ * disconnects all the client's channels (should be called from the client's thread) ++ */ ++void red_client_destroy(RedClient *client); ++ ++RedClient *red_client_ref(RedClient *client); ++ ++/* ++ * releases the client resources when refs == 0. ++ * We assume the red_client_derstroy was called before ++ * we reached refs==0 ++ */ ++RedClient *red_client_unref(RedClient *client); ++ + MainChannelClient *red_client_get_main(RedClient *client); + // main should be set once before all the other channels are created + void red_client_set_main(RedClient *client, MainChannelClient *mcc); +@@ -580,7 +595,5 @@ void red_client_semi_seamless_migrate_complete(RedClient *client); /* dst side * + int red_client_during_migrate_at_target(RedClient *client); + + void red_client_migrate(RedClient *client); +-// disconnects all the client's channels (should be called from the client's thread) +-void red_client_destroy(RedClient *client); + + #endif +-- +1.8.3.1 + diff --git a/SOURCES/0003-main_dispatcher-add-ref-count-protection-to-RedClien.patch b/SOURCES/0003-main_dispatcher-add-ref-count-protection-to-RedClien.patch new file mode 100644 index 0000000..fab6d5c --- /dev/null +++ b/SOURCES/0003-main_dispatcher-add-ref-count-protection-to-RedClien.patch @@ -0,0 +1,51 @@ +From 06ba03b7b32a2f0c7f78c82d8f399242526a0b45 Mon Sep 17 00:00:00 2001 +From: Yonit Halperin +Date: Fri, 26 Jul 2013 13:49:24 -0400 +Subject: [PATCH 3/8] main_dispatcher: add ref count protection to RedClient + instances + +--- + server/main_dispatcher.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/server/main_dispatcher.c b/server/main_dispatcher.c +index e7a451a..bf160dd 100644 +--- a/server/main_dispatcher.c ++++ b/server/main_dispatcher.c +@@ -97,6 +97,7 @@ static void main_dispatcher_handle_migrate_complete(void *opaque, + MainDispatcherMigrateSeamlessDstCompleteMessage *mig_complete = payload; + + reds_on_client_seamless_migrate_complete(mig_complete->client); ++ red_client_unref(mig_complete->client); + } + + static void main_dispatcher_handle_mm_time_latency(void *opaque, +@@ -104,6 +105,7 @@ static void main_dispatcher_handle_mm_time_latency(void *opaque, + { + MainDispatcherMmTimeLatencyMessage *msg = payload; + reds_set_client_mm_time_latency(msg->client, msg->latency); ++ red_client_unref(msg->client); + } + + void main_dispatcher_seamless_migrate_dst_complete(RedClient *client) +@@ -115,7 +117,7 @@ void main_dispatcher_seamless_migrate_dst_complete(RedClient *client) + return; + } + +- msg.client = client; ++ msg.client = red_client_ref(client); + dispatcher_send_message(&main_dispatcher.base, MAIN_DISPATCHER_MIGRATE_SEAMLESS_DST_COMPLETE, + &msg); + } +@@ -129,7 +131,7 @@ void main_dispatcher_set_mm_time_latency(RedClient *client, uint32_t latency) + return; + } + +- msg.client = client; ++ msg.client = red_client_ref(client); + msg.latency = latency; + dispatcher_send_message(&main_dispatcher.base, MAIN_DISPATCHER_SET_MM_TIME_LATENCY, + &msg); +-- +1.8.3.1 + diff --git a/SOURCES/0004-decouple-disconnection-of-the-main-channel-from-clie.patch b/SOURCES/0004-decouple-disconnection-of-the-main-channel-from-clie.patch new file mode 100644 index 0000000..85d70ec --- /dev/null +++ b/SOURCES/0004-decouple-disconnection-of-the-main-channel-from-clie.patch @@ -0,0 +1,238 @@ +From 8490f83e1f51ac8dbcac3c68c97827e0acb9ec4e Mon Sep 17 00:00:00 2001 +From: Yonit Halperin +Date: Thu, 25 Jul 2013 14:19:21 -0400 +Subject: [PATCH 4/8] decouple disconnection of the main channel from client + destruction + +Fixes rhbz#918169 + +Some channels make direct calls to reds/main_channel routines. If +these routines try to read/write to the socket, and they get socket +error, main_channel_client_on_disconnect is called, and triggers +red_client_destroy. In order to prevent accessing expired references +to RedClient, RedChannelClient, or other objects (inside the original call, after +red_client_destroy has been called) I made the call to +red_client_destroy asynchronous with respect to main_channel_client_on_disconnect. +I added MAIN_DISPATCHER_CLIENT_DISCONNECT to main_dispatcher. +main_channel_client_on_disconnect pushes this msg to the dispatcher, +instead of calling directly to reds_client_disconnect. + +The patch uses RedClient ref-count in order to handle a case where +reds_client_disconnect is called directly (e.g., when a new client connects while +another one is connected), while there is already CLIENT_DISCONNECT msg +pending in the main_dispatcher. + +Examples: +(1) snd_worker.c + + snd_disconnect_channel() + channel->cleanup() //snd_playback_cleanup + reds_enable_mm_timer() + . + . + main_channel_push_multi_media_time()...socket_error + . + . + red_client_destory() + . + . + snd_disconnect_channel() + channel->cleanup() + celt051_encoder_destroy() + celt051_encoder_destory() // double release + +Note that this bug could have been solved by changing the order of +calls: e.g., channel->stream = NULL before calling cleanup, and +some other changes + reference counting. However, I found other +places in the code with similar problems, and I looked for a general +solution, at least till we redesign red_channel to handle reference +counting more consistently. + +(2) inputs_channel.c + + inputs_connect() + main_channel_client_push_notify()...socket_error + . + . + red_client_destory() + . + . + red_channel_client_create() // refers to client which is already destroyed + +(3) reds.c + + reds_handle_main_link() + main_channel_push_init() ...socket error + . + . + red_client_destory() + . + . + main_channel_client_start_net_test(mcc) // refers to mcc which is already destroyed + + This can explain the assert in rhbz#964136, comment #1 (but not the hang that occurred before). +--- + server/main_channel.c | 9 +++++---- + server/main_dispatcher.c | 37 +++++++++++++++++++++++++++++++++++++ + server/main_dispatcher.h | 7 +++++++ + server/reds.c | 1 + + server/reds.h | 2 ++ + 5 files changed, 52 insertions(+), 4 deletions(-) + +diff --git a/server/main_channel.c b/server/main_channel.c +index 233e633..fe032a6 100644 +--- a/server/main_channel.c ++++ b/server/main_channel.c +@@ -46,6 +46,7 @@ + #include "red_common.h" + #include "reds.h" + #include "migration_protocol.h" ++#include "main_dispatcher.h" + + #define ZERO_BUF_SIZE 4096 + +@@ -175,13 +176,13 @@ int main_channel_is_connected(MainChannel *main_chan) + return red_channel_is_connected(&main_chan->base); + } + +-// when disconnection occurs, let reds shutdown all channels. This will trigger the +-// real disconnection of main channel ++/* ++ * When the main channel is disconnected, disconnect the entire client. ++ */ + static void main_channel_client_on_disconnect(RedChannelClient *rcc) + { + spice_printerr("rcc=%p", rcc); +- reds_client_disconnect(rcc->client); +-// red_channel_client_disconnect(rcc); ++ main_dispatcher_client_disconnect(rcc->client); + } + + RedClient *main_channel_get_client_by_link_id(MainChannel *main_chan, uint32_t connection_id) +diff --git a/server/main_dispatcher.c b/server/main_dispatcher.c +index bf160dd..dbe1037 100644 +--- a/server/main_dispatcher.c ++++ b/server/main_dispatcher.c +@@ -41,6 +41,7 @@ enum { + MAIN_DISPATCHER_CHANNEL_EVENT = 0, + MAIN_DISPATCHER_MIGRATE_SEAMLESS_DST_COMPLETE, + MAIN_DISPATCHER_SET_MM_TIME_LATENCY, ++ MAIN_DISPATCHER_CLIENT_DISCONNECT, + + MAIN_DISPATCHER_NUM_MESSAGES + }; +@@ -59,6 +60,10 @@ typedef struct MainDispatcherMmTimeLatencyMessage { + uint32_t latency; + } MainDispatcherMmTimeLatencyMessage; + ++typedef struct MainDispatcherClientDisconnectMessage { ++ RedClient *client; ++} MainDispatcherClientDisconnectMessage; ++ + /* channel_event - calls core->channel_event, must be done in main thread */ + static void main_dispatcher_self_handle_channel_event( + int event, +@@ -108,6 +113,16 @@ static void main_dispatcher_handle_mm_time_latency(void *opaque, + red_client_unref(msg->client); + } + ++static void main_dispatcher_handle_client_disconnect(void *opaque, ++ void *payload) ++{ ++ MainDispatcherClientDisconnectMessage *msg = payload; ++ ++ spice_debug("client=%p", msg->client); ++ reds_client_disconnect(msg->client); ++ red_client_unref(msg->client); ++} ++ + void main_dispatcher_seamless_migrate_dst_complete(RedClient *client) + { + MainDispatcherMigrateSeamlessDstCompleteMessage msg; +@@ -137,6 +152,20 @@ void main_dispatcher_set_mm_time_latency(RedClient *client, uint32_t latency) + &msg); + } + ++void main_dispatcher_client_disconnect(RedClient *client) ++{ ++ MainDispatcherClientDisconnectMessage msg; ++ ++ if (!client->disconnecting) { ++ spice_debug("client %p", client); ++ msg.client = red_client_ref(client); ++ dispatcher_send_message(&main_dispatcher.base, MAIN_DISPATCHER_CLIENT_DISCONNECT, ++ &msg); ++ } else { ++ spice_debug("client %p already during disconnection", client); ++ } ++} ++ + static void dispatcher_handle_read(int fd, int event, void *opaque) + { + Dispatcher *dispatcher = opaque; +@@ -144,6 +173,11 @@ static void dispatcher_handle_read(int fd, int event, void *opaque) + dispatcher_handle_recv_read(dispatcher); + } + ++/* ++ * FIXME: ++ * Reds routines shouldn't be exposed. Instead reds.c should register the callbacks, ++ * and the corresponding operations should be made only via main_dispatcher. ++ */ + void main_dispatcher_init(SpiceCoreInterface *core) + { + memset(&main_dispatcher, 0, sizeof(main_dispatcher)); +@@ -160,4 +194,7 @@ void main_dispatcher_init(SpiceCoreInterface *core) + dispatcher_register_handler(&main_dispatcher.base, MAIN_DISPATCHER_SET_MM_TIME_LATENCY, + main_dispatcher_handle_mm_time_latency, + sizeof(MainDispatcherMmTimeLatencyMessage), 0 /* no ack */); ++ dispatcher_register_handler(&main_dispatcher.base, MAIN_DISPATCHER_CLIENT_DISCONNECT, ++ main_dispatcher_handle_client_disconnect, ++ sizeof(MainDispatcherClientDisconnectMessage), 0 /* no ack */); + } +diff --git a/server/main_dispatcher.h b/server/main_dispatcher.h +index 0c79ca8..522c7f9 100644 +--- a/server/main_dispatcher.h ++++ b/server/main_dispatcher.h +@@ -7,6 +7,13 @@ + void main_dispatcher_channel_event(int event, SpiceChannelEventInfo *info); + void main_dispatcher_seamless_migrate_dst_complete(RedClient *client); + void main_dispatcher_set_mm_time_latency(RedClient *client, uint32_t latency); ++/* ++ * Disconnecting the client is always executed asynchronously, ++ * in order to protect from expired references in the routines ++ * that triggered the client destruction. ++ */ ++void main_dispatcher_client_disconnect(RedClient *client); ++ + void main_dispatcher_init(SpiceCoreInterface *core); + + #endif //MAIN_DISPATCHER_H +diff --git a/server/reds.c b/server/reds.c +index 30d0652..c66ddc4 100644 +--- a/server/reds.c ++++ b/server/reds.c +@@ -537,6 +537,7 @@ void reds_client_disconnect(RedClient *client) + } + + if (!client || client->disconnecting) { ++ spice_debug("client %p already during disconnection", client); + return; + } + +diff --git a/server/reds.h b/server/reds.h +index c5c557d..1c5ae84 100644 +--- a/server/reds.h ++++ b/server/reds.h +@@ -136,6 +136,8 @@ void reds_handle_agent_mouse_event(const VDAgentMouseState *mouse_state); // use + extern struct SpiceCoreInterface *core; + + // Temporary measures to make splitting reds.c to inputs_channel.c easier ++ ++/* should be called only from main_dispatcher */ + void reds_client_disconnect(RedClient *client); + + // Temporary (?) for splitting main channel +-- +1.8.3.1 + diff --git a/SOURCES/0005-reds-s-red_client_disconnect-red_channel_client_shut.patch b/SOURCES/0005-reds-s-red_client_disconnect-red_channel_client_shut.patch new file mode 100644 index 0000000..035f462 --- /dev/null +++ b/SOURCES/0005-reds-s-red_client_disconnect-red_channel_client_shut.patch @@ -0,0 +1,56 @@ +From 46c2ce8f1af0170a2c6a335cc743a3ddff2d96d0 Mon Sep 17 00:00:00 2001 +From: Yonit Halperin +Date: Thu, 25 Jul 2013 14:25:24 -0400 +Subject: [PATCH 5/8] reds: s/red_client_disconnect/red_channel_client_shutdown + inside callbacks + +When we want to disconnect the main channel from a callback, it is +safer to use red_channel_client_shutdown, instead of directly +destroying the client. It is also more consistent with how other +channels treat errors. +red_channel_client_shutdown will trigger socket error in the main channel. +Then, main_channel_client_on_disconnect will be called, +and eventually, main_dispatcher_client_disconnect. + +I didn't replace calls to reds_disconnect/reds_client_disconnect in +places where those calls were safe && that might need immediate client +disconnection. +--- + server/reds.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/server/reds.c b/server/reds.c +index c66ddc4..ae87c90 100644 +--- a/server/reds.c ++++ b/server/reds.c +@@ -879,7 +879,8 @@ static void vdi_port_on_free_self_token(void *opaque) + + static void vdi_port_remove_client(RedClient *client, void *opaque) + { +- reds_client_disconnect(client); ++ red_channel_client_shutdown(main_channel_client_get_base( ++ red_client_get_main(client))); + } + + /****************************************************************************/ +@@ -1009,7 +1010,7 @@ void reds_on_main_agent_start(MainChannelClient *mcc, uint32_t num_tokens) + + if (!client_added) { + spice_warning("failed to add client to agent"); +- reds_client_disconnect(rcc->client); ++ red_channel_client_shutdown(rcc); + return; + } + } else { +@@ -1126,7 +1127,7 @@ void reds_on_main_agent_data(MainChannelClient *mcc, void *message, size_t size) + reds_on_main_agent_monitors_config(mcc, message, size); + return; + case AGENT_MSG_FILTER_PROTO_ERROR: +- reds_disconnect(); ++ red_channel_client_shutdown(main_channel_client_get_base(mcc)); + return; + } + +-- +1.8.3.1 + diff --git a/SOURCES/0006-snd_worker-fix-memory-leak-of-PlaybackChannel.patch b/SOURCES/0006-snd_worker-fix-memory-leak-of-PlaybackChannel.patch new file mode 100644 index 0000000..fc1ee51 --- /dev/null +++ b/SOURCES/0006-snd_worker-fix-memory-leak-of-PlaybackChannel.patch @@ -0,0 +1,42 @@ +From 134b7f310de5120b233670d18641d32204f31318 Mon Sep 17 00:00:00 2001 +From: Yonit Halperin +Date: Thu, 25 Jul 2013 14:49:33 -0400 +Subject: [PATCH 6/8] snd_worker: fix memory leak of PlaybackChannel + +When the sequence of calls bellow occurs, the PlaybackChannel +is not released (snd_channel_put is not called for the +samples that refer to the channel). + + spice_server_playback_get_buffer + snd_channel_disconnect + spice_server_playback_put_samples +--- + server/snd_worker.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/server/snd_worker.c b/server/snd_worker.c +index d6ec47a..849f002 100644 +--- a/server/snd_worker.c ++++ b/server/snd_worker.c +@@ -1097,14 +1097,13 @@ SPICE_GNUC_VISIBLE void spice_server_playback_put_samples(SpicePlaybackInstance + PlaybackChannel *playback_channel; + AudioFrame *frame; + +- if (!sin->st->worker.connection) { +- return; +- } +- + frame = SPICE_CONTAINEROF(samples, AudioFrame, samples); + playback_channel = frame->channel; +- if (!snd_channel_put(&playback_channel->base) || !playback_channel->base.worker->connection) { ++ spice_assert(playback_channel); ++ if (!snd_channel_put(&playback_channel->base) || ++ sin->st->worker.connection != &playback_channel->base) { + /* lost last reference, channel has been destroyed previously */ ++ spice_info("audio samples belong to a disconnected channel"); + return; + } + spice_assert(playback_channel->base.active); +-- +1.8.3.1 + diff --git a/SOURCES/0007-snd_worker-snd_disconnect_channel-don-t-call-snd_cha.patch b/SOURCES/0007-snd_worker-snd_disconnect_channel-don-t-call-snd_cha.patch new file mode 100644 index 0000000..fd461be --- /dev/null +++ b/SOURCES/0007-snd_worker-snd_disconnect_channel-don-t-call-snd_cha.patch @@ -0,0 +1,62 @@ +From 02f44c137df99ed2e89699e49b64c13673b0cd06 Mon Sep 17 00:00:00 2001 +From: Yonit Halperin +Date: Thu, 25 Jul 2013 15:07:43 -0400 +Subject: [PATCH 7/8] snd_worker/snd_disconnect_channel: don't call + snd_channel_put if the channel has already been disconnected + +The snd channels has one reference as long as their socket is active. +The playback channel has an additional reference for each frame that is +currently filled by the sound device. +Once the channel is disconnected (the socket has been freed and the +first reference is released) snd_disconnect_channel shouldn't release +a reference again. +--- + server/snd_worker.c | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/server/snd_worker.c b/server/snd_worker.c +index 849f002..3827416 100644 +--- a/server/snd_worker.c ++++ b/server/snd_worker.c +@@ -212,21 +212,20 @@ static void snd_disconnect_channel(SndChannel *channel) + { + SndWorker *worker; + +- if (!channel) { ++ if (!channel || !channel->stream) { + spice_debug("not connected"); + return; + } + spice_debug("%p", channel); + worker = channel->worker; +- if (channel->stream) { +- channel->cleanup(channel); +- red_channel_client_disconnect(worker->connection->channel_client); +- core->watch_remove(channel->stream->watch); +- channel->stream->watch = NULL; +- reds_stream_free(channel->stream); +- channel->stream = NULL; +- spice_marshaller_destroy(channel->send_data.marshaller); +- } ++ channel->cleanup(channel); ++ red_channel_client_disconnect(worker->connection->channel_client); ++ worker->connection->channel_client = NULL; ++ core->watch_remove(channel->stream->watch); ++ channel->stream->watch = NULL; ++ reds_stream_free(channel->stream); ++ channel->stream = NULL; ++ spice_marshaller_destroy(channel->send_data.marshaller); + snd_channel_put(channel); + worker->connection = NULL; + } +@@ -897,6 +896,7 @@ static SndChannel *__new_channel(SndWorker *worker, int size, uint32_t channel_i + int tos; + MainChannelClient *mcc = red_client_get_main(client); + ++ spice_assert(stream); + if ((flags = fcntl(stream->socket, F_GETFL)) == -1) { + spice_printerr("accept failed, %s", strerror(errno)); + goto error1; +-- +1.8.3.1 + diff --git a/SOURCES/0008-log-improve-debug-information-related-to-client-disc.patch b/SOURCES/0008-log-improve-debug-information-related-to-client-disc.patch new file mode 100644 index 0000000..77a04ba --- /dev/null +++ b/SOURCES/0008-log-improve-debug-information-related-to-client-disc.patch @@ -0,0 +1,99 @@ +From c2e46b926e0ee4226f0f93942e7fa2c5b409f73d Mon Sep 17 00:00:00 2001 +From: Yonit Halperin +Date: Fri, 26 Jul 2013 12:15:00 -0400 +Subject: [PATCH 8/8] log: improve debug information related to client + disconnection + +--- + server/red_channel.c | 9 ++++++--- + server/snd_worker.c | 7 ++++--- + 2 files changed, 10 insertions(+), 6 deletions(-) + +diff --git a/server/red_channel.c b/server/red_channel.c +index 9168b8a..d565634 100644 +--- a/server/red_channel.c ++++ b/server/red_channel.c +@@ -1112,6 +1112,7 @@ static void red_channel_client_ref(RedChannelClient *rcc) + static void red_channel_client_unref(RedChannelClient *rcc) + { + if (!--rcc->refs) { ++ spice_debug("destroy rcc=%p", rcc); + if (rcc->send_data.main.marshaller) { + spice_marshaller_destroy(rcc->send_data.main.marshaller); + } +@@ -1708,6 +1709,8 @@ static void red_channel_client_disconnect_dummy(RedChannelClient *rcc) + { + spice_assert(rcc->dummy); + if (ring_item_is_linked(&rcc->channel_link)) { ++ spice_printerr("rcc=%p (channel=%p type=%d id=%d)", rcc, rcc->channel, ++ rcc->channel->type, rcc->channel->id); + red_channel_remove_client(rcc); + } + rcc->dummy_connected = FALSE; +@@ -1715,8 +1718,6 @@ static void red_channel_client_disconnect_dummy(RedChannelClient *rcc) + + void red_channel_client_disconnect(RedChannelClient *rcc) + { +- spice_printerr("%p (channel %p type %d id %d)", rcc, rcc->channel, +- rcc->channel->type, rcc->channel->id); + if (rcc->dummy) { + red_channel_client_disconnect_dummy(rcc); + return; +@@ -1724,6 +1725,8 @@ void red_channel_client_disconnect(RedChannelClient *rcc) + if (!red_channel_client_is_connected(rcc)) { + return; + } ++ spice_printerr("rcc=%p (channel=%p type=%d id=%d)", rcc, rcc->channel, ++ rcc->channel->type, rcc->channel->id); + red_channel_client_pipe_clear(rcc); + if (rcc->stream->watch) { + rcc->channel->core->watch_remove(rcc->stream->watch); +@@ -2007,7 +2010,7 @@ void red_client_destroy(RedClient *client) + RingItem *link, *next; + RedChannelClient *rcc; + +- spice_printerr("destroy client with #channels %d", client->channels_num); ++ spice_printerr("destroy client %p with #channels=%d", client, client->channels_num); + if (!pthread_equal(pthread_self(), client->thread_id)) { + spice_warning("client->thread_id (0x%lx) != pthread_self (0x%lx)." + "If one of the threads is != io-thread && != vcpu-thread," +diff --git a/server/snd_worker.c b/server/snd_worker.c +index 3827416..ebddfcd 100644 +--- a/server/snd_worker.c ++++ b/server/snd_worker.c +@@ -201,8 +201,8 @@ static SndChannel *snd_channel_get(SndChannel *channel) + static SndChannel *snd_channel_put(SndChannel *channel) + { + if (!--channel->refs) { ++ spice_printerr("SndChannel=%p freed", channel); + free(channel); +- spice_printerr("sound channel freed"); + return NULL; + } + return channel; +@@ -216,7 +216,8 @@ static void snd_disconnect_channel(SndChannel *channel) + spice_debug("not connected"); + return; + } +- spice_debug("%p", channel); ++ spice_debug("SndChannel=%p rcc=%p type=%d", ++ channel, channel->channel_client, channel->channel_client->channel->type); + worker = channel->worker; + channel->cleanup(channel); + red_channel_client_disconnect(worker->connection->channel_client); +@@ -976,11 +977,11 @@ static void snd_disconnect_channel_client(RedChannelClient *rcc) + { + SndWorker *worker; + +- spice_debug(NULL); + spice_assert(rcc->channel); + spice_assert(rcc->channel->data); + worker = (SndWorker *)rcc->channel->data; + ++ spice_debug("channel-type=%d", rcc->channel->type); + if (worker->connection) { + spice_assert(worker->connection->channel_client == rcc); + snd_disconnect_channel(worker->connection); +-- +1.8.3.1 + diff --git a/SOURCES/0009-red_worker-decrease-the-timeout-when-flushing-comman.patch b/SOURCES/0009-red_worker-decrease-the-timeout-when-flushing-comman.patch new file mode 100644 index 0000000..a37b32b --- /dev/null +++ b/SOURCES/0009-red_worker-decrease-the-timeout-when-flushing-comman.patch @@ -0,0 +1,66 @@ +From 6ced0f698507de02a67cfcd25b7ab07e8c423fad Mon Sep 17 00:00:00 2001 +Message-Id: <6ced0f698507de02a67cfcd25b7ab07e8c423fad.1377595745.git.uril@redhat.com> +From: Yonit Halperin +Date: Mon, 5 Aug 2013 12:10:15 -0400 +Subject: [PATCH] red_worker: decrease the timeout when flushing commands and waiting for the client. + +150 seconds is way too long period for holding the guest driver and +waiting for a response for the client. This timeout was 15 seconds, but +when off-screen surfaces ware introduced it was arbitrarily multiplied by +10. +Other existing related bugs emphasize why it is important to decrease +the timeout: +(1) 994211 - the qxl driver waits for an async-io reponse for 60 seconds + and after that, it switches to sync-io mode. Not only that the + driver might use invalid data (since it didn't wait for the query to + complete), falling back to sync-io mode introduces other errors. +(2) 994175 - spice server sometimes doesn't recognize that the client + has disconnected. +(3) There might be cache inconsistency between the client and the server, +and then the display channel waits indefinitely for a cache item (e.g., bug +977998) + +This patch changes the timeout to 30 seconds. I tested it under wifi +emulating 2.5Mbps network, +together with playing video on the guest and changing resolutions in a loop. The timeout didn't expired +during my tests. + +This bug is related to rhbz#964136 (but from rhbz#964136 info it is still not +clear why the client wasn't responsive). +--- + server/red_worker.c | 6 +++--- + 1 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/server/red_worker.c b/server/red_worker.c +index b45208b..9896696 100644 +--- a/server/red_worker.c ++++ b/server/red_worker.c +@@ -103,7 +103,7 @@ + #define CHANNEL_PUSH_TIMEOUT 30000000000ULL //nano + #define CHANNEL_PUSH_SLEEP_DURATION 10000 //micro + +-#define DISPLAY_CLIENT_TIMEOUT 15000000000ULL //nano ++#define DISPLAY_CLIENT_TIMEOUT 30000000000ULL //nano + #define DISPLAY_CLIENT_MIGRATE_DATA_TIMEOUT 10000000000ULL //nano, 10 sec + #define DISPLAY_CLIENT_RETRY_INTERVAL 10000 //micro + +@@ -9716,7 +9716,7 @@ static inline void flush_display_commands(RedWorker *worker) + if (ring_is_empty) { + break; + } +- end_time = red_now() + DISPLAY_CLIENT_TIMEOUT * 10; ++ end_time = red_now() + DISPLAY_CLIENT_TIMEOUT; + int sleep_count = 0; + for (;;) { + red_channel_push(&worker->display_channel->common.base); +@@ -9760,7 +9760,7 @@ static inline void flush_cursor_commands(RedWorker *worker) + if (ring_is_empty) { + break; + } +- end_time = red_now() + DISPLAY_CLIENT_TIMEOUT * 10; ++ end_time = red_now() + DISPLAY_CLIENT_TIMEOUT; + int sleep_count = 0; + for (;;) { + red_channel_push(&worker->cursor_channel->common.base); +-- +1.7.1 + diff --git a/SOURCES/0010-Fix-buffer-overflow-when-decrypting-client-SPICE-tic.patch b/SOURCES/0010-Fix-buffer-overflow-when-decrypting-client-SPICE-tic.patch new file mode 100644 index 0000000..320296a --- /dev/null +++ b/SOURCES/0010-Fix-buffer-overflow-when-decrypting-client-SPICE-tic.patch @@ -0,0 +1,108 @@ +From 3554c19d1c65c2bc4ae8cadb7296256c03215257 Mon Sep 17 00:00:00 2001 +From: Christophe Fergeau +Date: Fri, 23 Aug 2013 11:29:44 +0200 +Subject: [PATCH] Fix buffer overflow when decrypting client SPICE ticket + +reds_handle_ticket uses a fixed size 'password' buffer for the decrypted +password whose size is SPICE_MAX_PASSWORD_LENGTH. However, +RSA_private_decrypt which we call for the decryption expects the +destination buffer to be at least RSA_size(link->tiTicketing.rsa) +bytes long. On my spice-server build, SPICE_MAX_PASSWORD_LENGTH +is 60 while RSA_size() is 128, so we end up overflowing 'password' +when using long passwords (this was reproduced using the string: +'fullscreen=1proxy=#enter proxy here; e.g spice_proxy = http://[proxy]:[port]' +as a password). + +When the overflow occurs, QEMU dies with: +*** stack smashing detected ***: qemu-system-x86_64 terminated + +This commit ensures we use a corectly sized 'password' buffer, +and that it's correctly nul-terminated so that we can use strcmp +instead of strncmp. To keep using strncmp, we'd need to figure out +which one of 'password' and 'taTicket.password' is the smaller buffer, +and use that size. + +This fixes rhbz#999839 +--- + server/reds.c | 44 ++++++++++++++++++++++++++++++++------------ + 1 file changed, 32 insertions(+), 12 deletions(-) + +diff --git a/server/reds.c b/server/reds.c +index 0f81a32..7b7f262 100644 +--- a/server/reds.c ++++ b/server/reds.c +@@ -1932,39 +1932,59 @@ static void reds_handle_link(RedLinkInfo *link) + static void reds_handle_ticket(void *opaque) + { + RedLinkInfo *link = (RedLinkInfo *)opaque; +- char password[SPICE_MAX_PASSWORD_LENGTH]; ++ char *password; + time_t ltime; ++ int password_size; + + //todo: use monotonic time + time(<ime); +- RSA_private_decrypt(link->tiTicketing.rsa_size, +- link->tiTicketing.encrypted_ticket.encrypted_data, +- (unsigned char *)password, link->tiTicketing.rsa, RSA_PKCS1_OAEP_PADDING); ++ if (RSA_size(link->tiTicketing.rsa) < SPICE_MAX_PASSWORD_LENGTH) { ++ spice_warning("RSA modulus size is smaller than SPICE_MAX_PASSWORD_LENGTH (%d < %d), " ++ "SPICE ticket sent from client may be truncated", ++ RSA_size(link->tiTicketing.rsa), SPICE_MAX_PASSWORD_LENGTH); ++ } ++ ++ password = g_malloc0(RSA_size(link->tiTicketing.rsa) + 1); ++ password_size = RSA_private_decrypt(link->tiTicketing.rsa_size, ++ link->tiTicketing.encrypted_ticket.encrypted_data, ++ (unsigned char *)password, ++ link->tiTicketing.rsa, ++ RSA_PKCS1_OAEP_PADDING); ++ if (password_size == -1) { ++ spice_warning("failed to decrypt RSA encrypted password: %s", ++ ERR_error_string(ERR_get_error(), NULL)); ++ goto error; ++ } ++ password[password_size] = '\0'; + + if (ticketing_enabled && !link->skip_auth) { + int expired = taTicket.expiration_time < ltime; + + if (strlen(taTicket.password) == 0) { +- reds_send_link_result(link, SPICE_LINK_ERR_PERMISSION_DENIED); + spice_warning("Ticketing is enabled, but no password is set. " +- "please set a ticket first"); +- reds_link_free(link); +- return; ++ "please set a ticket first"); ++ goto error; + } + +- if (expired || strncmp(password, taTicket.password, SPICE_MAX_PASSWORD_LENGTH) != 0) { ++ if (expired || strcmp(password, taTicket.password) != 0) { + if (expired) { + spice_warning("Ticket has expired"); + } else { + spice_warning("Invalid password"); + } +- reds_send_link_result(link, SPICE_LINK_ERR_PERMISSION_DENIED); +- reds_link_free(link); +- return; ++ goto error; + } + } + + reds_handle_link(link); ++ goto end; ++ ++error: ++ reds_send_link_result(link, SPICE_LINK_ERR_PERMISSION_DENIED); ++ reds_link_free(link); ++ ++end: ++ g_free(password); + } + + static inline void async_read_clear_handlers(AsyncRead *obj) +-- +1.8.3.1 + diff --git a/SPECS/spice.spec b/SPECS/spice.spec new file mode 100644 index 0000000..7706f02 --- /dev/null +++ b/SPECS/spice.spec @@ -0,0 +1,280 @@ +Name: spice +Version: 0.12.4 +Release: 3%{?dist} +Summary: Implements the SPICE protocol +Group: User Interface/Desktops +License: LGPLv2+ +URL: http://www.spice-space.org/ +Source0: http://www.spice-space.org/download/releases/%{name}-%{version}.tar.bz2 +Patch1: 0001-red_channel-prevent-adding-and-pushing-pipe-items-af.patch +Patch2: 0002-red_channel-add-ref-count-to-RedClient.patch +Patch3: 0003-main_dispatcher-add-ref-count-protection-to-RedClien.patch +Patch4: 0004-decouple-disconnection-of-the-main-channel-from-clie.patch +Patch5: 0005-reds-s-red_client_disconnect-red_channel_client_shut.patch +Patch6: 0006-snd_worker-fix-memory-leak-of-PlaybackChannel.patch +Patch7: 0007-snd_worker-snd_disconnect_channel-don-t-call-snd_cha.patch +Patch8: 0008-log-improve-debug-information-related-to-client-disc.patch +Patch9: 0009-red_worker-decrease-the-timeout-when-flushing-comman.patch +Patch10: 0010-Fix-buffer-overflow-when-decrypting-client-SPICE-tic.patch + +# https://bugzilla.redhat.com/show_bug.cgi?id=613529 +%if 0%{?rhel} +ExclusiveArch: x86_64 +%else +ExclusiveArch: i686 x86_64 armv6l armv7l armv7hl +%endif + +BuildRequires: pkgconfig +BuildRequires: glib2-devel >= 2.22 +# BuildRequires: spice-protocol >= 0.12.3 -- not needed since spice-0.11.3 +BuildRequires: celt051-devel +BuildRequires: pixman-devel alsa-lib-devel openssl-devel libjpeg-turbo-devel +BuildRequires: libcacard-devel cyrus-sasl-devel +BuildRequires: pyparsing + +%description +The Simple Protocol for Independent Computing Environments (SPICE) is +a remote display system built for virtual environments which allows +you to view a computing 'desktop' environment not only on the machine +where it is running, but from anywhere on the Internet and from a wide +variety of machine architectures. + + +%package server +Summary: Implements the server side of the SPICE protocol +Group: System Environment/Libraries +Obsoletes: spice-client < %{version}-%{release} + +%description server +The Simple Protocol for Independent Computing Environments (SPICE) is +a remote display system built for virtual environments which allows +you to view a computing 'desktop' environment not only on the machine +where it is running, but from anywhere on the Internet and from a wide +variety of machine architectures. + +This package contains the run-time libraries for any application that wishes +to be a SPICE server. + + +%package server-devel +Summary: Header files, libraries and development documentation for spice-server +Group: Development/Libraries +Requires: %{name}-server%{?_isa} = %{version}-%{release} +Requires: pkgconfig +Requires: spice-protocol >= 0.12.3 + +%description server-devel +This package contains the header files, static libraries and development +documentation for spice-server. If you like to develop programs +using spice-server, you will need to install spice-server-devel. + + +%prep +%setup -q +%patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 +%patch6 -p1 +%patch7 -p1 +%patch8 -p1 +%patch9 -p1 +%patch10 -p1 + + +%build +%define configure_client --disable-client +%configure --enable-smartcard %{configure_client} +make %{?_smp_mflags} WARN_CFLAGS='' V=1 + + +%install +make DESTDIR=%{buildroot} install +rm -f %{buildroot}%{_libdir}/libspice-server.a +rm -f %{buildroot}%{_libdir}/libspice-server.la +mkdir -p %{buildroot}%{_libexecdir} + + +%post server -p /sbin/ldconfig +%postun server -p /sbin/ldconfig + + +%files server +%doc COPYING README NEWS +%{_libdir}/libspice-server.so.1* + +%files server-devel +%{_includedir}/spice-server +%{_libdir}/libspice-server.so +%{_libdir}/pkgconfig/spice-server.pc + + +%changelog +* Tue Oct 15 2013 Christophe Fergeau 0.12.4-3 +- Fix spice-server crash when client sends a password which is too long + Resolves: CVE-2013-4282 + +* Fri Sep 13 2013 Christophe Fergeau 0.12.4-2 +- Add upstream patch fixing rhbz#995041 + +* Fri Aug 2 2013 Hans de Goede - 0.12.4-1 +- Add patches from upstream git to fix sound-channel-free crash (rhbz#986407) +- Add Obsoletes for dropped spice-client sub-package + +* Tue Jul 22 2013 Yonit Halperin 0.12.4-1 +- New upstream release 0.12.4 +- Require libjpeg-turbo-devel instead of libjpeg-devel +- Remove "BuildRequires: spice-protocol" from spice-server +- Add "Requires: spice-protocol" to spice-server-devel. + +* Thu May 23 2013 Christophe Fergeau 0.12.3-2 +- Stop building spicec, it's obsolete and superseded by remote-viewer + (part of virt-viewer) + +* Tue May 21 2013 Christophe Fergeau 0.12.3-1 +- New upstream release 0.12.3 +- Drop all patches (they were all upstreamed) + +* Mon Apr 15 2013 Hans de Goede - 0.12.2-4 +- Add fix from upstream for a crash when the guest uses RGBA (rhbz#952242) + +* Thu Mar 07 2013 Adam Jackson 0.12.2-4 +- Rebuild for new libsasl2 soname in F19 + +* Mon Jan 21 2013 Hans de Goede - 0.12.2-3 +- Add a number of misc. bug-fixes from upstream + +* Fri Dec 21 2012 Adam Tkac - 0.12.2-2 +- rebuild against new libjpeg + +* Thu Dec 20 2012 Hans de Goede - 0.12.2-1 +- New upstream release 0.12.2 + +* Fri Sep 28 2012 Hans de Goede - 0.12.0-1 +- New upstream release 0.12.0 +- Some minor spec file cleanups +- Enable building on arm + +* Thu Sep 6 2012 Soren Sandmann - 0.11.3-1 +- BuildRequire pyparsing + +* Thu Sep 6 2012 Soren Sandmann - 0.11.3-1 +- Add capability patches +- Add capability patches to the included copy of spice-protocol + + Please see the comment above Patch6 and Patch7 + regarding this situation. + +* Thu Sep 6 2012 Soren Sandmann - 0.11.3-1 +- Update to 0.11.3 and drop upstreamed patches +- BuildRequire spice-protocol 0.12.1 + +* Sat Jul 21 2012 Fedora Release Engineering - 0.10.1-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Mon May 14 2012 Alon Levy +- Fix mjpeg memory leak and bad behavior. +- Add usbredir to list of channels for security purposes. (#819484) + +* Sun May 13 2012 Alon Levy +- Add double free fix. (#808936) + +%changelog +* Tue Apr 24 2012 Alon Levy +- Add 32 bit fixes from git master. (#815717) + +* Tue Feb 28 2012 Fedora Release Engineering - 0.10.1-2 +- Rebuilt for c++ ABI breakage + +* Mon Jan 23 2012 Hans de Goede - 0.10.1-1 +- New upstream release 0.10.1 + +* Sat Jan 14 2012 Fedora Release Engineering - 0.10.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Thu Nov 10 2011 Alon Levy - 0.10.0-1 +- New upstream release 0.10.0 +- support spice-server.i686 + +* Wed Sep 28 2011 Marc-André Lureau - 0.9.1-2 +- Provides spice-xpi-client alternative in spice-client + +* Thu Aug 25 2011 Hans de Goede - 0.9.1-1 +- New upstream release 0.9.1 + +* Mon Jul 25 2011 Marc-André Lureau - 0.9.0-1 +- New upstream release 0.9.0 + +* Wed Apr 20 2011 Hans de Goede - 0.8.1-1 +- New upstream release 0.8.1 + +* Fri Mar 11 2011 Hans de Goede - 0.8.0-2 +- Fix being unable to send ctrl+alt+key when release mouse is bound to + ctrl+alt (which can happen when used from RHEV-M) + +* Tue Mar 1 2011 Hans de Goede - 0.8.0-1 +- New upstream release 0.8.0 + +* Fri Feb 11 2011 Hans de Goede - 0.7.3-1 +- New upstream release 0.7.3 + +* Wed Feb 09 2011 Fedora Release Engineering - 0.7.2-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Wed Jan 19 2011 Hans de Goede - 0.7.2-1 +- New upstream release 0.7.2 + +* Fri Dec 17 2010 Hans de Goede - 0.7.1-1 +- New upstream release 0.7.1 +- Drop all patches (all upstreamed) +- Enable smartcard (CAC) support + +* Wed Nov 17 2010 Hans de Goede - 0.6.3-4 +- Fix the info layer not showing when used through the XPI +- Do not let the connection gui flash by when a hostname has been specified + on the cmdline +- Fix spice client locking up when dealing with XIM input (#654265) +- Fix modifier keys getting stuck (#655048) +- Fix spice client crashing when dealing with XIM ibus input (#655836) +- Fix spice client only showing a white screen in full screen mode + +* Sat Nov 6 2010 Hans de Goede - 0.6.3-3 +- Log to ~/.spicec/cegui.log rather then to CEGUI.log in the cwd, this + fixes spicec from aborting when run in a non writable dir (#650253) + +* Fri Nov 5 2010 Hans de Goede - 0.6.3-2 +- Various bugfixes from upstream git: + - Make spicec work together with the Firefox XPI for RHEV-M + - Make sure the spicec window gets properly raised when first shown + +* Mon Oct 18 2010 Hans de Goede - 0.6.3-1 +- Update to 0.6.3 +- Enable GUI + +* Thu Sep 30 2010 Gerd Hoffmann - 0.6.1-1 +- Update to 0.6.1. + +* Tue Aug 31 2010 Alexander Larsson - 0.6.0-1 +- Update to 0.6.0 (stable release) + +* Tue Jul 20 2010 Alexander Larsson - 0.5.3-1 +- Update to 0.5.3 + +* Tue Jul 13 2010 Gerd Hoffmann - 0.5.2-4 +- Quote %% in changelog to avoid macro expansion. + +* Mon Jul 12 2010 Gerd Hoffmann - 0.5.2-3 +- %%configure handles CFLAGS automatically, no need to fiddle + with %%{optflags} manually. + +* Mon Jul 12 2010 Gerd Hoffmann - 0.5.2-2 +- Fix license: LGPL. +- Cleanup specfile, drop bits not needed any more with + recent rpm versions (F13+). +- Use optflags as-is. +- + +* Fri Jul 9 2010 Gerd Hoffmann - 0.5.2-1 +- initial package. +