File gtk-vnc-CVE-2017-5885.patch of Package gtk-vnc.20718
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 39f1966..efd1517 100644
--- a/src/vncconnection.c
+++ b/src/vncconnection.c
@@ -3339,8 +3339,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;
@@ -3348,9 +3353,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 7ae7265..a4ea9eb 100644
--- a/src/vncconnectiontest.c
+++ b/src/vncconnectiontest.c
@@ -88,6 +88,21 @@ 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)
{
@@ -136,6 +151,8 @@ static gpointer test_helper_server(gpointer opaque)
}
g_object_unref(client);
+
+ return NULL;
}
static void test_helper_desktop_resize(VncConnection *conn,
@@ -359,6 +376,76 @@ static void test_copyrect_bounds_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;
@@ -435,6 +522,11 @@ static void test_validation_copyrect(void)
{
test_validation(test_copyrect_bounds_server);
}
+
+static void test_validation_overflow_cmap(void)
+{
+ test_validation(test_overflow_cmap_server);
+}
#endif
int main(int argc, char **argv) {
@@ -449,6 +541,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/overflowcmap", test_validation_overflow_cmap);
#endif
return g_test_run();