From: Gerd Hoffmann <kraxel@redhat.com>
Date: Thu, 28 Feb 2013 11:34:31 +0100
Subject: console: kill DisplayState->opaque

It's broken by design.  There can be multiple DisplayChangeListener
instances, so they simply can't store state in the (single) DisplayState
struct.  Try 'qemu -display gtk -vnc :0', watch it crash & burn.

With DisplayChangeListenerOps having a more sane interface now we can
simply use the DisplayChangeListener pointer to get access to our
private data instead.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit 21ef45d71221b4577330fe3aacfb06afad91ad46)
[BR: BSC#1026612 CVE-2017-2633 (infrastructure patch)]
Signed-off-by: Bruce Rogers <brogers@suse.com>
---
 include/ui/console.h |  1 -
 ui/vnc.c             | 36 ++++++++++++++++--------------------
 ui/vnc.h             |  1 +
 3 files changed, 17 insertions(+), 21 deletions(-)

diff --git a/include/ui/console.h b/include/ui/console.h
index 058c96bad8e767a63241256f896e..7b4610aea0d03ceab4c8a46ffcb2 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -189,7 +189,6 @@ struct DisplayChangeListener {
 
 struct DisplayState {
     struct DisplaySurface *surface;
-    void *opaque;
     struct QEMUTimer *gui_timer;
     bool have_gfx;
     bool have_text;
diff --git a/ui/vnc.c b/ui/vnc.c
index 2a43535526ca36fb7b21f464b68e..0a3fdd4b8c726d1103a42b7d4f5c 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -44,7 +44,6 @@ static const struct timeval VNC_REFRESH_LOSSY = { 2, 0 };
 #include "d3des.h"
 
 static VncDisplay *vnc_display; /* needed for info vnc */
-static DisplayChangeListener *dcl;
 static int allowed_connections = 0;
 
 static int vnc_cursor_define(VncState *vs);
@@ -435,7 +434,7 @@ static void vnc_dpy_update(DisplayChangeListener *dcl,
                            int x, int y, int w, int h)
 {
     int i;
-    VncDisplay *vd = ds->opaque;
+    VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
     struct VncSurface *s = &vd->guest;
     int width = ds_get_width(ds);
     int height = ds_get_height(ds);
@@ -578,7 +577,7 @@ void *vnc_server_fb_ptr(VncDisplay *vd, int x, int y)
 static void vnc_dpy_resize(DisplayChangeListener *dcl,
                            DisplayState *ds)
 {
-    VncDisplay *vd = ds->opaque;
+    VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
     VncState *vs;
 
     vnc_abort_display_jobs(vd);
@@ -975,7 +974,7 @@ void vnc_disconnect_finish(VncState *vs)
     }
 
     if (QTAILQ_EMPTY(&vs->vd->clients)) {
-        dcl->idle = 1;
+        vs->vd->dcl.idle = 1;
     }
 
     vnc_remove_timer(vs->vd);
@@ -1976,7 +1975,7 @@ static void pixel_format_message (VncState *vs) {
 static void vnc_dpy_setdata(DisplayChangeListener *dcl,
                             DisplayState *ds)
 {
-    VncDisplay *vd = ds->opaque;
+    VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
 
     qemu_pixman_image_unref(vd->guest.fb);
     vd->guest.fb = pixman_image_ref(ds->surface->image);
@@ -2695,7 +2694,7 @@ static void vnc_init_timer(VncDisplay *vd)
     vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
     if (vd->timer == NULL && !QTAILQ_EMPTY(&vd->clients)) {
         vd->timer = qemu_new_timer_ms(rt_clock, vnc_refresh, vd);
-        vnc_dpy_resize(dcl, vd->ds);
+        vnc_dpy_resize(&vd->dcl, vd->ds);
         vnc_refresh(vd);
     }
 }
@@ -2734,7 +2733,7 @@ static void vnc_connect(VncDisplay *vd, int csock, int skipauth, bool websocket)
     }
 
     VNC_DEBUG("New client on socket %d\n", csock);
-    dcl->idle = 0;
+    vd->dcl.idle = 0;
     qemu_set_nonblock(vs->csock);
 #ifdef CONFIG_VNC_WS
     if (websocket) {
@@ -2853,10 +2852,7 @@ void vnc_display_init(DisplayState *ds)
 {
     VncDisplay *vs = g_malloc0(sizeof(*vs));
 
-    dcl = g_malloc0(sizeof(DisplayChangeListener));
-
-    ds->opaque = vs;
-    dcl->idle = 1;
+    vs->dcl.idle = 1;
     vnc_display = vs;
 
     vs->lsock = -1;
@@ -2879,14 +2875,14 @@ void vnc_display_init(DisplayState *ds)
     qemu_mutex_init(&vs->mutex);
     vnc_start_worker_thread();
 
-    dcl->ops = &dcl_ops;
-    register_displaychangelistener(ds, dcl);
+    vs->dcl.ops = &dcl_ops;
+    register_displaychangelistener(ds, &vs->dcl);
 }
 
 
 static void vnc_display_close(DisplayState *ds)
 {
-    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
+    VncDisplay *vs = vnc_display;
 
     if (!vs)
         return;
@@ -2917,7 +2913,7 @@ static void vnc_display_close(DisplayState *ds)
 
 static int vnc_display_disable_login(DisplayState *ds)
 {
-    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
+    VncDisplay *vs = vnc_display;
 
     if (!vs) {
         return -1;
@@ -2937,7 +2933,7 @@ static int vnc_display_disable_login(DisplayState *ds)
 
 int vnc_display_password(DisplayState *ds, const char *password)
 {
-    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
+    VncDisplay *vs = vnc_display;
 
     if (!vs) {
         return -EINVAL;
@@ -2963,7 +2959,7 @@ int vnc_display_password(DisplayState *ds, const char *password)
 
 int vnc_display_pw_expire(DisplayState *ds, time_t expires)
 {
-    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
+    VncDisplay *vs = vnc_display;
 
     if (!vs) {
         return -EINVAL;
@@ -2975,7 +2971,7 @@ int vnc_display_pw_expire(DisplayState *ds, time_t expires)
 
 char *vnc_display_local_addr(DisplayState *ds)
 {
-    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
+    VncDisplay *vs = vnc_display;
     
     return vnc_socket_local_addr("%s:%s", vs->lsock);
 }
@@ -3015,7 +3011,7 @@ static void read_file_password(DisplayState *ds, char *filename, Error **errp)
 
 void vnc_display_open(DisplayState *ds, const char *display, Error **errp)
 {
-    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
+    VncDisplay *vs = vnc_display;
     const char *options;
     int password = 0;
     int reverse = 0;
@@ -3351,7 +3347,7 @@ fail:
 
 void vnc_display_add_client(DisplayState *ds, int csock, int skipauth)
 {
-    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
+    VncDisplay *vs = vnc_display;
 
     vnc_connect(vs, csock, skipauth, 0);
 }
diff --git a/ui/vnc.h b/ui/vnc.h
index 56126f36b2da0095e6bfdf6685bb..2d08bee05c9c21f722bd915454e6 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -151,6 +151,7 @@ struct VncDisplay
     char *ws_display;
 #endif
     DisplayState *ds;
+    DisplayChangeListener dcl;
     kbd_layout_t *kbd_layout;
     int lock_key_sync;
     QemuMutex mutex;
