Drop VNC connection if the server sends a update spaning outside bounds of

desktop (rhbz #540810) Fix gcrypt threading initialization (rhbz
    #537489)
This commit is contained in:
Daniel P. Berrange 2010-04-27 11:45:39 +00:00
parent 4c858e6a33
commit 453bca619a
8 changed files with 299 additions and 1506 deletions

217
gtk-vnc-0.3.10-bounds.patch Normal file
View File

@ -0,0 +1,217 @@
diff -rup gtk-vnc-0.3.10/src/gvnc.c gtk-vnc-0.3.10.new/src/gvnc.c
--- gtk-vnc-0.3.10/src/gvnc.c 2010-04-27 12:04:45.657317541 +0100
+++ gtk-vnc-0.3.10.new/src/gvnc.c 2010-04-27 12:12:00.726185001 +0100
@@ -2192,35 +2192,64 @@ static void gvnc_ext_key_event(struct gv
gvnc->keycode_map = x_keycode_to_pc_keycode_map();
}
-static void gvnc_framebuffer_update(struct gvnc *gvnc, int32_t etype,
- uint16_t x, uint16_t y,
- uint16_t width, uint16_t height)
+
+static gboolean gvnc_validate_boundary(struct gvnc *gvnc,
+ uint16_t width, uint16_t height)
+{
+
+ if (width > gvnc->width || height > gvnc->height) {
+ GVNC_DEBUG("Framebuffer update %dx%d outside boundary %dx%d",
+ width, height, gvnc->width, gvnc->height);
+ gvnc->has_error = TRUE;
+ }
+
+ return !gvnc_has_error(gvnc);
+}
+
+static gboolean gvnc_framebuffer_update(struct gvnc *gvnc, int32_t etype,
+ uint16_t x, uint16_t y,
+ uint16_t width, uint16_t height)
{
GVNC_DEBUG("FramebufferUpdate(%d, %d, %d, %d, %d)",
etype, x, y, width, height);
+ if (gvnc_has_error(gvnc))
+ return !gvnc_has_error(gvnc);
+
switch (etype) {
case GVNC_ENCODING_RAW:
+ if (!gvnc_validate_boundary(gvnc, width, height))
+ break;
gvnc_raw_update(gvnc, x, y, width, height);
gvnc_update(gvnc, x, y, width, height);
break;
case GVNC_ENCODING_COPY_RECT:
+ if (!gvnc_validate_boundary(gvnc, width, height))
+ break;
gvnc_copyrect_update(gvnc, x, y, width, height);
gvnc_update(gvnc, x, y, width, height);
break;
case GVNC_ENCODING_RRE:
+ if (!gvnc_validate_boundary(gvnc, width, height))
+ break;
gvnc_rre_update(gvnc, x, y, width, height);
gvnc_update(gvnc, x, y, width, height);
break;
case GVNC_ENCODING_HEXTILE:
+ if (!gvnc_validate_boundary(gvnc, width, height))
+ break;
gvnc_hextile_update(gvnc, x, y, width, height);
gvnc_update(gvnc, x, y, width, height);
break;
case GVNC_ENCODING_ZRLE:
+ if (!gvnc_validate_boundary(gvnc, width, height))
+ break;
gvnc_zrle_update(gvnc, x, y, width, height);
gvnc_update(gvnc, x, y, width, height);
break;
case GVNC_ENCODING_TIGHT:
+ if (!gvnc_validate_boundary(gvnc, width, height))
+ break;
gvnc_tight_update(gvnc, x, y, width, height);
gvnc_update(gvnc, x, y, width, height);
break;
@@ -2249,6 +2278,8 @@ static void gvnc_framebuffer_update(stru
gvnc->has_error = TRUE;
break;
}
+
+ return !gvnc_has_error(gvnc);
}
gboolean gvnc_server_message(struct gvnc *gvnc)
@@ -2256,6 +2287,9 @@ gboolean gvnc_server_message(struct gvnc
uint8_t msg;
int ret;
+ if (gvnc_has_error(gvnc))
+ return !gvnc_has_error(gvnc);
+
/* NB: make sure that all server message functions
handle has_error appropriately */
@@ -2290,7 +2324,8 @@ gboolean gvnc_server_message(struct gvnc
h = gvnc_read_u16(gvnc);
etype = gvnc_read_s32(gvnc);
- gvnc_framebuffer_update(gvnc, etype, x, y, w, h);
+ if (!gvnc_framebuffer_update(gvnc, etype, x, y, w, h))
+ break;
}
} break;
case 1: { /* SetColorMapEntries */
@@ -3459,8 +3494,11 @@ void gvnc_close(struct gvnc *gvnc)
gvnc->tls_session = NULL;
}
#if HAVE_SASL
- if (gvnc->saslconn)
+ if (gvnc->saslconn) {
sasl_dispose (&gvnc->saslconn);
+ gvnc->saslconn = NULL;
+ gvnc->saslDecodedOffset = gvnc->saslDecodedLength = 0;
+ }
#endif
if (gvnc->channel) {
@@ -3512,6 +3550,7 @@ void gvnc_close(struct gvnc *gvnc)
g_free(gvnc->cred_x509_key);
gvnc->cred_x509_key = NULL;
}
+ gvnc->want_cred_x509 = gvnc->want_cred_username = gvnc->want_cred_password = FALSE;
for (i = 0; i < 5; i++)
inflateEnd(&gvnc->streams[i]);
@@ -3519,7 +3558,28 @@ void gvnc_close(struct gvnc *gvnc)
gvnc->auth_type = GVNC_AUTH_INVALID;
gvnc->auth_subtype = GVNC_AUTH_INVALID;
- gvnc->has_error = 0;
+ memset(&gvnc->fmt, 0, sizeof(gvnc->fmt));
+ gvnc->perfect_match = FALSE;
+ memset(&gvnc->local, 0, sizeof(gvnc->local));
+ gvnc->rm = gvnc->gm = gvnc->bm = 0;
+ gvnc->rrs = gvnc->grs = gvnc->brs = 0;
+ gvnc->rls = gvnc->gls = gvnc->bls = 0;
+
+ gvnc->read_offset = gvnc->read_size = 0;
+ gvnc->write_offset = 0;
+
+ if (gvnc->xmit_buffer) {
+ g_free(gvnc->xmit_buffer);
+ gvnc->xmit_buffer = NULL;
+ }
+ gvnc->xmit_buffer_size = gvnc->xmit_buffer_capacity = 0;
+ gvnc->uncompressed_length = 0;
+ gvnc->compressed_length = 0;
+
+ gvnc->width = gvnc->height = 0;
+ gvnc->major = gvnc->minor = 0;
+
+ gvnc->has_error = FALSE;
}
void gvnc_shutdown(struct gvnc *gvnc)
@@ -3569,11 +3629,15 @@ gboolean gvnc_initialize(struct gvnc *gv
gvnc->absolute = 1;
gvnc_read(gvnc, version, 12);
- version[12] = 0;
+ if (gvnc_has_error(gvnc)) {
+ GVNC_DEBUG("Error while reading server version");
+ goto fail;
+ }
+ version[12] = 0;
ret = sscanf(version, "RFB %03d.%03d\n", &gvnc->major, &gvnc->minor);
if (ret != 2) {
- GVNC_DEBUG("Error while getting server version");
+ GVNC_DEBUG("Error while parsing server version");
goto fail;
}
@@ -3604,6 +3668,8 @@ gboolean gvnc_initialize(struct gvnc *gv
gvnc->width = gvnc_read_u16(gvnc);
gvnc->height = gvnc_read_u16(gvnc);
+ GVNC_DEBUG("Initial desktop size %dx%d", gvnc->width, gvnc->height);
+
if (gvnc_has_error(gvnc))
return FALSE;
@@ -3638,7 +3704,7 @@ gboolean gvnc_initialize(struct gvnc *gv
return !gvnc_has_error(gvnc);
fail:
- gvnc->has_error = 1;
+ gvnc->has_error = TRUE;
return !gvnc_has_error(gvnc);
}
diff -rup gtk-vnc-0.3.10/src/vncdisplay.c gtk-vnc-0.3.10.new/src/vncdisplay.c
--- gtk-vnc-0.3.10/src/vncdisplay.c 2009-10-16 17:52:28.000000000 +0100
+++ gtk-vnc-0.3.10.new/src/vncdisplay.c 2010-04-27 12:10:24.790184856 +0100
@@ -879,7 +879,8 @@ static void setup_gdk_image(VncDisplay *
priv->image = gdk_image_new(GDK_IMAGE_FASTEST, visual, width, height);
priv->pixmap = gdk_pixmap_new(GTK_WIDGET(obj)->window, width, height, -1);
- GVNC_DEBUG("Visual mask: %3d %3d %3d\n shift: %3d %3d %3d",
+ GVNC_DEBUG("Size %dx%%d\n Visual mask: %3d %3d %3d\n shift: %3d %3d %3d",
+ width, height,
visual->red_mask,
visual->green_mask,
visual->blue_mask,
@@ -973,6 +974,8 @@ static gboolean do_resize(void *opaque,
VncDisplayPrivate *priv = obj->priv;
struct signal_data s;
+ GVNC_DEBUG("Do resize %dx%d %d", width, height, quiet);
+
if (priv->gvnc == NULL || !gvnc_is_initialized(priv->gvnc))
return TRUE;
@@ -1340,6 +1343,7 @@ static gboolean delayed_unref_object(gpo
{
VncDisplay *obj = VNC_DISPLAY(data);
+ GVNC_DEBUG("Delayed unref %p %d", data, obj->priv->coroutine.exited);
g_assert(obj->priv->coroutine.exited == TRUE);
if (obj->priv->image) {

View File

@ -0,0 +1,73 @@
commit 90225c7981ae7a1586e6dbf136ba34b0e1ec8cae
Author: Daniel P. Berrange <berrange@redhat.com>
Date: Thu Dec 17 18:23:19 2009 +0000
Initialize gcrypt threading callbacks
If GTK has threading enabled, we must be sure to enable gcrypt
threading callbacks too for safety
diff --git a/src/gvnc.c b/src/gvnc.c
index 307bbfe..c42fd6e 100644
--- a/src/gvnc.c
+++ b/src/gvnc.c
@@ -781,6 +781,47 @@ static void gvnc_debug_gnutls_log(int level, const char* str) {
}
#endif
+
+static int gvnc_tls_mutex_init (void **priv)
+{ \
+ GMutex *lock = NULL;
+ lock = g_mutex_new();
+ *priv = lock;
+ return 0;
+}
+
+static int gvnc_tls_mutex_destroy(void **priv)
+{
+ GMutex *lock = *priv;
+ g_mutex_free(lock);
+ return 0;
+}
+
+static int gvnc_tls_mutex_lock(void **priv)
+{
+ GMutex *lock = *priv;
+ g_mutex_lock(lock);
+ return 0;
+}
+
+static int gvnc_tls_mutex_unlock(void **priv)
+{
+ GMutex *lock = *priv;
+ g_mutex_unlock(lock);
+ return 0;
+}
+
+static struct gcry_thread_cbs gvnc_thread_impl = {
+ (GCRY_THREAD_OPTION_PTHREAD | (GCRY_THREAD_OPTION_VERSION << 8)),
+ NULL,
+ gvnc_tls_mutex_init,
+ gvnc_tls_mutex_destroy,
+ gvnc_tls_mutex_lock,
+ gvnc_tls_mutex_unlock,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+
static gboolean gvnc_tls_initialize(void)
{
static int tlsinitialized = 0;
@@ -788,6 +829,11 @@ static gboolean gvnc_tls_initialize(void)
if (tlsinitialized)
return TRUE;
+ if (g_thread_supported()) {
+ gcry_control(GCRYCTL_SET_THREAD_CBS, &gvnc_thread_impl);
+ gcry_check_version(NULL);
+ }
+
if (gnutls_global_init () < 0)
return FALSE;

View File

@ -1,142 +0,0 @@
commit 85279b75576fcce7465754a8cc7b21cb6db5c355
Author: Daniel P. Berrange <berrange@redhat.com>
Date: Thu Feb 26 13:29:16 2009 +0000
Change pointer grab to allow movement across entire desktop and
fix warping of pointer at desktop edges, to make relative mouse
mode work correctly. Document what's going on with more comments.
diff --git a/src/vncdisplay.c b/src/vncdisplay.c
index 5a25b91..f1082da 100644
--- a/src/vncdisplay.c
+++ b/src/vncdisplay.c
@@ -439,14 +439,22 @@ static void do_pointer_grab(VncDisplay *obj, gboolean quiet)
if (!priv->grab_keyboard)
do_keyboard_grab(obj, quiet);
+ /*
+ * For relative mouse to work correctly when grabbed we need to
+ * allow the pointer to move anywhere on the local desktop, so
+ * use NULL for the 'confine_to' argument. Furthermore we need
+ * the coords to be reported to our VNC window, regardless of
+ * what window the pointer is actally over, so use 'FALSE' for
+ * 'owner_events' parameter
+ */
gdk_pointer_grab(GTK_WIDGET(obj)->window,
- TRUE,
+ FALSE, /* All events to come to our window directly */
GDK_POINTER_MOTION_MASK |
GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK |
GDK_BUTTON_MOTION_MASK |
GDK_SCROLL_MASK,
- GTK_WIDGET(obj)->window,
+ NULL, /* Allow cursor to move over entire desktop */
priv->remote_cursor ? priv->remote_cursor : priv->null_cursor,
GDK_CURRENT_TIME);
priv->in_pointer_grab = TRUE;
@@ -551,15 +559,33 @@ static gboolean scroll_event(GtkWidget *widget, GdkEventScroll *scroll)
return TRUE;
}
+
+/*
+ * There are several scenarios to considier when handling client
+ * mouse motion events:
+ *
+ * - Mouse in relative mode + centered rendering of desktop
+ * - Mouse in relative mode + scaled rendering of desktop
+ * - Mouse in absolute mode + centered rendering of desktop
+ * - Mouse in absolute mode + scaled rendering of desktop
+ *
+ * Once scaled / offset, absolute mode is easy.
+ *
+ * Relative mode has a couple of special complications
+ *
+ * - Need to turn client absolute events into a delta
+ * - Need to warp local pointer to avoid hitting a wall
+ */
static gboolean motion_event(GtkWidget *widget, GdkEventMotion *motion)
{
VncDisplayPrivate *priv = VNC_DISPLAY(widget)->priv;
- int dx, dy;
int ww, wh;
if (priv->gvnc == NULL || !gvnc_is_initialized(priv->gvnc))
return FALSE;
+ /* In relative mode, only move the server mouse pointer
+ * if the client grab is active */
if (!priv->absolute && !priv->in_pointer_grab)
return FALSE;
@@ -568,11 +594,14 @@ static gboolean motion_event(GtkWidget *widget, GdkEventMotion *motion)
gdk_drawable_get_size(widget->window, &ww, &wh);
+ /* First apply adjustments to the coords in the motion event */
if (priv->allow_scaling) {
double sx, sy;
sx = (double)priv->fb.width / (double)ww;
sy = (double)priv->fb.height / (double)wh;
+ /* Scaling the desktop, so scale the mouse coords
+ * by same ratio */
motion->x *= sx;
motion->y *= sy;
} else {
@@ -583,21 +612,28 @@ static gboolean motion_event(GtkWidget *widget, GdkEventMotion *motion)
if (wh > priv->fb.height)
mh = (wh - priv->fb.height) / 2;
+ /* Not scaling, drawing the desktop centered
+ * in the larger window, so offset the mouse
+ * coords to match centering */
motion->x -= mw;
motion->y -= mh;
-
- if (motion->x < 0 || motion->x >= priv->fb.width ||
- motion->y < 0 || motion->y >= priv->fb.height)
- return FALSE;
}
- if (!priv->absolute && priv->in_pointer_grab) {
+ /* Next adjust the real client pointer */
+ if (!priv->absolute) {
GdkDrawable *drawable = GDK_DRAWABLE(widget->window);
GdkDisplay *display = gdk_drawable_get_display(drawable);
GdkScreen *screen = gdk_drawable_get_screen(drawable);
int x = (int)motion->x_root;
int y = (int)motion->y_root;
+ /* In relative mode check to see if client pointer hit
+ * one of the screen edges, and if so move it back by
+ * 200 pixels. This is important because the pointer
+ * in the server doesn't correspond 1-for-1, and so
+ * may still be only half way across the screen. Without
+ * this warp, the server pointer would thus appear to hit
+ * an invisible wall */
if (x == 0) x += 200;
if (y == 0) y += 200;
if (x == (gdk_screen_get_width(screen) - 1)) x -= 200;
@@ -611,11 +647,20 @@ static gboolean motion_event(GtkWidget *widget, GdkEventMotion *motion)
}
}
+ /* Finally send the event to server */
if (priv->last_x != -1) {
+ int dx, dy;
if (priv->absolute) {
dx = (int)motion->x;
dy = (int)motion->y;
+
+ /* Drop out of bounds motion to avoid upsetting
+ * the server */
+ if (dx < 0 || dx >= priv->fb.width ||
+ dy < 0 || dy >= priv->fb.height)
+ return FALSE;
} else {
+ /* Just send the delta since last motion event */
dx = (int)motion->x + 0x7FFF - priv->last_x;
dy = (int)motion->y + 0x7FFF - priv->last_y;
}

View File

@ -1,25 +0,0 @@
diff -rup gtk-vnc-0.3.8.orig/src/gvnc.c gtk-vnc-0.3.8.new/src/gvnc.c
--- gtk-vnc-0.3.8.orig/src/gvnc.c 2009-03-05 15:35:33.000000000 +0000
+++ gtk-vnc-0.3.8.new/src/gvnc.c 2009-03-05 15:57:58.000000000 +0000
@@ -2579,7 +2579,9 @@ static gboolean gvnc_perform_auth_sasl(s
errno, strerror(errno));
goto error;
}
- if ((localAddr = gvnc_addr_to_string(&sa, salen)) == NULL)
+ if ((sa.ss_family == AF_INET ||
+ sa.ss_family == AF_INET6) &&
+ (localAddr = gvnc_addr_to_string(&sa, salen)) == NULL)
goto error;
/* Get remote address in form IPADDR:PORT */
@@ -2590,7 +2592,9 @@ static gboolean gvnc_perform_auth_sasl(s
g_free(localAddr);
goto error;
}
- if ((remoteAddr = gvnc_addr_to_string(&sa, salen)) == NULL) {
+ if ((sa.ss_family == AF_INET ||
+ sa.ss_family == AF_INET6) &&
+ (remoteAddr = gvnc_addr_to_string(&sa, salen)) == NULL) {
g_free(localAddr);
goto error;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +0,0 @@
diff -rup gtk-vnc-0.3.8.orig/src/vncdisplay.c gtk-vnc-0.3.8.new/src/vncdisplay.c
--- gtk-vnc-0.3.8.orig/src/vncdisplay.c 2009-03-27 15:09:37.000000000 +0000
+++ gtk-vnc-0.3.8.new/src/vncdisplay.c 2009-03-27 15:10:14.000000000 +0000
@@ -1034,7 +1034,7 @@ static gboolean on_pointer_type_change(v
VncDisplay *obj = VNC_DISPLAY(opaque);
VncDisplayPrivate *priv = obj->priv;
- if (absolute && priv->in_pointer_grab && !priv->grab_pointer)
+ if (absolute && priv->in_pointer_grab && priv->grab_pointer)
do_pointer_ungrab(obj, FALSE);
priv->absolute = absolute;

View File

@ -1,24 +0,0 @@
diff --git a/src/vncdisplay.c b/src/vncdisplay.c
index f1082da..5c78ab8 100644
--- a/src/vncdisplay.c
+++ b/src/vncdisplay.c
@@ -765,9 +765,6 @@ static gboolean enter_event(GtkWidget *widget, GdkEventCrossing *crossing)
if (priv->gvnc == NULL || !gvnc_is_initialized(priv->gvnc))
return FALSE;
- if (crossing->mode != GDK_CROSSING_NORMAL)
- return FALSE;
-
if (priv->grab_keyboard)
do_keyboard_grab(VNC_DISPLAY(widget), FALSE);
@@ -781,9 +778,6 @@ static gboolean leave_event(GtkWidget *widget, GdkEventCrossing *crossing)
if (priv->gvnc == NULL || !gvnc_is_initialized(priv->gvnc))
return FALSE;
- if (crossing->mode != GDK_CROSSING_NORMAL)
- return FALSE;
-
if (priv->grab_keyboard)
do_keyboard_ungrab(VNC_DISPLAY(widget), FALSE);

View File

@ -7,11 +7,12 @@
Summary: A GTK widget for VNC clients
Name: gtk-vnc
Version: 0.3.10
Release: 1%{?dist}
Release: 3%{?dist}
License: LGPLv2+
Group: Development/Libraries
Source: http://ftp.gnome.org/pub/GNOME/sources/%{name}/0.3/%{name}-%{version}.tar.bz2
Patch1: %{name}-%{version}-gcrypt-threading.patch
Patch2: %{name}-%{version}-bounds.patch
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
URL: http://live.gnome.org/gtk-vnc
BuildRequires: gtk2-devel pygtk2-devel python-devel zlib-devel
@ -69,6 +70,8 @@ browsers.
%prep
%setup -q
%patch1 -p1
%patch2 -p1
%build
%if %{with_plugin}
@ -124,6 +127,10 @@ rm -fr %{buildroot}
%endif
%changelog
* Tue Apr 27 2010 Daniel P. Berrange <berrange@redhat.com> - 0.3.10-3
- Drop VNC connection if the server sends a update spaning outside bounds of desktop (rhbz #540810)
- Fix gcrypt threading initialization (rhbz #537489)
* Tue Oct 20 2009 Matthias Clasen <mclaesn@redhat.com> - 0.3.10-1
- Update to 0.3.10