Package: release.debian.org Severity: normal User: release.debian....@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 <a...@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 <eribe...@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 <eribe...@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?= <a...@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" <berra...@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 <berra...@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" <berra...@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 <berra...@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" <berra...@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 <berra...@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 <anth...@codemonkey.ws> ++ * Copyright (C) 2009-2010 Daniel P. Berrange <d...@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