[Spice-devel] [PATCH spice 1/3] spice-server: Add the ability to filter agent messages

Alon Levy alevy at redhat.com
Fri Mar 25 06:52:40 PDT 2011


On Thu, Mar 24, 2011 at 05:39:46PM +0100, Hans de Goede wrote:
> ---
>  server/Makefile.am        |    2 +
>  server/agent-msg-filter.c |   85 +++++++++++++++++++++++++++++++++++++++++++++
>  server/agent-msg-filter.h |   45 ++++++++++++++++++++++++
>  server/reds.c             |   32 ++++++++++++++++-
>  4 files changed, 162 insertions(+), 2 deletions(-)
>  create mode 100644 server/agent-msg-filter.c
>  create mode 100644 server/agent-msg-filter.h
> 
> diff --git a/server/Makefile.am b/server/Makefile.am
> index 7ab8c3d..37ff183 100644
> --- a/server/Makefile.am
> +++ b/server/Makefile.am
> @@ -95,6 +95,8 @@ SMARTCARD_SRCS =
>  endif
>  
>  libspice_server_la_SOURCES =			\
> +	agent-msg-filter.c			\
> +	agent-msg-filter.h			\
>  	demarshallers.h				\
>  	glz_encoder.c				\
>  	glz_encoder_config.h			\
> diff --git a/server/agent-msg-filter.c b/server/agent-msg-filter.c
> new file mode 100644
> index 0000000..3867d11
> --- /dev/null
> +++ b/server/agent-msg-filter.c
> @@ -0,0 +1,85 @@
> +/*
> +   Copyright (C) 2011 Red Hat, Inc.
> +
> +   This library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   This library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with this library; if not, see <http://www.gnu.org/licenses/>.
> +
> +   Red Hat Authors:
> +        hdegoede at redhat.com
> +*/
> +
> +#include <string.h>
> +#include "red_common.h"
> +#include "agent-msg-filter.h"
> +
> +void agent_msg_filter_init(struct AgentMsgFilter *filter, int copy_paste)
> +{
> +    memset(filter, 0, sizeof(*filter));

You are explicitly relying on AGENT_MSG_FILTER_OK == 0, would be nice
to set filter->Result = AGENT_MSG_FILTER_OK explicitly.

> +    filter->copy_paste_enabled = copy_paste;
> +}
> +
> +int agent_msg_filter_process_data(struct AgentMsgFilter *filter,
> +                                  uint8_t *data, uint32_t len)
> +{
> +    struct VDAgentMessage msg_header;
> +
> +    if (len > VD_AGENT_MAX_DATA_SIZE) {
> +        red_printf("invalid agent message: too large");
> +        return AGENT_MSG_FILTER_PROTO_ERROR;
> +    }
> +
> +    /* Are we expecting more data from a previous message? */
> +    if (filter->msg_data_to_read) {
> +data_to_read:
> +        if (len > filter->msg_data_to_read) {
> +            red_printf("invalid agent message: data exceeds size from header");
> +            return AGENT_MSG_FILTER_PROTO_ERROR;
> +        }
> +        filter->msg_data_to_read -= len;
> +        return filter->result;
> +    }
> +
> +    if (len < sizeof(msg_header)) {

Is it impossible to get a partial write that is smaller then the size
of the header? This also applies for a read with multiple messages
ending with a partial header.

> +        red_printf("invalid agent message: incomplete header");
> +        return AGENT_MSG_FILTER_PROTO_ERROR;
> +    }
> +    memcpy(&msg_header, data, sizeof(msg_header));
> +    len -= sizeof(msg_header);
> +
> +    if (msg_header.protocol != VD_AGENT_PROTOCOL) {
> +        red_printf("invalid agent protocol: %u", msg_header.protocol);
> +        return AGENT_MSG_FILTER_PROTO_ERROR;
> +    }
> +
> +    switch (msg_header.type) {
> +    case VD_AGENT_CLIPBOARD:
> +    case VD_AGENT_CLIPBOARD_GRAB:
> +    case VD_AGENT_CLIPBOARD_REQUEST:
> +    case VD_AGENT_CLIPBOARD_RELEASE:
> +        if (filter->copy_paste_enabled) {
> +            filter->result = AGENT_MSG_FILTER_OK;
> +        } else {
> +            filter->result = AGENT_MSG_FILTER_DISCARD;
> +        }
> +        break;
> +    default:
> +        filter->result = AGENT_MSG_FILTER_OK;
> +    }
> +
> +    filter->msg_data_to_read = msg_header.size;
> +    if (filter->msg_data_to_read) {
> +        goto data_to_read;
> +    }
> +
> +    return filter->result;
> +}
> diff --git a/server/agent-msg-filter.h b/server/agent-msg-filter.h
> new file mode 100644
> index 0000000..99dbb8c
> --- /dev/null
> +++ b/server/agent-msg-filter.h
> @@ -0,0 +1,45 @@
> +/*
> +   Copyright (C) 2011 Red Hat, Inc.
> +
> +   This library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   This library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with this library; if not, see <http://www.gnu.org/licenses/>.
> +
> +   Red Hat Authors:
> +        hdegoede at redhat.com
> +*/
> +
> +#ifndef _H_AGENT_MSG_FILTER
> +#define _H_AGENT_MSG_FILTER
> +
> +#include <spice/vd_agent.h>
> +
> +/* Possible return values for agent_msg_filter_process_data */
> +enum {
> +    AGENT_MSG_FILTER_OK,
> +    AGENT_MSG_FILTER_DISCARD,
> +    AGENT_MSG_FILTER_PROTO_ERROR,
> +    AGENT_MSG_FILTER_END
> +};
> +
> +typedef struct AgentMsgFilter {
> +    struct VDAgentMessage msg_header;
> +    int msg_data_to_read;
> +    int result;
> +    int copy_paste_enabled;
> +} AgentMsgFilter;
> +
> +void agent_msg_filter_init(struct AgentMsgFilter *filter, int copy_paste);
> +int agent_msg_filter_process_data(struct AgentMsgFilter *filter,
> +                                  uint8_t *data, uint32_t len);
> +
> +#endif
> diff --git a/server/reds.c b/server/reds.c
> index c1873ef..4663a85 100644
> --- a/server/reds.c
> +++ b/server/reds.c
> @@ -49,6 +49,7 @@
>  #include "reds.h"
>  #include <spice/protocol.h>
>  #include <spice/vd_agent.h>
> +#include "agent-msg-filter.h"
>  
>  #include "inputs_channel.h"
>  #include "main_channel.h"
> @@ -158,6 +159,7 @@ typedef struct VDIPortState {
>      Ring external_bufs;
>      Ring internal_bufs;
>      Ring write_queue;
> +    AgentMsgFilter write_filter;
>  
>      Ring read_bufs;
>      uint32_t read_state;
> @@ -165,6 +167,7 @@ typedef struct VDIPortState {
>      uint8_t *recive_pos;
>      uint32_t recive_len;
>      VDIReadBuf *current_read_buf;
> +    AgentMsgFilter read_filter;
>  
>      VDIChunkHeader vdi_chunk_header;
>  
> @@ -806,9 +809,24 @@ void vdi_read_buf_release(uint8_t *data, void *opaque)
>  static void dispatch_vdi_port_data(int port, VDIReadBuf *buf)
>  {
>      VDIPortState *state = &reds->agent_state;
> +    int res;
>  
>      switch (port) {
>      case VDP_CLIENT_PORT: {
> +        res = agent_msg_filter_process_data(&state->read_filter,
> +                                            buf->data, buf->len);
> +        switch (res) {
> +        case AGENT_MSG_FILTER_OK:
> +            break;
> +        case AGENT_MSG_FILTER_DISCARD:
> +            ring_add(&state->read_bufs, &buf->link);
> +            return;
> +        case AGENT_MSG_FILTER_PROTO_ERROR:
> +            ring_add(&state->read_bufs, &buf->link);
> +            reds_agent_remove();
> +            return;
> +        }
> +
>          if (reds->agent_state.connected) {
>              main_channel_push_agent_data(reds->main_channel, buf->data, buf->len,
>                                           vdi_read_buf_release, buf);
> @@ -994,6 +1012,7 @@ void reds_on_main_agent_data(void *message, size_t size)
>  {
>      RingItem *ring_item;
>      VDAgentExtBuf *buf;
> +    int res;
>  
>      if (!reds->agent_state.num_client_tokens) {
>          red_printf("token violation");
> @@ -1013,8 +1032,15 @@ void reds_on_main_agent_data(void *message, size_t size)
>          return;
>      }
>  
> -    if (size > SPICE_AGENT_MAX_DATA_SIZE) {
> -        red_printf("invalid agent message");
> +    res = agent_msg_filter_process_data(&reds->agent_state.write_filter,
> +                                        message, size);
> +    switch (res) {
> +    case AGENT_MSG_FILTER_OK:
> +        break;
> +    case AGENT_MSG_FILTER_DISCARD:
> +        add_token();
> +        return;
> +    case AGENT_MSG_FILTER_PROTO_ERROR:
>          reds_disconnect();
>          return;
>      }
> @@ -3384,6 +3410,8 @@ static void init_vd_agent_resources()
>      ring_init(&state->internal_bufs);
>      ring_init(&state->write_queue);
>      ring_init(&state->read_bufs);
> +    agent_msg_filter_init(&state->write_filter, TRUE);
> +    agent_msg_filter_init(&state->read_filter, TRUE);
>  
>      state->read_state = VDI_PORT_READ_STATE_READ_HADER;
>      state->recive_pos = (uint8_t *)&state->vdi_chunk_header;
> -- 
> 1.7.3.2
> 
> _______________________________________________
> Spice-devel mailing list
> Spice-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/spice-devel


More information about the Spice-devel mailing list