[Spice-devel] [PATCH spice-server] agent: fix mishandling of agent data received from the client after agent disconnection
Hans de Goede
hdegoede at redhat.com
Sun Dec 2 03:43:05 PST 2012
Hi,
Thanks for your work on this!
Fix looks good, ACK.
Regards,
Hans
On 11/30/2012 05:28 PM, Yonit Halperin wrote:
> The server can receive from the client agent data even when the agent
> is disconnected. This can happen if the client sends the agent data
> before it receives the AGENT_DISCONNECTED msg. We should receive and handle such msgs, instead
> of disconnecting the client.
> This bug can also lead to a server crash if the agent gets reconnected
> fast enough, and it receives an agent data msg from the client before MSGC_AGENT_START.
>
> upstream bz#55726
> rhbz#881980
> ---
> server/reds.c | 28 ++++++++++++++++++++++------
> 1 file changed, 22 insertions(+), 6 deletions(-)
>
> diff --git a/server/reds.c b/server/reds.c
> index b99d01f..3a8a28d 100644
> --- a/server/reds.c
> +++ b/server/reds.c
> @@ -474,7 +474,11 @@ static void reds_reset_vdp(void)
> /* Reset read filter to start with clean state when the agent reconnects */
> agent_msg_filter_init(&state->read_filter, agent_copypaste, TRUE);
> /* Throw away pending chunks from the current (if any) and future
> - messages written by the client */
> + * messages written by the client.
> + * TODO: client should clear its agent messages queue when the agent
> + * is disconnect. Currently, when and agent gets disconnected and reconnected,
> + * messeges that were directed to the previous instance of the agent continues
> + * to be sent from the client. This TODO will require server, protocol, and client changes */
> state->write_filter.result = AGENT_MSG_FILTER_DISCARD;
> state->write_filter.discard_all = TRUE;
> state->client_agent_started = FALSE;
> @@ -996,8 +1000,15 @@ uint8_t *reds_get_agent_data_buffer(MainChannelClient *mcc, size_t size)
> VDIPortState *dev_state = &reds->agent_state;
> RedClient *client;
>
> - if (!dev_state->base) {
> - return NULL;
> + if (!dev_state->client_agent_started) {
> + /*
> + * agent got disconnected, and possibly got reconnected, but we still can receive
> + * msgs that are addressed to the agent's old instance, in case they were
> + * sent by the client before it received the AGENT_DISCONNECTED msg.
> + * In such case, we will receive and discard the msgs (reds_reset_vdp takes care
> + * of setting state->write_filter.result = AGENT_MSG_FILTER_DISCARD).
> + */
> + return spice_malloc(size);
> }
>
> spice_assert(dev_state->recv_from_client_buf == NULL);
> @@ -1013,8 +1024,12 @@ void reds_release_agent_data_buffer(uint8_t *buf)
> {
> VDIPortState *dev_state = &reds->agent_state;
>
> - spice_assert(buf == dev_state->recv_from_client_buf->buf + sizeof(VDIChunkHeader));
> + if (!dev_state->recv_from_client_buf) {
> + free(buf);
> + return;
> + }
>
> + spice_assert(buf == dev_state->recv_from_client_buf->buf + sizeof(VDIChunkHeader));
> if (!dev_state->recv_from_client_buf_pushed) {
> spice_char_device_write_buffer_release(reds->agent_state.base,
> dev_state->recv_from_client_buf);
> @@ -1064,8 +1079,6 @@ void reds_on_main_agent_data(MainChannelClient *mcc, void *message, size_t size)
> VDIChunkHeader *header;
> int res;
>
> - spice_assert(message == reds->agent_state.recv_from_client_buf->buf + sizeof(VDIChunkHeader));
> -
> res = agent_msg_filter_process_data(&reds->agent_state.write_filter,
> message, size);
> switch (res) {
> @@ -1080,6 +1093,9 @@ void reds_on_main_agent_data(MainChannelClient *mcc, void *message, size_t size)
> reds_disconnect();
> return;
> }
> +
> + spice_assert(reds->agent_state.recv_from_client_buf);
> + spice_assert(message == reds->agent_state.recv_from_client_buf->buf + sizeof(VDIChunkHeader));
> // TODO - start tracking agent data per channel
> header = (VDIChunkHeader *)dev_state->recv_from_client_buf->buf;
> header->port = VDP_CLIENT_PORT;
>
More information about the Spice-devel
mailing list