[Spice-devel] [PATCH spice-server 2/4] spicevmc: Avoids DoS if client is not able to get data faster enough

Victor Toso victortoso at redhat.com
Tue Sep 24 11:24:32 UTC 2019


On Mon, Jun 17, 2019 at 04:40:09PM +0100, Frediano Ziglio wrote:
> This fix half (one direction) of
> https://gitlab.freedesktop.org/spice/spice/issues/29.
> Specifically if you have attempt to transfer a file to the client
> using WebDAV.
> Previously the queue to the client was unbound. If client was not
> getting data fast enough the server started queuing data.
> To easily test this you can use a tool to limit bandwidth and
> transfer a big file (I used a "dd if=/dev/zero bs=1M of=test") from
> the guest.
> 
> Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
> ---
>  server/spicevmc.c | 33 ++++++++++++++++++++++++++-------
>  1 file changed, 26 insertions(+), 7 deletions(-)
> 
> diff --git a/server/spicevmc.c b/server/spicevmc.c
> index 8c41573ae..02e90199c 100644
> --- a/server/spicevmc.c
> +++ b/server/spicevmc.c
> @@ -34,14 +34,14 @@
>  #include "reds.h"
>  #include "migration-protocol.h"
>  
> -/* todo: add flow control. i.e.,
> - * (a) limit the tokens available for the client
> - * (b) limit the tokens available for the server
> - */
>  /* 64K should be enough for all but the largest writes + 32 bytes hdr */
>  #define BUF_SIZE (64 * 1024 + 32)
>  #define COMPRESS_THRESHOLD 1000
>  
> +// limit of the queued data, at this limit we stop reading from device to
> +// avoid DoS
> +#define QUEUED_DATA_LIMIT (1024*1024)
> +

Looks fine,
Acked-by: Victor Toso <victortoso at redhat.com>

>  SPICE_DECLARE_TYPE(RedCharDeviceSpiceVmc, red_char_device_spicevmc, CHAR_DEVICE_SPICEVMC);
>  #define RED_TYPE_CHAR_DEVICE_SPICEVMC red_char_device_spicevmc_get_type()
>  
> @@ -83,6 +83,7 @@ struct RedCharDeviceSpiceVmcClass
>  static RedCharDevice *red_char_device_spicevmc_new(SpiceCharDeviceInstance *sin,
>                                                     RedsState *reds,
>                                                     RedVmcChannel *channel);
> +static void spicevmc_red_channel_queue_data(RedVmcChannel *channel, RedVmcPipeItem *item);
>  
>  G_DEFINE_TYPE(RedCharDeviceSpiceVmc, red_char_device_spicevmc, RED_TYPE_CHAR_DEVICE)
>  
> @@ -96,6 +97,7 @@ struct RedVmcChannel
>      RedVmcPipeItem *pipe_item;
>      RedCharDeviceWriteBuffer *recv_from_client_buf;
>      uint8_t port_opened;
> +    uint32_t queued_data;
>      RedStatCounter in_data;
>      RedStatCounter in_compressed;
>      RedStatCounter in_decompressed;
> @@ -337,7 +339,7 @@ static RedPipeItem *spicevmc_chardev_read_msg_from_dev(RedCharDevice *self,
>  
>      sif = spice_char_device_get_interface(sin);
>  
> -    if (!channel->rcc) {
> +    if (!channel->rcc || channel->queued_data >= QUEUED_DATA_LIMIT) {
>          return NULL;
>      }
>  
> @@ -360,14 +362,14 @@ static RedPipeItem *spicevmc_chardev_read_msg_from_dev(RedCharDevice *self,
>  
>          msg_item_compressed = try_compress_lz4(channel, n, msg_item);
>          if (msg_item_compressed != NULL) {
> -            red_channel_client_pipe_add_push(channel->rcc, &msg_item_compressed->base);
> +            spicevmc_red_channel_queue_data(channel, msg_item_compressed);
>              return NULL;
>          }
>  #endif
>          stat_inc_counter(channel->out_data, n);
>          msg_item->uncompressed_data_size = n;
>          msg_item->buf_used = n;
> -        red_channel_client_pipe_add_push(channel->rcc, &msg_item->base);
> +        spicevmc_red_channel_queue_data(channel, msg_item);
>          return NULL;
>      }
>      channel->pipe_item = msg_item;
> @@ -609,11 +611,19 @@ static void spicevmc_red_channel_release_msg_rcv_buf(RedChannelClient *rcc,
>      }
>  }
>  
> +static void
> +spicevmc_red_channel_queue_data(RedVmcChannel *channel, RedVmcPipeItem *item)
> +{
> +    channel->queued_data += item->buf_used;
> +    red_channel_client_pipe_add_push(channel->rcc, &item->base);
> +}
> +
>  static void spicevmc_red_channel_send_data(RedChannelClient *rcc,
>                                             SpiceMarshaller *m,
>                                             RedPipeItem *item)
>  {
>      RedVmcPipeItem *i = SPICE_UPCAST(RedVmcPipeItem, item);
> +    RedVmcChannel *channel = RED_VMC_CHANNEL(red_channel_client_get_channel(rcc));
>  
>      /* for compatibility send using not compressed data message */
>      if (i->type == SPICE_DATA_COMPRESSION_TYPE_NONE) {
> @@ -630,6 +640,14 @@ static void spicevmc_red_channel_send_data(RedChannelClient *rcc,
>      red_pipe_item_ref(item);
>      spice_marshaller_add_by_ref_full(m, i->buf, i->buf_used,
>                                       marshaller_unref_pipe_item, item);
> +
> +    // account for sent data and wake up device if was blocked
> +    uint32_t old_queued_data = channel->queued_data;
> +    channel->queued_data -= i->buf_used;
> +    if (channel->chardev &&
> +        old_queued_data >= QUEUED_DATA_LIMIT && channel->queued_data < QUEUED_DATA_LIMIT) {
> +        red_char_device_wakeup(channel->chardev);
> +    }
>  }
>  
>  static void spicevmc_red_channel_send_migrate_data(RedChannelClient *rcc,
> @@ -768,6 +786,7 @@ static void spicevmc_connect(RedChannel *channel, RedClient *client,
>          return;
>      }
>      vmc_channel->rcc = rcc;
> +    vmc_channel->queued_data = 0;
>      red_channel_client_ack_zero_messages_window(rcc);
>  
>      if (strcmp(sin->subtype, "port") == 0) {
> -- 
> 2.20.1
> 
> _______________________________________________
> Spice-devel mailing list
> Spice-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/spice-devel
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <https://lists.freedesktop.org/archives/spice-devel/attachments/20190924/19b05cad/attachment.sig>


More information about the Spice-devel mailing list