9ae3a8
From 023a741e196fd99b532f69df9560730425b174a0 Mon Sep 17 00:00:00 2001
9ae3a8
From: "Daniel P. Berrange" <berrange@redhat.com>
9ae3a8
Date: Thu, 8 Feb 2018 17:50:39 +0100
9ae3a8
Subject: [PATCH 25/27] ui: avoid sign extension using client width/height
9ae3a8
9ae3a8
RH-Author: Daniel P. Berrange <berrange@redhat.com>
9ae3a8
Message-id: <20180208175041.5634-26-berrange@redhat.com>
9ae3a8
Patchwork-id: 78960
9ae3a8
O-Subject: [RHEL-7.5 qemu-kvm PATCH v1 25/27] ui: avoid sign extension using client width/height
9ae3a8
Bugzilla: 1527405
9ae3a8
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
9ae3a8
RH-Acked-by: Gerd Hoffmann <kraxel@redhat.com>
9ae3a8
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
9ae3a8
From: "Daniel P. Berrange" <berrange@redhat.com>
9ae3a8
9ae3a8
Pixman returns a signed int for the image width/height, but the VNC
9ae3a8
protocol only permits a unsigned int16. Effective framebuffer size
9ae3a8
is determined by the guest, limited by the video RAM size, so the
9ae3a8
dimensions are unlikely to exceed the range of an unsigned int16,
9ae3a8
but this is not currently validated.
9ae3a8
9ae3a8
With the current use of 'int' for client width/height, the calculation
9ae3a8
of offsets in vnc_update_throttle_offset() suffers from integer size
9ae3a8
promotion and sign extension, causing coverity warnings
9ae3a8
9ae3a8
*** CID 1385147:  Integer handling issues  (SIGN_EXTENSION)
9ae3a8
/ui/vnc.c: 979 in vnc_update_throttle_offset()
9ae3a8
973      * than that the client would already suffering awful audio
9ae3a8
974      * glitches, so dropping samples is no worse really).
9ae3a8
975      */
9ae3a8
976     static void vnc_update_throttle_offset(VncState *vs)
9ae3a8
977     {
9ae3a8
978         size_t offset =
9ae3a8
>>>     CID 1385147:  Integer handling issues  (SIGN_EXTENSION)
9ae3a8
>>>     Suspicious implicit sign extension:
9ae3a8
    "vs->client_pf.bytes_per_pixel" with type "unsigned char" (8 bits,
9ae3a8
    unsigned) is promoted in "vs->client_width * vs->client_height *
9ae3a8
    vs->client_pf.bytes_per_pixel" to type "int" (32 bits, signed), then
9ae3a8
    sign-extended to type "unsigned long" (64 bits, unsigned).  If
9ae3a8
    "vs->client_width * vs->client_height * vs->client_pf.bytes_per_pixel"
9ae3a8
    is greater than 0x7FFFFFFF, the upper bits of the result will all be 1.
9ae3a8
979             vs->client_width * vs->client_height * vs->client_pf.bytes_per_pixel;
9ae3a8
9ae3a8
Change client_width / client_height to be a size_t to avoid sign
9ae3a8
extension and integer promotion. Then validate that dimensions are in
9ae3a8
range wrt the RFB protocol u16 limits.
9ae3a8
9ae3a8
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
9ae3a8
Message-id: 20180118155254.17053-1-berrange@redhat.com
9ae3a8
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
9ae3a8
(cherry picked from commit 4c956bd81e2e16afd19d38d1fdeba6d9faa8a1ae)
9ae3a8
9ae3a8
 Conflicts:
9ae3a8
	ui/vnc.c
9ae3a8
	ui/vnc.h - context differences
9ae3a8
9ae3a8
RHEL-7 note: The context difference in VncState is because downstream
9ae3a8
lacks commit 14768eba46e4 ("input: mouse: switch vnc ui to new core",
9ae3a8
2014-03-05), part of v2.0.0. The context difference in
9ae3a8
protocol_client_init() is because downstream lacks e5f34cdd2da5 ("vnc:
9ae3a8
track & limit connections", 2015-01-22), part of v2.3.0. Neither
9ae3a8
upstream commit is necessary for this backport.
9ae3a8
9ae3a8
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
---
9ae3a8
 ui/vnc.c | 9 +++++++++
9ae3a8
 ui/vnc.h | 4 ++--
9ae3a8
 2 files changed, 11 insertions(+), 2 deletions(-)
9ae3a8
9ae3a8
diff --git a/ui/vnc.c b/ui/vnc.c
9ae3a8
index 61fbec2..2be87b8 100644
9ae3a8
--- a/ui/vnc.c
9ae3a8
+++ b/ui/vnc.c
9ae3a8
@@ -570,6 +570,11 @@ static void vnc_desktop_resize(VncState *vs)
9ae3a8
         vs->client_height == pixman_image_get_height(vs->vd->server)) {
9ae3a8
         return;
9ae3a8
     }
9ae3a8
+
9ae3a8
+    assert(pixman_image_get_width(vs->vd->server) < 65536 &&
9ae3a8
+           pixman_image_get_width(vs->vd->server) >= 0);
9ae3a8
+    assert(pixman_image_get_height(vs->vd->server) < 65536 &&
9ae3a8
+           pixman_image_get_height(vs->vd->server) >= 0);
9ae3a8
     vs->client_width = pixman_image_get_width(vs->vd->server);
9ae3a8
     vs->client_height = pixman_image_get_height(vs->vd->server);
9ae3a8
     vnc_lock_output(vs);
9ae3a8
@@ -2387,6 +2392,10 @@ static int protocol_client_init(VncState *vs, uint8_t *data, size_t len)
9ae3a8
     }
9ae3a8
     vnc_set_share_mode(vs, mode);
9ae3a8
 
9ae3a8
+    assert(pixman_image_get_width(vs->vd->server) < 65536 &&
9ae3a8
+           pixman_image_get_width(vs->vd->server) >= 0);
9ae3a8
+    assert(pixman_image_get_height(vs->vd->server) < 65536 &&
9ae3a8
+           pixman_image_get_height(vs->vd->server) >= 0);
9ae3a8
     vs->client_width = pixman_image_get_width(vs->vd->server);
9ae3a8
     vs->client_height = pixman_image_get_height(vs->vd->server);
9ae3a8
     vnc_write_u16(vs, vs->client_width);
9ae3a8
diff --git a/ui/vnc.h b/ui/vnc.h
9ae3a8
index 70316ba..f9c5f89 100644
9ae3a8
--- a/ui/vnc.h
9ae3a8
+++ b/ui/vnc.h
9ae3a8
@@ -274,8 +274,8 @@ struct VncState
9ae3a8
     int absolute;
9ae3a8
     int last_x;
9ae3a8
     int last_y;
9ae3a8
-    int client_width;
9ae3a8
-    int client_height;
9ae3a8
+    size_t client_width; /* limited to u16 by RFB proto */
9ae3a8
+    size_t client_height; /* limited to u16 by RFB proto */
9ae3a8
     VncShareMode share_mode;
9ae3a8
 
9ae3a8
     uint32_t vnc_encoding;
9ae3a8
-- 
9ae3a8
1.8.3.1
9ae3a8