[Spice-devel] [PATCH] Avoid race conditions reading monitor configs from guest

Christophe Fergeau cfergeau at redhat.com
Tue Sep 8 05:27:42 PDT 2015


ACK.

On Tue, Sep 08, 2015 at 11:11:41AM +0100, Frediano Ziglio wrote:
> For security reasons do not assume guest do not change structures it
> pass to Qemu.
> Guest could change count field while Qemu is copying QXLMonitorsConfig
> structure leading to heap corruption.
> This patch avoid it reading count only once.
> 
> This patch solves CVE-2015-3247.
> 
> Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
> ---
>  server/red_worker.c | 44 +++++++++++++++++++++++++++++++-------------
>  1 file changed, 31 insertions(+), 13 deletions(-)
> 
> diff --git a/server/red_worker.c b/server/red_worker.c
> index 2f2d5a9..e2feb23 100644
> --- a/server/red_worker.c
> +++ b/server/red_worker.c
> @@ -11222,19 +11222,18 @@ static inline void red_monitors_config_item_add(DisplayChannelClient *dcc)
>  
>  static void worker_update_monitors_config(RedWorker *worker,
>                                            QXLMonitorsConfig *dev_monitors_config,
> -                                          unsigned int max_monitors)
> +                                          uint16_t count, uint16_t max_allowed)
>  {
>      int heads_size;
>      MonitorsConfig *monitors_config;
>      int i;
> -    unsigned int count = MIN(dev_monitors_config->count, max_monitors);
>  
>      monitors_config_decref(worker->monitors_config);
>  
>      spice_debug("monitors config %d(%d)",
> -                dev_monitors_config->count,
> -                dev_monitors_config->max_allowed);
> -    for (i = 0; i < dev_monitors_config->count; i++) {
> +                count,
> +                max_allowed);
> +    for (i = 0; i < count; i++) {
>          spice_debug("+%d+%d %dx%d",
>                      dev_monitors_config->heads[i].x,
>                      dev_monitors_config->heads[i].y,
> @@ -11247,7 +11246,7 @@ static void worker_update_monitors_config(RedWorker *worker,
>      monitors_config->refs = 1;
>      monitors_config->worker = worker;
>      monitors_config->count = count;
> -    monitors_config->max_allowed = MIN(dev_monitors_config->max_allowed, max_monitors);
> +    monitors_config->max_allowed = max_allowed;
>      memcpy(monitors_config->heads, dev_monitors_config->heads, heads_size);
>  }
>  
> @@ -11636,33 +11635,52 @@ void handle_dev_display_migrate(void *opaque, void *payload)
>      red_migrate_display(worker, rcc);
>  }
>  
> +static inline uint32_t qxl_monitors_config_size(uint32_t heads)
> +{
> +    return sizeof(QXLMonitorsConfig) + sizeof(QXLHead) * heads;
> +}
> +
>  static void handle_dev_monitors_config_async(void *opaque, void *payload)
>  {
>      RedWorkerMessageMonitorsConfigAsync *msg = payload;
>      RedWorker *worker = opaque;
> -    int min_size = sizeof(QXLMonitorsConfig) + sizeof(QXLHead);
>      int error;
> +    uint16_t count, max_allowed;
>      QXLMonitorsConfig *dev_monitors_config =
>          (QXLMonitorsConfig*)get_virt(&worker->mem_slots, msg->monitors_config,
> -                                     min_size, msg->group_id, &error);
> +                                     qxl_monitors_config_size(1),
> +                                     msg->group_id, &error);
>  
>      if (error) {
>          /* TODO: raise guest bug (requires added QXL interface) */
>          return;
>      }
>      worker->driver_cap_monitors_config = 1;
> -    if (dev_monitors_config->count == 0) {
> +    count = dev_monitors_config->count;
> +    max_allowed = dev_monitors_config->max_allowed;
> +    if (count == 0) {
>          spice_warning("ignoring an empty monitors config message from driver");
>          return;
>      }
> -    if (dev_monitors_config->count > dev_monitors_config->max_allowed) {
> +    if (count > max_allowed) {
>          spice_warning("ignoring malformed monitors_config from driver, "
>                        "count > max_allowed %d > %d",
> -                      dev_monitors_config->count,
> -                      dev_monitors_config->max_allowed);
> +                      count,
> +                      max_allowed);
> +        return;
> +    }
> +    /* get pointer again to check virtual size */
> +    dev_monitors_config =
> +        (QXLMonitorsConfig*)get_virt(&worker->mem_slots, msg->monitors_config,
> +                                     qxl_monitors_config_size(count),
> +                                     msg->group_id, &error);
> +    if (error) {
> +        /* TODO: raise guest bug (requires added QXL interface) */
>          return;
>      }
> -    worker_update_monitors_config(worker, dev_monitors_config, msg->max_monitors);
> +    worker_update_monitors_config(worker, dev_monitors_config,
> +                                  MIN(count, msg->max_monitors),
> +                                  MIN(max_allowed, msg->max_monitors));
>      red_worker_push_monitors_config(worker);
>  }
>  
> -- 
> 2.4.3
> 
> _______________________________________________
> Spice-devel mailing list
> Spice-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/spice-devel
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.freedesktop.org/archives/spice-devel/attachments/20150908/0d93c3f9/attachment.sig>


More information about the Spice-devel mailing list