Bug#854827: unblock: gtk-vnc/0.6.0-3
Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock
Please unblock package gtk-vnc
It fixes CVE-2017-5885 and CVE-2017-5884. There's more noise in the diff
than there should be since wanted to bring patches into a more
git-format-patch compatible layout. The diff is probably easier to read
here:
https://anonscm.debian.org/cgit/pkg-libvirt/gtk-vnc.git/log/
unblock gtk-vnc/0.6.0-3
-- System Information:
Debian Release: 9.0
APT prefers testing
APT policy: (990, 'testing'), (500, 'unstable-debug'), (500, 'testing-debug'), (500, 'stable-updates'), (500, 'unstable'), (500, 'stable'), (500, 'oldstable'), (1, 'experimental')
Architecture: amd64 (x86_64)
Foreign Architectures: i386
Kernel: Linux 4.9.0-1-amd64 (SMP w/4 CPU cores)
Locale: LANG=de_DE.UTF-8, LC_CTYPE=de_DE.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)
diff --git a/debian/changelog b/debian/changelog
index 8698ecc..28203ee 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,14 @@
+gtk-vnc (0.6.0-3) unstable; urgency=medium
+
+ * [b8d9918] CVE-2017-5884: Fix bounds checking for RRE, hextile & copyrect
+ encodings
+ * [ca87ace] CVE-2017-5885: Correctly validate color map range indexes
+ (Closes: #854450)
+ * [0e71020] Link against GIO_LIBS explicitly to fix build failure
+ * [7d3fdde] Rediff patches to make them more git-format-patch compatible
+
+ -- Guido Günther <agx@sigxcpu.org> Fri, 10 Feb 2017 14:20:29 +0100
+
gtk-vnc (0.6.0-2) unstable; urgency=medium
* Team upload.
diff --git a/debian/patches/Add-I-m4-to-Makefile.am.patch b/debian/patches/Add-I-m4-to-Makefile.am.patch
new file mode 100644
index 0000000..8d44369
--- /dev/null
+++ b/debian/patches/Add-I-m4-to-Makefile.am.patch
@@ -0,0 +1,19 @@
+From: Joao Eriberto Mota Filho <eriberto@debian.org>
+Date: Fri, 10 Feb 2017 10:22:10 +0100
+Subject: Add -I m4 to Makefile.am
+
+---
+ Makefile.am | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index 69d1f50..dabb899 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -1,5 +1,5 @@
+ SUBDIRS = src tools examples po vapi
+-ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS}
++ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS} -I m4
+
+ pkgconfig_DATA = $(PACKAGE)-$(GTK_VNC_API_VERSION).pc gvnc-1.0.pc
+ pkgconfigdir = $(libdir)/pkgconfig
diff --git a/debian/patches/Add-m4.patch b/debian/patches/Add-m4.patch
deleted file mode 100644
index c5bdca4..0000000
--- a/debian/patches/Add-m4.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-Description: add -I m4 to Makefile.am
-Author: Joao Eriberto Mota Filho <eriberto@debian.org>
-Last-Update: 2017-01-08
---- gtk-vnc-0.6.0.orig/Makefile.am
-+++ gtk-vnc-0.6.0/Makefile.am
-@@ -1,5 +1,5 @@
- SUBDIRS = src tools examples po vapi
--ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS}
-+ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS} -I m4
-
- pkgconfig_DATA = $(PACKAGE)-$(GTK_VNC_API_VERSION).pc gvnc-1.0.pc
- pkgconfigdir = $(libdir)/pkgconfig
diff --git a/debian/patches/Link-against-GIO_LIBS-explicitly.patch b/debian/patches/Link-against-GIO_LIBS-explicitly.patch
new file mode 100644
index 0000000..d962eb4
--- /dev/null
+++ b/debian/patches/Link-against-GIO_LIBS-explicitly.patch
@@ -0,0 +1,31 @@
+From: =?utf-8?q?Guido_G=C3=BCnther?= <agx@sigxcpu.org>
+Date: Fri, 10 Feb 2017 13:16:26 +0100
+Subject: Link against GIO_LIBS explicitly
+
+to avoid
+
+libtool: link: gcc -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -g -O2 -fdebug-prefix-map=/build/gtk-vnc-0.6.0=. -fstack-protector-strong -Wformat -Werror=format-security -Wl,-z -Wl,relro
+ -Wl,-z -Wl,now -o .libs/vncconnectiontest vncconnectiontest-vncconnectiontest.o ./.libs/libgvnc-1.0.so -lz -pthread
+/usr/bin/ld: vncconnectiontest-vncconnectiontest.o: undefined reference to symbol 'g_io_stream_get_output_stream'
+//usr/lib/x86_64-linux-gnu/libgio-2.0.so.0: error adding symbols: DSO missing from command line
+
+Also make the use of *_CFLAGS and *_LIBS match.
+---
+ src/Makefile.am | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/Makefile.am b/src/Makefile.am
+index f7c1d9d..8bc9085 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -317,8 +317,8 @@ BUILT_SOURCES += $(MARSHAL_FILES) $(ENUM_FILES)
+ CLEANFILES = $(MARSHAL_FILES) $(ENUM_FILES)
+
+ vncconnectiontest_SOURCES = vncconnectiontest.c
+-vncconnectiontest_CFLAGS = $(GOBJECT_CFLAGS)
+-vncconnectiontest_LDADD = libgvnc-1.0.la
++vncconnectiontest_CFLAGS = $(GOBJECT_CFLAGS) $(GIO_CLFAGS)
++vncconnectiontest_LDADD = libgvnc-1.0.la $(GOBJECT_LIBS) $(GIO_LIBS)
+
+ if WITH_PYTHON
+ pyexec_LTLIBRARIES = gtkvnc.la
diff --git a/debian/patches/Remove-GNUmakefile-links.patch b/debian/patches/Remove-GNUmakefile-links.patch
index e35e3b9..a25c47f 100644
--- a/debian/patches/Remove-GNUmakefile-links.patch
+++ b/debian/patches/Remove-GNUmakefile-links.patch
@@ -9,10 +9,10 @@ since it breaks the out of tree build
2 files changed, 22 deletions(-)
diff --git a/configure b/configure
-index 9e779d3..7e8162d 100755
+index 6974f35..d103091 100755
--- a/configure
+++ b/configure
-@@ -12015,17 +12015,6 @@ cat >>confdefs.h <<_ACEOF
+@@ -12615,17 +12615,6 @@ cat >>confdefs.h <<_ACEOF
#define VERSION_MICRO $VERSION_MICRO
_ACEOF
@@ -31,10 +31,10 @@ index 9e779d3..7e8162d 100755
no) :
ac_cv_prog_cc_c99=no; ac_cv_prog_cc_c89=no ;; #(
diff --git a/configure.ac b/configure.ac
-index ff38b17..3568a2b 100644
+index a208501..f4f3dbd 100644
--- a/configure.ac
+++ b/configure.ac
-@@ -56,17 +56,6 @@ AC_DEFINE_UNQUOTED([VERSION_MAJOR], [$VERSION_MAJOR], [Major version number of p
+@@ -55,17 +55,6 @@ AC_DEFINE_UNQUOTED([VERSION_MAJOR], [$VERSION_MAJOR], [Major version number of p
AC_DEFINE_UNQUOTED([VERSION_MINOR], [$VERSION_MINOR], [Minor version number of package])
AC_DEFINE_UNQUOTED([VERSION_MICRO], [$VERSION_MICRO], [Micro version number of package])
diff --git a/debian/patches/security/Correctly-validate-color-map-range-indexes.patch b/debian/patches/security/Correctly-validate-color-map-range-indexes.patch
new file mode 100644
index 0000000..7bf63e0
--- /dev/null
+++ b/debian/patches/security/Correctly-validate-color-map-range-indexes.patch
@@ -0,0 +1,178 @@
+From: "Daniel P. Berrange" <berrange@redhat.com>
+Date: Thu, 2 Feb 2017 18:18:48 +0000
+Subject: Correctly validate color map range indexes
+
+The color map index could wrap around to zero causing negative
+array index accesses.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=778050
+
+CVE-2017-5885
+
+Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
+---
+ src/vnccolormap.c | 4 +--
+ src/vncconnection.c | 18 +++++++++---
+ src/vncconnectiontest.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 92 insertions(+), 6 deletions(-)
+
+diff --git a/src/vnccolormap.c b/src/vnccolormap.c
+index 25cd2fc..f3e153a 100644
+--- a/src/vnccolormap.c
++++ b/src/vnccolormap.c
+@@ -119,7 +119,7 @@ gboolean vnc_color_map_set(VncColorMap *map,
+ guint16 green,
+ guint16 blue)
+ {
+- if (idx >= (map->size + map->offset))
++ if (idx < map->offset || idx >= (map->size + map->offset))
+ return FALSE;
+
+ map->colors[idx - map->offset].red = red;
+@@ -149,7 +149,7 @@ gboolean vnc_color_map_lookup(VncColorMap *map,
+ guint16 *green,
+ guint16 *blue)
+ {
+- if (idx >= (map->size + map->offset))
++ if (idx < map->offset || idx >= (map->size + map->offset))
+ return FALSE;
+
+ *red = map->colors[idx - map->offset].red;
+diff --git a/src/vncconnection.c b/src/vncconnection.c
+index 8290b65..e95811f 100644
+--- a/src/vncconnection.c
++++ b/src/vncconnection.c
+@@ -3344,8 +3344,13 @@ static gboolean vnc_connection_server_message(VncConnection *conn)
+
+ VNC_DEBUG("Colour map from %d with %d entries",
+ first_color, n_colors);
+- map = vnc_color_map_new(first_color, n_colors);
+
++ if (first_color > (65536 - n_colors)) {
++ vnc_connection_set_error(conn, "Colormap start %d out of range %d", first_color, 65536 - n_colors);
++ break;
++ }
++
++ map = vnc_color_map_new(first_color, n_colors);
+ for (i = 0; i < n_colors; i++) {
+ guint16 red, green, blue;
+
+@@ -3353,9 +3358,14 @@ static gboolean vnc_connection_server_message(VncConnection *conn)
+ green = vnc_connection_read_u16(conn);
+ blue = vnc_connection_read_u16(conn);
+
+- vnc_color_map_set(map,
+- i + first_color,
+- red, green, blue);
++ if (!vnc_color_map_set(map,
++ i + first_color,
++ red, green, blue)) {
++ /* Should not be reachable given earlier range check */
++ vnc_connection_set_error(conn, "Colormap index %d out of range %d,%d",
++ i + first_color, first_color, 65536 - n_colors);
++ break;
++ }
+ }
+
+ vnc_framebuffer_set_color_map(priv->fb, map);
+diff --git a/src/vncconnectiontest.c b/src/vncconnectiontest.c
+index 521529e..4917b2f 100644
+--- a/src/vncconnectiontest.c
++++ b/src/vncconnectiontest.c
+@@ -445,6 +445,76 @@ static void test_unexpected_cmap_server(GInputStream *is, GOutputStream *os)
+ }
+
+
++static void test_overflow_cmap_server(GInputStream *is, GOutputStream *os)
++{
++ /* Frame buffer width / height */
++ test_send_u16(os, 100);
++ test_send_u16(os, 100);
++
++ /* BPP, depth, endian, true color */
++ test_send_u8(os, 32);
++ test_send_u8(os, 8);
++ test_send_u8(os, 1);
++ test_send_u8(os, 0);
++
++ /* RGB max + shift*/
++ test_send_u16(os, 255);
++ test_send_u16(os, 255);
++ test_send_u16(os, 255);
++ test_send_u8(os, 0);
++ test_send_u8(os, 8);
++ test_send_u8(os, 16);
++
++ guint8 pad[3] = {0};
++ test_send_bytes(os, pad, G_N_ELEMENTS(pad));
++
++ /* name */
++ guint8 name[] = { 'T', 'e', 's', 't' };
++ test_send_u32(os, G_N_ELEMENTS(name));
++ test_send_bytes(os, name, G_N_ELEMENTS(name));
++
++ /* n-encodings */
++ test_recv_u8(is, 2);
++ /* pad */
++ test_recv_u8(is, 0);
++ /* num encodings */
++ test_recv_u16(is, 5);
++
++ /* encodings */
++ test_recv_s32(is, 16);
++ test_recv_s32(is, 5);
++ test_recv_s32(is, 2);
++ test_recv_s32(is, 1);
++ test_recv_s32(is, 0);
++
++ /* update request */
++ test_recv_u8(is, 3);
++ /* ! incremental */
++ test_recv_u8(is, 0);
++
++ /* x, y, w, h */
++ test_recv_u16(is, 0);
++ test_recv_u16(is, 0);
++ test_recv_u16(is, 100);
++ test_recv_u16(is, 100);
++
++ /* set color map */
++ test_send_u8(os, 1);
++ /* pad */
++ test_send_u8(os, 0);
++ /* first color, ncolors */
++ test_send_u16(os, 65535);
++ test_send_u16(os, 2);
++
++ /* r,g,b */
++ for (int i = 0 ; i < 2; i++) {
++ test_send_u16(os, i);
++ test_send_u16(os, i);
++ test_send_u16(os, i);
++ }
++}
++
++
+ static void test_validation(void (*test_func)(GInputStream *, GOutputStream *))
+ {
+ struct GVncTest *test;
+@@ -526,6 +596,11 @@ static void test_validation_unexpected_cmap(void)
+ {
+ test_validation(test_unexpected_cmap_server);
+ }
++
++static void test_validation_overflow_cmap(void)
++{
++ test_validation(test_overflow_cmap_server);
++}
+ #endif
+
+ int main(int argc, char **argv) {
+@@ -541,6 +616,7 @@ int main(int argc, char **argv) {
+ g_test_add_func("/conn/validation/copyrect", test_validation_copyrect);
+ g_test_add_func("/conn/validation/hextile", test_validation_hextile);
+ g_test_add_func("/conn/validation/unexpectedcmap", test_validation_unexpected_cmap);
++ g_test_add_func("/conn/validation/overflowcmap", test_validation_overflow_cmap);
+ #endif
+
+ return g_test_run();
diff --git a/debian/patches/security/Don-t-accept-color-map-entries-for-true-color-pixel-forma.patch b/debian/patches/security/Don-t-accept-color-map-entries-for-true-color-pixel-forma.patch
new file mode 100644
index 0000000..1d9ddc5
--- /dev/null
+++ b/debian/patches/security/Don-t-accept-color-map-entries-for-true-color-pixel-forma.patch
@@ -0,0 +1,171 @@
+From: "Daniel P. Berrange" <berrange@redhat.com>
+Date: Thu, 2 Feb 2017 18:01:53 +0000
+Subject: Don't accept color map entries for true-color pixel format
+
+The color map entries should only be sent by the server
+when true-color flag is false.
+
+Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
+---
+ src/vncconnection.c | 5 +++
+ src/vncconnectiontest.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++--
+ 2 files changed, 99 insertions(+), 2 deletions(-)
+
+diff --git a/src/vncconnection.c b/src/vncconnection.c
+index 39f1966..8290b65 100644
+--- a/src/vncconnection.c
++++ b/src/vncconnection.c
+@@ -3333,6 +3333,11 @@ static gboolean vnc_connection_server_message(VncConnection *conn)
+ VncColorMap *map;
+ int i;
+
++ if (priv->fmt.true_color_flag) {
++ vnc_connection_set_error(conn, "Got color map entries in true-color pix format");
++ break;
++ }
++
+ vnc_connection_read(conn, pad, 1);
+ first_color = vnc_connection_read_u16(conn);
+ n_colors = vnc_connection_read_u16(conn);
+diff --git a/src/vncconnectiontest.c b/src/vncconnectiontest.c
+index 7ae7265..521529e 100644
+--- a/src/vncconnectiontest.c
++++ b/src/vncconnectiontest.c
+@@ -88,6 +88,22 @@ static void test_recv_u8(GInputStream *is, guint8 v)
+ g_assert(e == v);
+ }
+
++static void test_recv_u16(GInputStream *is, guint16 v)
++{
++ guint16 e;
++ g_assert(g_input_stream_read_all(is, &e, 2, NULL, NULL, NULL));
++ e = GINT16_FROM_BE(e);
++ g_assert(e == v);
++}
++
++static void test_recv_s32(GInputStream *is, gint32 v)
++{
++ gint32 e;
++ g_assert(g_input_stream_read_all(is, &e, 4, NULL, NULL, NULL));
++ e = GINT32_FROM_BE(e);
++ g_assert(e == v);
++}
++
+
+ static gpointer test_helper_server(gpointer opaque)
+ {
+@@ -128,6 +144,9 @@ static gpointer test_helper_server(gpointer opaque)
+ /* auth result */
+ test_send_u32(os, 0);
+
++ /* shared flag */
++ test_recv_u8(is, 0);
++
+ data->test_func(is, os);
+
+ g_mutex_lock(&data->clock);
+@@ -179,8 +198,7 @@ static void test_helper_initialized(VncConnection *conn,
+ gpointer opaque)
+ {
+ struct GVncTest *test = opaque;
+- gint32 encodings[] = { VNC_CONNECTION_ENCODING_DESKTOP_RESIZE,
+- VNC_CONNECTION_ENCODING_ZRLE,
++ gint32 encodings[] = { VNC_CONNECTION_ENCODING_ZRLE,
+ VNC_CONNECTION_ENCODING_HEXTILE,
+ VNC_CONNECTION_ENCODING_RRE,
+ VNC_CONNECTION_ENCODING_COPY_RECT,
+@@ -359,6 +377,74 @@ static void test_copyrect_bounds_server(GInputStream *is, GOutputStream *os)
+ }
+
+
++static void test_unexpected_cmap_server(GInputStream *is, GOutputStream *os)
++{
++ /* Frame buffer width / height */
++ test_send_u16(os, 100);
++ test_send_u16(os, 100);
++
++ /* BPP, depth, endian, true color */
++ test_send_u8(os, 32);
++ test_send_u8(os, 8);
++ test_send_u8(os, 1);
++ test_send_u8(os, 1);
++
++ /* RGB max + shift*/
++ test_send_u16(os, 255);
++ test_send_u16(os, 255);
++ test_send_u16(os, 255);
++ test_send_u8(os, 0);
++ test_send_u8(os, 8);
++ test_send_u8(os, 16);
++
++ guint8 pad[3] = {0};
++ test_send_bytes(os, pad, G_N_ELEMENTS(pad));
++
++ /* name */
++ guint8 name[] = { 'T', 'e', 's', 't' };
++ test_send_u32(os, G_N_ELEMENTS(name));
++ test_send_bytes(os, name, G_N_ELEMENTS(name));
++
++ /* n-encodings */
++ test_recv_u8(is, 2);
++ /* pad */
++ test_recv_u8(is, 0);
++ /* num encodings */
++ test_recv_u16(is, 5);
++
++ /* encodings */
++ test_recv_s32(is, 16);
++ test_recv_s32(is, 5);
++ test_recv_s32(is, 2);
++ test_recv_s32(is, 1);
++ test_recv_s32(is, 0);
++
++ /* update request */
++ test_recv_u8(is, 3);
++ /* ! incremental */
++ test_recv_u8(is, 0);
++
++ /* x, y, w, h */
++ test_recv_u16(is, 0);
++ test_recv_u16(is, 0);
++ test_recv_u16(is, 100);
++ test_recv_u16(is, 100);
++
++ /* set color map */
++ test_send_u8(os, 1);
++ /* pad */
++ test_send_u8(os, 0);
++ /* first color, ncolors */
++ test_send_u16(os, 0);
++ test_send_u16(os, 1);
++
++ /* r,g,b */
++ test_send_u16(os, 128);
++ test_send_u16(os, 128);
++ test_send_u16(os, 128);
++}
++
++
+ static void test_validation(void (*test_func)(GInputStream *, GOutputStream *))
+ {
+ struct GVncTest *test;
+@@ -435,6 +521,11 @@ static void test_validation_copyrect(void)
+ {
+ test_validation(test_copyrect_bounds_server);
+ }
++
++static void test_validation_unexpected_cmap(void)
++{
++ test_validation(test_unexpected_cmap_server);
++}
+ #endif
+
+ int main(int argc, char **argv) {
+@@ -449,6 +540,7 @@ int main(int argc, char **argv) {
+ g_test_add_func("/conn/validation/rre", test_validation_rre);
+ g_test_add_func("/conn/validation/copyrect", test_validation_copyrect);
+ g_test_add_func("/conn/validation/hextile", test_validation_hextile);
++ g_test_add_func("/conn/validation/unexpectedcmap", test_validation_unexpected_cmap);
+ #endif
+
+ return g_test_run();
diff --git a/debian/patches/security/Fix-bounds-checking-for-RRE-hextile-copyrect-encodings.patch b/debian/patches/security/Fix-bounds-checking-for-RRE-hextile-copyrect-encodings.patch
new file mode 100644
index 0000000..3f4ac46
--- /dev/null
+++ b/debian/patches/security/Fix-bounds-checking-for-RRE-hextile-copyrect-encodings.patch
@@ -0,0 +1,610 @@
+From: "Daniel P. Berrange" <berrange@redhat.com>
+Date: Thu, 2 Feb 2017 17:34:47 +0000
+Subject: Fix bounds checking for RRE, hextile & copyrect encodings
+
+While the client would bounds check the overall update
+region, it failed to bounds check the payload data
+parameters.
+
+Add a test case to validate bounds checking.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=778048
+
+CVE-2017-5884
+
+Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
+---
+ cfg.mk | 2 +-
+ src/Makefile.am | 8 +
+ src/vncconnection.c | 41 +++--
+ src/vncconnectiontest.c | 462 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 496 insertions(+), 17 deletions(-)
+ create mode 100644 src/vncconnectiontest.c
+
+diff --git a/cfg.mk b/cfg.mk
+index 524a330..cd4a264 100644
+--- a/cfg.mk
++++ b/cfg.mk
+@@ -109,7 +109,7 @@ sc_copyright_format:
+ prev_version_file = /dev/null
+
+
+-exclude_file_name_regexp--sc_bindtextdomain = ^examples/
++exclude_file_name_regexp--sc_bindtextdomain = ^examples/|src/.*test.c
+
+ exclude_file_name_regexp--sc_preprocessor_indentation = ^*/*.[ch]
+
+diff --git a/src/Makefile.am b/src/Makefile.am
+index 996f5e0..f7c1d9d 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -1,6 +1,10 @@
+
+ EXTRA_DIST = libgvnc_sym.version libgvncpulse_sym.version libgtk-vnc_sym.version vncmarshal.txt
+
++TESTS = vncconnectiontest
++
++noinst_PROGRAMS = $(TESTS)
++
+ lib_LTLIBRARIES = libgvnc-1.0.la
+
+ BUILT_SOURCES =
+@@ -312,6 +316,10 @@ BUILT_SOURCES += $(MARSHAL_FILES) $(ENUM_FILES)
+
+ CLEANFILES = $(MARSHAL_FILES) $(ENUM_FILES)
+
++vncconnectiontest_SOURCES = vncconnectiontest.c
++vncconnectiontest_CFLAGS = $(GOBJECT_CFLAGS)
++vncconnectiontest_LDADD = libgvnc-1.0.la
++
+ if WITH_PYTHON
+ pyexec_LTLIBRARIES = gtkvnc.la
+
+diff --git a/src/vncconnection.c b/src/vncconnection.c
+index 89f07d0..39f1966 100644
+--- a/src/vncconnection.c
++++ b/src/vncconnection.c
+@@ -2168,6 +2168,21 @@ static vnc_connection_tight_sum_pixel_func *vnc_connection_tight_sum_pixel_table
+ (vnc_connection_tight_sum_pixel_func *)vnc_connection_tight_sum_pixel_32x32,
+ };
+
++static gboolean vnc_connection_validate_boundary(VncConnection *conn,
++ guint16 x, guint16 y,
++ guint16 width, guint16 height)
++{
++ VncConnectionPrivate *priv = conn->priv;
++
++ if ((x + width) > priv->width || (y + height) > priv->height) {
++ vnc_connection_set_error(conn, "Framebuffer update %dx%d at %d,%d "
++ "outside boundary %dx%d",
++ width, height, x, y, priv->width, priv->height);
++ }
++
++ return !vnc_connection_has_error(conn);
++}
++
+
+ static void vnc_connection_raw_update(VncConnection *conn,
+ guint16 x, guint16 y,
+@@ -2215,6 +2230,9 @@ static void vnc_connection_copyrect_update(VncConnection *conn,
+ src_x = vnc_connection_read_u16(conn);
+ src_y = vnc_connection_read_u16(conn);
+
++ if (!vnc_connection_validate_boundary(conn, src_x, src_y, width, height))
++ return;
++
+ vnc_framebuffer_copyrect(priv->fb,
+ src_x, src_y,
+ dst_x, dst_y,
+@@ -2257,6 +2275,10 @@ static void vnc_connection_hextile_rect(VncConnection *conn,
+ xy = vnc_connection_read_u8(conn);
+ wh = vnc_connection_read_u8(conn);
+
++ if (!vnc_connection_validate_boundary(conn, x + nibhi(xy), y + niblo(xy),
++ nibhi(wh) + 1, niblo(wh) + 1))
++ return;
++
+ vnc_framebuffer_fill(priv->fb, fg,
+ x + nibhi(xy), y + niblo(xy),
+ nibhi(wh) + 1, niblo(wh) + 1);
+@@ -2313,6 +2335,9 @@ static void vnc_connection_rre_update(VncConnection *conn,
+ sub_w = vnc_connection_read_u16(conn);
+ sub_h = vnc_connection_read_u16(conn);
+
++ if (!vnc_connection_validate_boundary(conn, x + sub_x, y + sub_y, sub_w, sub_h))
++ break;
++
+ vnc_framebuffer_fill(priv->fb, fg,
+ x + sub_x, y + sub_y, sub_w, sub_h);
+ }
+@@ -3079,22 +3104,6 @@ static void vnc_connection_ext_key_event(VncConnection *conn)
+ }
+
+
+-static gboolean vnc_connection_validate_boundary(VncConnection *conn,
+- guint16 x, guint16 y,
+- guint16 width, guint16 height)
+-{
+- VncConnectionPrivate *priv = conn->priv;
+-
+- if ((x + width) > priv->width || (y + height) > priv->height) {
+- vnc_connection_set_error(conn, "Framebuffer update %dx%d at %d,%d "
+- "outside boundary %dx%d",
+- width, height, x, y, priv->width, priv->height);
+- }
+-
+- return !vnc_connection_has_error(conn);
+-}
+-
+-
+ static gboolean vnc_connection_framebuffer_update(VncConnection *conn, gint32 etype,
+ guint16 x, guint16 y,
+ guint16 width, guint16 height)
+diff --git a/src/vncconnectiontest.c b/src/vncconnectiontest.c
+new file mode 100644
+index 0000000..7ae7265
+--- /dev/null
++++ b/src/vncconnectiontest.c
+@@ -0,0 +1,462 @@
++/*
++ * GTK VNC Widget
++ *
++ * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
++ * Copyright (C) 2009-2010 Daniel P. Berrange <dan@berrange.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.0 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#include <config.h>
++
++#include <string.h>
++#include <stdlib.h>
++
++#include "vncconnection.h"
++#include "vncbaseframebuffer.h"
++
++static gboolean debug;
++
++#if GLIB_CHECK_VERSION(2, 22, 0)
++
++struct GVncTest {
++ GMutex lock;
++ GMutex clock;
++ GCond cond;
++ int port;
++ VncConnection *conn;
++ GMainLoop *loop;
++ gboolean connected;
++ gboolean quit;
++ char *error;
++
++ char *pixels;
++
++ void (*test_func)(GInputStream *, GOutputStream *);
++};
++
++
++static void test_send_bytes(GOutputStream *os, const guint8 *str, gsize len)
++{
++ g_assert(g_output_stream_write_all(os, str, len, NULL, NULL, NULL));
++}
++
++static void test_send_u8(GOutputStream *os, guint8 v)
++{
++ g_assert(g_output_stream_write_all(os, &v, 1, NULL, NULL, NULL));
++}
++
++static void test_send_u16(GOutputStream *os, guint16 v)
++{
++ v = GUINT16_TO_BE(v);
++ g_assert(g_output_stream_write_all(os, &v, 2, NULL, NULL, NULL));
++}
++
++static void test_send_u32(GOutputStream *os, guint32 v)
++{
++ v = GUINT32_TO_BE(v);
++ g_assert(g_output_stream_write_all(os, &v, 4, NULL, NULL, NULL));
++}
++
++static void test_send_s32(GOutputStream *os, gint32 v)
++{
++ v = GINT32_TO_BE(v);
++ g_assert(g_output_stream_write_all(os, &v, 4, NULL, NULL, NULL));
++}
++
++static void test_recv_bytes(GInputStream *is, guint8 *str, gsize len)
++{
++ g_assert(g_input_stream_read_all(is, str, len, NULL, NULL, NULL));
++}
++
++static void test_recv_u8(GInputStream *is, guint8 v)
++{
++ guint8 e;
++ g_assert(g_input_stream_read_all(is, &e, 1, NULL, NULL, NULL));
++ g_assert(e == v);
++}
++
++
++static gpointer test_helper_server(gpointer opaque)
++{
++ struct GVncTest *data = opaque;
++ GSocketListener *server;
++ GSocketConnection *client;
++ GIOStream *ios;
++ GInputStream *is;
++ GOutputStream *os;
++
++ server = g_socket_listener_new();
++
++ data->port = g_socket_listener_add_any_inet_port(server, NULL, NULL);
++ g_mutex_unlock(&data->lock);
++
++ client = g_socket_listener_accept(server, NULL, NULL, NULL);
++
++ ios = G_IO_STREAM(client);
++ is = g_io_stream_get_input_stream(ios);
++ os = g_io_stream_get_output_stream(ios);
++
++ guint8 greeting[] = {
++ 'R', 'F', 'B', ' ',
++ '0', '0', '3', '.',
++ '0', '0', '8', '\n',
++ };
++
++ /* Greeting */
++ test_send_bytes(os, greeting, G_N_ELEMENTS(greeting));
++ test_recv_bytes(is, greeting, G_N_ELEMENTS(greeting));
++
++ /* N auth */
++ test_send_u8(os, 1);
++ /* auth == none */
++ test_send_u8(os, 1);
++ test_recv_u8(is, 1);
++
++ /* auth result */
++ test_send_u32(os, 0);
++
++ data->test_func(is, os);
++
++ g_mutex_lock(&data->clock);
++ while (!data->quit) {
++ g_cond_wait(&data->cond, &data->clock);
++ }
++
++ g_object_unref(client);
++}
++
++static void test_helper_desktop_resize(VncConnection *conn,
++ int width, int height,
++ gpointer opaque)
++{
++ struct GVncTest *test = opaque;
++ const VncPixelFormat *remoteFormat;
++ VncPixelFormat localFormat = {
++ .bits_per_pixel = 32,
++ .depth = 32,
++ .byte_order = G_BYTE_ORDER,
++ .true_color_flag = TRUE,
++ .red_max = 255,
++ .green_max = 255,
++ .blue_max = 255,
++ .red_shift = 0,
++ .green_shift = 8,
++ .blue_shift = 16,
++ };
++ VncBaseFramebuffer *fb;
++
++
++ VNC_DEBUG("Resize %dx%d", width, height);
++ remoteFormat = vnc_connection_get_pixel_format(conn);
++
++ /* We'll fix our local copy as rgb888 */
++ test->pixels = g_new0(char, width * height * 4);
++
++ fb = vnc_base_framebuffer_new(test->pixels, width, height, width * 4,
++ remoteFormat,
++ &localFormat);
++
++ vnc_connection_set_framebuffer(conn, VNC_FRAMEBUFFER(fb));
++
++ g_object_unref(fb);
++}
++
++
++static void test_helper_initialized(VncConnection *conn,
++ gpointer opaque)
++{
++ struct GVncTest *test = opaque;
++ gint32 encodings[] = { VNC_CONNECTION_ENCODING_DESKTOP_RESIZE,
++ VNC_CONNECTION_ENCODING_ZRLE,
++ VNC_CONNECTION_ENCODING_HEXTILE,
++ VNC_CONNECTION_ENCODING_RRE,
++ VNC_CONNECTION_ENCODING_COPY_RECT,
++ VNC_CONNECTION_ENCODING_RAW };
++ gint32 *encodingsp;
++ int n_encodings;
++
++ test_helper_desktop_resize(conn,
++ vnc_connection_get_width(conn),
++ vnc_connection_get_height(conn),
++ test);
++
++ encodingsp = encodings;
++ n_encodings = G_N_ELEMENTS(encodings);
++
++ VNC_DEBUG("Sending %d encodings", n_encodings);
++ if (!vnc_connection_set_encodings(conn, n_encodings, encodingsp))
++ goto error;
++
++ VNC_DEBUG("Requesting first framebuffer update");
++ if (!vnc_connection_framebuffer_update_request(test->conn,
++ 0, 0, 0,
++ vnc_connection_get_width(test->conn),
++ vnc_connection_get_height(test->conn)))
++ vnc_connection_shutdown(test->conn);
++
++ test->connected = TRUE;
++ return;
++
++ error:
++ vnc_connection_shutdown(conn);
++}
++
++static void test_helper_auth_choose_type(VncConnection *conn,
++ GValueArray *types G_GNUC_UNUSED,
++ gpointer opaque G_GNUC_UNUSED)
++{
++ vnc_connection_set_auth_type(conn, VNC_CONNECTION_AUTH_NONE);
++}
++
++
++static void test_helper_disconnected(VncConnection *conn G_GNUC_UNUSED,
++ gpointer opaque)
++{
++ struct GVncTest *test = opaque;
++ g_main_quit(test->loop);
++}
++
++static void test_helper_error(VncConnection *conn,
++ const char *str,
++ gpointer opaque)
++{
++ struct GVncTest *test = opaque;
++ test->error = g_strdup(str);
++}
++
++static void test_common_bounds_server(GInputStream *is, GOutputStream *os)
++{
++ /* Frame buffer width / height */
++ test_send_u16(os, 100);
++ test_send_u16(os, 100);
++
++ /* BPP, depth, endian, true color */
++ test_send_u8(os, 32);
++ test_send_u8(os, 8);
++ test_send_u8(os, 1);
++ test_send_u8(os, 1);
++
++ /* RGB max + shift*/
++ test_send_u16(os, 255);
++ test_send_u16(os, 255);
++ test_send_u16(os, 255);
++ test_send_u8(os, 0);
++ test_send_u8(os, 8);
++ test_send_u8(os, 16);
++
++ guint8 pad[3] = {0};
++ test_send_bytes(os, pad, G_N_ELEMENTS(pad));
++
++ /* name */
++ guint8 name[] = { 'T', 'e', 's', 't' };
++ test_send_u32(os, G_N_ELEMENTS(name));
++ test_send_bytes(os, name, G_N_ELEMENTS(name));
++}
++
++static void test_rre_bounds_server(GInputStream *is, GOutputStream *os)
++{
++ test_common_bounds_server(is, os);
++
++ /* Message type & pad */
++ test_send_u8(os, 0);
++ test_send_u8(os, 0);
++
++ /* num rect */
++ test_send_u16(os, 1);
++ /* x, y, w, h */
++ test_send_u16(os, 90);
++ test_send_u16(os, 90);
++ test_send_u16(os, 10);
++ test_send_u16(os, 10);
++
++ /* encoding=rre */
++ test_send_s32(os, 2);
++
++ /* num rect */
++ test_send_u32(os, 1);
++
++ /* bg pix, fg pix */
++ test_send_u32(os, 0x41414141);
++ test_send_u32(os, 0x42424242);
++
++ /* x, y, w, h */
++ test_send_u16(os, 10);
++ test_send_u16(os, 10000);
++ test_send_u16(os, 1);
++ test_send_u16(os, 1);
++}
++
++
++static void test_hextile_bounds_server(GInputStream *is, GOutputStream *os)
++{
++ test_common_bounds_server(is, os);
++
++ /* Message type & pad */
++ test_send_u8(os, 0);
++ test_send_u8(os, 0);
++
++ /* num rect */
++ test_send_u16(os, 1);
++ /* x, y, w, h */
++ test_send_u16(os, 90);
++ test_send_u16(os, 90);
++ test_send_u16(os, 10);
++ test_send_u16(os, 10);
++
++ /* encoding=hextile */
++ test_send_s32(os, 5);
++
++ /* tile type */
++ test_send_u8(os, 0x18);
++
++ /* num rect */
++ test_send_u8(os, 1);
++
++ /* fg pix */
++ test_send_u32(os, 0x12345678);
++
++ /* x, y */
++ test_send_u8(os, 0xff);
++ test_send_u8(os, 0xff);
++}
++
++
++static void test_copyrect_bounds_server(GInputStream *is, GOutputStream *os)
++{
++ test_common_bounds_server(is, os);
++
++ /* Message type & pad */
++ test_send_u8(os, 0);
++ test_send_u8(os, 0);
++
++ /* num rect */
++ test_send_u16(os, 1);
++ /* x, y, w, h */
++ test_send_u16(os, 90);
++ test_send_u16(os, 90);
++ test_send_u16(os, 10);
++ test_send_u16(os, 10);
++
++ /* encoding=copyrect */
++ test_send_s32(os, 1);
++
++ /* src x, y */
++ test_send_u16(os, 91);
++ test_send_u16(os, 91);
++}
++
++
++static void test_validation(void (*test_func)(GInputStream *, GOutputStream *))
++{
++ struct GVncTest *test;
++ char *port;
++ GMainLoop *loop;
++ GThread *th;
++
++ test = g_new0(struct GVncTest, 1);
++ test->test_func = test_func;
++
++ g_mutex_init(&test->lock);
++ g_mutex_init(&test->clock);
++ g_cond_init(&test->cond);
++ g_mutex_lock(&test->lock);
++
++ loop = g_main_loop_new(g_main_context_default(), FALSE);
++
++ th = g_thread_new("rre-server", test_helper_server, test);
++
++ g_mutex_lock(&test->lock);
++ port = g_strdup_printf("%d", test->port);
++
++ test->conn = vnc_connection_new();
++
++ g_signal_connect(test->conn, "vnc-initialized",
++ G_CALLBACK(test_helper_initialized), test);
++ g_signal_connect(test->conn, "vnc-disconnected",
++ G_CALLBACK(test_helper_disconnected), test);
++ g_signal_connect(test->conn, "vnc-auth-choose-type",
++ G_CALLBACK(test_helper_auth_choose_type), test);
++ g_signal_connect(test->conn, "vnc-desktop-resize",
++ G_CALLBACK(test_helper_desktop_resize), test);
++ g_signal_connect(test->conn, "vnc-error",
++ G_CALLBACK(test_helper_error), test);
++
++ vnc_connection_open_host(test->conn, "127.0.0.1", port);
++
++ test->loop = g_main_loop_new(g_main_context_default(), FALSE);
++
++ g_main_loop_run(test->loop);
++
++ g_mutex_lock(&test->clock);
++ test->quit = TRUE;
++ g_mutex_unlock(&test->clock);
++ g_cond_signal(&test->cond);
++
++ g_thread_join(th);
++
++ vnc_connection_shutdown(test->conn);
++ g_object_unref(test->conn);
++ g_free(test->pixels);
++ g_main_loop_unref(test->loop);
++
++ g_assert(test->error);
++ if (debug)
++ g_printerr("Got err %s\n", test->error);
++ g_free(test->error);
++
++ g_free(port);
++ g_free(test);
++}
++
++static void test_validation_rre(void)
++{
++ test_validation(test_rre_bounds_server);
++}
++
++static void test_validation_hextile(void)
++{
++ test_validation(test_hextile_bounds_server);
++}
++
++static void test_validation_copyrect(void)
++{
++ test_validation(test_copyrect_bounds_server);
++}
++#endif
++
++int main(int argc, char **argv) {
++ g_test_init(&argc, &argv, NULL);
++
++ if (getenv("GTK_VNC_DEBUG")) {
++ debug = TRUE;
++ vnc_util_set_debug(TRUE);
++ }
++
++#if GLIB_CHECK_VERSION(2, 22, 0)
++ g_test_add_func("/conn/validation/rre", test_validation_rre);
++ g_test_add_func("/conn/validation/copyrect", test_validation_copyrect);
++ g_test_add_func("/conn/validation/hextile", test_validation_hextile);
++#endif
++
++ return g_test_run();
++}
++/*
++ * Local variables:
++ * c-indent-level: 4
++ * c-basic-offset: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
diff --git a/debian/patches/series b/debian/patches/series
index 5620351..6af8186 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,2 +1,6 @@
Remove-GNUmakefile-links.patch
-Add-m4.patch
+Add-I-m4-to-Makefile.am.patch
+security/Fix-bounds-checking-for-RRE-hextile-copyrect-encodings.patch
+security/Don-t-accept-color-map-entries-for-true-color-pixel-forma.patch
+security/Correctly-validate-color-map-range-indexes.patch
+Link-against-GIO_LIBS-explicitly.patch
Reply to: