Re: [RFC PATCH-for-7.2 3/5] hw/display/qxl: Pass requested buffer size to qxl_phys2virt()

2022-11-28 Thread Philippe Mathieu-Daudé

On 28/11/22 17:29, Philippe Mathieu-Daudé wrote:

On 28/11/22 17:18, Philippe Mathieu-Daudé wrote:

On 28/11/22 16:41, Philippe Mathieu-Daudé wrote:

On 28/11/22 16:08, Gerd Hoffmann wrote:



Also at least one code path (processing SPICE_CURSOR_TYPE_MONO in
qxl_cursor) goes access chunk.data[] without calling
qxl_unpack_chunks(), that needs additional verification too (or
switch it to call qxl_unpack_chunks, or just drop it because nobody
uses mono chrome cursors anyway).

Per commit 36ffc122dc ("qxl: support mono cursors with inverted colors")
"Monochrome cursors are still used by Windows guests" (i.e. Win2008R2)
:/


Hmm I guess I'm missing something in qxl_cursor() following the
SPICE_CURSOR_TYPE_MONO case.

- cursor_alloc() allocate QEMUCursor* c but doesn't set c->data,


Sorry long day, cursor_alloc() does allocate c->data:

typedef struct QEMUCursor {
int width, height;
int hot_x, hot_y;
int refcount;
uint32_tdata[];
} QEMUCursor;

QEMUCursor *cursor_alloc(int width, int height)
{
QEMUCursor *c;
size_t datasize = width * height * sizeof(uint32_t);

if (width > 512 || height > 512) {
return NULL;
}

c = g_malloc0(sizeof(QEMUCursor) + datasize);



- nothing seems to set c->data
- cursor_set_mono() is called and *(c->data) is assigned...

?






Re: [RFC PATCH-for-7.2 3/5] hw/display/qxl: Pass requested buffer size to qxl_phys2virt()

2022-11-28 Thread Philippe Mathieu-Daudé

On 28/11/22 17:18, Philippe Mathieu-Daudé wrote:

On 28/11/22 16:41, Philippe Mathieu-Daudé wrote:

On 28/11/22 16:08, Gerd Hoffmann wrote:



Also at least one code path (processing SPICE_CURSOR_TYPE_MONO in
qxl_cursor) goes access chunk.data[] without calling
qxl_unpack_chunks(), that needs additional verification too (or
switch it to call qxl_unpack_chunks, or just drop it because nobody
uses mono chrome cursors anyway).

Per commit 36ffc122dc ("qxl: support mono cursors with inverted colors")
"Monochrome cursors are still used by Windows guests" (i.e. Win2008R2)
:/


Hmm I guess I'm missing something in qxl_cursor() following the
SPICE_CURSOR_TYPE_MONO case.

- cursor_alloc() allocate QEMUCursor* c but doesn't set c->data,
- nothing seems to set c->data
- cursor_set_mono() is called and *(c->data) is assigned...

?




Re: [RFC PATCH-for-7.2 3/5] hw/display/qxl: Pass requested buffer size to qxl_phys2virt()

2022-11-28 Thread Philippe Mathieu-Daudé

On 28/11/22 16:41, Philippe Mathieu-Daudé wrote:

On 28/11/22 16:08, Gerd Hoffmann wrote:



Also at least one code path (processing SPICE_CURSOR_TYPE_MONO in
qxl_cursor) goes access chunk.data[] without calling
qxl_unpack_chunks(), that needs additional verification too (or
switch it to call qxl_unpack_chunks, or just drop it because nobody
uses mono chrome cursors anyway).

Per commit 36ffc122dc ("qxl: support mono cursors with inverted colors")
"Monochrome cursors are still used by Windows guests" (i.e. Win2008R2)
:/



Re: [RFC PATCH-for-7.2 3/5] hw/display/qxl: Pass requested buffer size to qxl_phys2virt()

2022-11-28 Thread Gerd Hoffmann
On Mon, Nov 28, 2022 at 04:41:14PM +0100, Philippe Mathieu-Daudé wrote:
> On 28/11/22 16:08, Gerd Hoffmann wrote:
> > > @@ -228,7 +230,7 @@ static void qxl_unpack_chunks(void *dest, size_t 
> > > size, PCIQXLDevice *qxl,
> > >   if (offset == size) {
> > >   return;
> > >   }
> > > -chunk = qxl_phys2virt(qxl, chunk->next_chunk, group_id);
> > > +chunk = qxl_phys2virt(qxl, chunk->next_chunk, group_id, bytes);
> > >   if (!chunk) {
> > >   return;
> > >   }
> > 
> > Naa, its not that simple.  You get a QXLDataChunk passed in which
> > typically is verified *excluding* dynamically-sized chunk->data.
> 
> OK so IIUC 1/ this line should be:
> 
>   chunk = qxl_phys2virt(qxl, chunk->next_chunk, group_id,
> sizeof(QXLDataChunk));

Depends on whenever you do (2) inside or outside the loop ;)

> but 2/ we should check chunk->data[chunk->data_size] is valid (within
> the MR) before calling the memcpy(), right?

Yes.

take care,
  Gerd




Re: [RFC PATCH-for-7.2 3/5] hw/display/qxl: Pass requested buffer size to qxl_phys2virt()

2022-11-28 Thread Philippe Mathieu-Daudé

On 28/11/22 16:08, Gerd Hoffmann wrote:

@@ -228,7 +230,7 @@ static void qxl_unpack_chunks(void *dest, size_t size, 
PCIQXLDevice *qxl,
  if (offset == size) {
  return;
  }
-chunk = qxl_phys2virt(qxl, chunk->next_chunk, group_id);
+chunk = qxl_phys2virt(qxl, chunk->next_chunk, group_id, bytes);
  if (!chunk) {
  return;
  }


Naa, its not that simple.  You get a QXLDataChunk passed in which
typically is verified *excluding* dynamically-sized chunk->data.


OK so IIUC 1/ this line should be:

  chunk = qxl_phys2virt(qxl, chunk->next_chunk, group_id,
sizeof(QXLDataChunk));

but 2/ we should check chunk->data[chunk->data_size] is valid (within
the MR) before calling the memcpy(), right?


Also at least one code path (processing SPICE_CURSOR_TYPE_MONO in
qxl_cursor) goes access chunk.data[] without calling
qxl_unpack_chunks(), that needs additional verification too (or
switch it to call qxl_unpack_chunks, or just drop it because nobody
uses mono chrome cursors anyway).


OK I'll look at that.

Thanks,

Phil.




Re: [RFC PATCH-for-7.2 3/5] hw/display/qxl: Pass requested buffer size to qxl_phys2virt()

2022-11-28 Thread Gerd Hoffmann
> @@ -228,7 +230,7 @@ static void qxl_unpack_chunks(void *dest, size_t size, 
> PCIQXLDevice *qxl,
>  if (offset == size) {
>  return;
>  }
> -chunk = qxl_phys2virt(qxl, chunk->next_chunk, group_id);
> +chunk = qxl_phys2virt(qxl, chunk->next_chunk, group_id, bytes);
>  if (!chunk) {
>  return;
>  }

Naa, its not that simple.  You get a QXLDataChunk passed in which
typically is verified *excluding* dynamically-sized chunk->data.

Also at least one code path (processing SPICE_CURSOR_TYPE_MONO in
qxl_cursor) goes access chunk.data[] without calling
qxl_unpack_chunks(), that needs additional verification too (or
switch it to call qxl_unpack_chunks, or just drop it because nobody
uses mono chrome cursors anyway).

take care,
  Gerd




Re: [RFC PATCH-for-7.2 3/5] hw/display/qxl: Pass requested buffer size to qxl_phys2virt()

2022-11-28 Thread Marc-André Lureau
Hi

On Mon, Nov 28, 2022 at 5:48 PM Philippe Mathieu-Daudé 
wrote:

> Currently qxl_phys2virt() doesn't check for buffer overrun.
> In order to do so in the next commit, pass the buffer size
> as argument.
>
> Signed-off-by: Philippe Mathieu-Daudé 
> ---
> RFC: Please double-check qxl_render_update_area_unlocked()
> ---
>  hw/display/qxl-logger.c | 11 ---
>  hw/display/qxl-render.c | 12 
>  hw/display/qxl.c| 14 +-
>  hw/display/qxl.h|  4 +++-
>  4 files changed, 28 insertions(+), 13 deletions(-)
>
> diff --git a/hw/display/qxl-logger.c b/hw/display/qxl-logger.c
> index 1bcf803db6..35c38f6252 100644
> --- a/hw/display/qxl-logger.c
> +++ b/hw/display/qxl-logger.c
> @@ -106,7 +106,7 @@ static int qxl_log_image(PCIQXLDevice *qxl,
> QXLPHYSICAL addr, int group_id)
>  QXLImage *image;
>  QXLImageDescriptor *desc;
>
> -image = qxl_phys2virt(qxl, addr, group_id);
> +image = qxl_phys2virt(qxl, addr, group_id, sizeof(QXLImage));
>  if (!image) {
>  return 1;
>  }
> @@ -214,7 +214,8 @@ int qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd
> *cmd, int group_id)
>  cmd->u.set.position.y,
>  cmd->u.set.visible ? "yes" : "no",
>  cmd->u.set.shape);
> -cursor = qxl_phys2virt(qxl, cmd->u.set.shape, group_id);
> +cursor = qxl_phys2virt(qxl, cmd->u.set.shape, group_id,
> +   sizeof(QXLCursor));
>  if (!cursor) {
>  return 1;
>  }
> @@ -236,6 +237,7 @@ int qxl_log_command(PCIQXLDevice *qxl, const char
> *ring, QXLCommandExt *ext)
>  {
>  bool compat = ext->flags & QXL_COMMAND_FLAG_COMPAT;
>  void *data;
> +size_t datasz;
>  int ret;
>
>  if (!qxl->cmdlog) {
> @@ -249,15 +251,18 @@ int qxl_log_command(PCIQXLDevice *qxl, const char
> *ring, QXLCommandExt *ext)
>
>  switch (ext->cmd.type) {
>  case QXL_CMD_DRAW:
> +datasz = compat ? sizeof(QXLCompatDrawable) : sizeof(QXLDrawable);
>  break;
>  case QXL_CMD_SURFACE:
> +datasz = sizeof(QXLSurfaceCmd);
>  break;
>  case QXL_CMD_CURSOR:
> +datasz = sizeof(QXLCursorCmd);
>  break;
>  default:
>  goto out;
>  }
> -data = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
> +data = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id, datasz);
>  if (!data) {
>  return 1;
>  }
> diff --git a/hw/display/qxl-render.c b/hw/display/qxl-render.c
> index ca217004bf..0a4bfa8aa6 100644
> --- a/hw/display/qxl-render.c
> +++ b/hw/display/qxl-render.c
> @@ -107,7 +107,9 @@ static void
> qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
>  qxl->guest_primary.resized = 0;
>  qxl->guest_primary.data = qxl_phys2virt(qxl,
>
>  qxl->guest_primary.surface.mem,
> -MEMSLOT_GROUP_GUEST);
> +MEMSLOT_GROUP_GUEST,
> +
> qxl->guest_primary.abs_stride
>
+* height);
>

Right, it looks like QXL device stride is in bytes.

Reviewed-by: Marc-André Lureau 


>  if (!qxl->guest_primary.data) {
>  goto end;
>  }
> @@ -228,7 +230,7 @@ static void qxl_unpack_chunks(void *dest, size_t size,
> PCIQXLDevice *qxl,
>  if (offset == size) {
>  return;
>  }
> -chunk = qxl_phys2virt(qxl, chunk->next_chunk, group_id);
> +chunk = qxl_phys2virt(qxl, chunk->next_chunk, group_id, bytes);
>  if (!chunk) {
>  return;
>  }
> @@ -295,7 +297,8 @@ fail:
>  /* called from spice server thread context only */
>  int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext)
>  {
> -QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
> +QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id,
> +  sizeof(QXLCursorCmd));
>  QXLCursor *cursor;
>  QEMUCursor *c;
>
> @@ -314,7 +317,8 @@ int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt
> *ext)
>  }
>  switch (cmd->type) {
>  case QXL_CURSOR_SET:
> -cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id);
> +cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id,
> +   sizeof(QXLCursor));
>  if (!cursor) {
>  return 1;
>  }
> diff --git a/hw/display/qxl.c b/hw/display/qxl.c
> index 5b10f697f1..231d733250 100644
> --- a/hw/display/qxl.c
> +++ b/hw/display/qxl.c
> @@ -274,7 +274,8 @@ static void
> qxl_spice_monitors_config_async(PCIQXLDevice *qxl, int replay)
>QXL_IO_MONITORS_CONFIG_ASYNC));
>  }
>
> -cfg = qxl_phys2virt(qxl, qxl->guest_monitors_config,
> MEMSLOT_GROUP_GUEST);
> +cfg = qxl_phys2virt(qxl, qxl->guest_monitors_config,
> MEMSLOT_GROUP_GUEST,
> +