diff mbox series

ui/cursor: fix integer overflow in cursor_alloc (CVE-2022-4206)

Message ID 20220405103258.105701-1-mcascell@redhat.com (mailing list archive)
State New, archived
Headers show
Series ui/cursor: fix integer overflow in cursor_alloc (CVE-2022-4206) | expand

Commit Message

Mauro Matteo Cascella April 5, 2022, 10:32 a.m. UTC
Prevent potential integer overflow by limiting 'width' and 'height' to
512x512. Also change 'datasize' type to size_t. Refer to security
advisory https://starlabs.sg/advisories/22-4206/ for more information.

Fixes: CVE-2022-4206
Signed-off-by: Mauro Matteo Cascella <mcascell@redhat.com>
---
 hw/display/qxl-render.c |  7 +++++++
 ui/cursor.c             | 12 +++++++++++-
 2 files changed, 18 insertions(+), 1 deletion(-)

Comments

Marc-André Lureau April 5, 2022, 10:55 a.m. UTC | #1
Hi

On Tue, Apr 5, 2022 at 2:43 PM Mauro Matteo Cascella <mcascell@redhat.com>
wrote:

> Prevent potential integer overflow by limiting 'width' and 'height' to
> 512x512. Also change 'datasize' type to size_t. Refer to security
> advisory https://starlabs.sg/advisories/22-4206/ for more information.
>
> Fixes: CVE-2022-4206
> Signed-off-by: Mauro Matteo Cascella <mcascell@redhat.com>
> ---
>  hw/display/qxl-render.c |  7 +++++++
>  ui/cursor.c             | 12 +++++++++++-
>  2 files changed, 18 insertions(+), 1 deletion(-)
>
> diff --git a/hw/display/qxl-render.c b/hw/display/qxl-render.c
> index d28849b121..dc3c4edd05 100644
> --- a/hw/display/qxl-render.c
> +++ b/hw/display/qxl-render.c
> @@ -247,6 +247,13 @@ static QEMUCursor *qxl_cursor(PCIQXLDevice *qxl,
> QXLCursor *cursor,
>      size_t size;
>
>      c = cursor_alloc(cursor->header.width, cursor->header.height);
> +
> +    if (!c) {
> +        qxl_set_guest_bug(qxl, "%s: cursor %ux%u alloc error", __func__,
> +                cursor->header.width, cursor->header.height);
> +        goto fail;
> +    }
> +
>      c->hot_x = cursor->header.hot_spot_x;
>      c->hot_y = cursor->header.hot_spot_y;
>      switch (cursor->header.type) {
> diff --git a/ui/cursor.c b/ui/cursor.c
> index 1d62ddd4d0..7cfb08a030 100644
> --- a/ui/cursor.c
> +++ b/ui/cursor.c
> @@ -46,6 +46,13 @@ static QEMUCursor *cursor_parse_xpm(const char *xpm[])
>
>      /* parse pixel data */
>      c = cursor_alloc(width, height);
> +
> +    if (!c) {
> +        fprintf(stderr, "%s: cursor %ux%u alloc error\n",
> +                __func__, width, height);
> +        return NULL;
> +    }
>

I think you could simply abort() in this function. It is used with static
data (ui/cursor*.xpm)

+
>      for (pixel = 0, y = 0; y < height; y++, line++) {
>          for (x = 0; x < height; x++, pixel++) {
>              idx = xpm[line][x];
> @@ -91,7 +98,10 @@ QEMUCursor *cursor_builtin_left_ptr(void)
>  QEMUCursor *cursor_alloc(int width, int height)
>  {
>      QEMUCursor *c;
> -    int datasize = width * height * sizeof(uint32_t);
> +    size_t datasize = width * height * sizeof(uint32_t);
> +
> +    if (width > 512 || height > 512)
> +        return NULL;
>
>      c = g_malloc0(sizeof(QEMUCursor) + datasize);
>      c->width  = width;
> --
> 2.35.1
>
>
>
lgtm otherwise
Gerd Hoffmann April 5, 2022, 11:10 a.m. UTC | #2
> > +++ b/ui/cursor.c
> > @@ -46,6 +46,13 @@ static QEMUCursor *cursor_parse_xpm(const char *xpm[])
> >
> >      /* parse pixel data */
> >      c = cursor_alloc(width, height);
> > +
> > +    if (!c) {
> > +        fprintf(stderr, "%s: cursor %ux%u alloc error\n",
> > +                __func__, width, height);
> > +        return NULL;
> > +    }
> >
> 
> I think you could simply abort() in this function. It is used with static
> data (ui/cursor*.xpm)

Yes, that should never happen.

Missing: vmsvga_cursor_define() calls cursor_alloc() with guest-supplied
values too.

take care,
  Gerd
Peter Maydell April 5, 2022, 11:56 a.m. UTC | #3
On Tue, 5 Apr 2022 at 11:50, Mauro Matteo Cascella <mcascell@redhat.com> wrote:
>
> Prevent potential integer overflow by limiting 'width' and 'height' to
> 512x512. Also change 'datasize' type to size_t. Refer to security
> advisory https://starlabs.sg/advisories/22-4206/ for more information.
>
> Fixes: CVE-2022-4206
> Signed-off-by: Mauro Matteo Cascella <mcascell@redhat.com>

> diff --git a/ui/cursor.c b/ui/cursor.c
> index 1d62ddd4d0..7cfb08a030 100644
> --- a/ui/cursor.c
> +++ b/ui/cursor.c
> @@ -46,6 +46,13 @@ static QEMUCursor *cursor_parse_xpm(const char *xpm[])
>
>      /* parse pixel data */
>      c = cursor_alloc(width, height);
> +
> +    if (!c) {
> +        fprintf(stderr, "%s: cursor %ux%u alloc error\n",
> +                __func__, width, height);
> +        return NULL;

Side note, we should probably clean up the error handling in
this file to not be "print to stderr" at some point...

> +    }
> +
>      for (pixel = 0, y = 0; y < height; y++, line++) {
>          for (x = 0; x < height; x++, pixel++) {
>              idx = xpm[line][x];
> @@ -91,7 +98,10 @@ QEMUCursor *cursor_builtin_left_ptr(void)
>  QEMUCursor *cursor_alloc(int width, int height)
>  {
>      QEMUCursor *c;
> -    int datasize = width * height * sizeof(uint32_t);
> +    size_t datasize = width * height * sizeof(uint32_t);
> +
> +    if (width > 512 || height > 512)
> +        return NULL;

Coding style requires braces on if statements.

thanks
-- PMM
Mauro Matteo Cascella April 5, 2022, 2:47 p.m. UTC | #4
On Tue, Apr 5, 2022 at 1:10 PM Gerd Hoffmann <kraxel@redhat.com> wrote:
>
> > > +++ b/ui/cursor.c
> > > @@ -46,6 +46,13 @@ static QEMUCursor *cursor_parse_xpm(const char *xpm[])
> > >
> > >      /* parse pixel data */
> > >      c = cursor_alloc(width, height);
> > > +
> > > +    if (!c) {
> > > +        fprintf(stderr, "%s: cursor %ux%u alloc error\n",
> > > +                __func__, width, height);
> > > +        return NULL;
> > > +    }
> > >
> >
> > I think you could simply abort() in this function. It is used with static
> > data (ui/cursor*.xpm)
>
> Yes, that should never happen.
>
> Missing: vmsvga_cursor_define() calls cursor_alloc() with guest-supplied
> values too.

I skipped that because the check (cursor.width > 256 || cursor.height
> 256) is already done in vmsvga_fifo_run before calling
vmsvga_cursor_define. You want me to add another check in
vmsvga_cursor_define and return NULL if cursor_alloc fails?

> take care,
>   Gerd
>


--
Mauro Matteo Cascella
Red Hat Product Security
PGP-Key ID: BB3410B0
Gerd Hoffmann April 6, 2022, 6:24 a.m. UTC | #5
On Tue, Apr 05, 2022 at 04:47:18PM +0200, Mauro Matteo Cascella wrote:
> On Tue, Apr 5, 2022 at 1:10 PM Gerd Hoffmann <kraxel@redhat.com> wrote:
> >
> > > > +++ b/ui/cursor.c
> > > > @@ -46,6 +46,13 @@ static QEMUCursor *cursor_parse_xpm(const char *xpm[])
> > > >
> > > >      /* parse pixel data */
> > > >      c = cursor_alloc(width, height);
> > > > +
> > > > +    if (!c) {
> > > > +        fprintf(stderr, "%s: cursor %ux%u alloc error\n",
> > > > +                __func__, width, height);
> > > > +        return NULL;
> > > > +    }
> > > >
> > >
> > > I think you could simply abort() in this function. It is used with static
> > > data (ui/cursor*.xpm)
> >
> > Yes, that should never happen.
> >
> > Missing: vmsvga_cursor_define() calls cursor_alloc() with guest-supplied
> > values too.
> 
> I skipped that because the check (cursor.width > 256 || cursor.height
> > 256) is already done in vmsvga_fifo_run before calling
> vmsvga_cursor_define. You want me to add another check in
> vmsvga_cursor_define and return NULL if cursor_alloc fails?

No check required then.

Maybe add an 'assert(c != NULL)' to clarify this should never happen
b/c those call sites never call cursor_alloc() with width/height being
too big (your choice, applies to both vmsvga and ui/cursor.c).

take care,
  Gerd
diff mbox series

Patch

diff --git a/hw/display/qxl-render.c b/hw/display/qxl-render.c
index d28849b121..dc3c4edd05 100644
--- a/hw/display/qxl-render.c
+++ b/hw/display/qxl-render.c
@@ -247,6 +247,13 @@  static QEMUCursor *qxl_cursor(PCIQXLDevice *qxl, QXLCursor *cursor,
     size_t size;
 
     c = cursor_alloc(cursor->header.width, cursor->header.height);
+
+    if (!c) {
+        qxl_set_guest_bug(qxl, "%s: cursor %ux%u alloc error", __func__,
+                cursor->header.width, cursor->header.height);
+        goto fail;
+    }
+
     c->hot_x = cursor->header.hot_spot_x;
     c->hot_y = cursor->header.hot_spot_y;
     switch (cursor->header.type) {
diff --git a/ui/cursor.c b/ui/cursor.c
index 1d62ddd4d0..7cfb08a030 100644
--- a/ui/cursor.c
+++ b/ui/cursor.c
@@ -46,6 +46,13 @@  static QEMUCursor *cursor_parse_xpm(const char *xpm[])
 
     /* parse pixel data */
     c = cursor_alloc(width, height);
+
+    if (!c) {
+        fprintf(stderr, "%s: cursor %ux%u alloc error\n",
+                __func__, width, height);
+        return NULL;
+    }
+
     for (pixel = 0, y = 0; y < height; y++, line++) {
         for (x = 0; x < height; x++, pixel++) {
             idx = xpm[line][x];
@@ -91,7 +98,10 @@  QEMUCursor *cursor_builtin_left_ptr(void)
 QEMUCursor *cursor_alloc(int width, int height)
 {
     QEMUCursor *c;
-    int datasize = width * height * sizeof(uint32_t);
+    size_t datasize = width * height * sizeof(uint32_t);
+
+    if (width > 512 || height > 512)
+        return NULL;
 
     c = g_malloc0(sizeof(QEMUCursor) + datasize);
     c->width  = width;