From 009008e2f4d5a54dd71f422070df3af7b3dbc931 Mon Sep 17 00:00:00 2001 From: Kazuma Matsumoto <269371721+y637F9QQ2x@users.noreply.github.com> Date: Sun, 22 Mar 2026 20:35:49 +0100 Subject: [PATCH] libvncclient: add bounds checks to UltraZip subrectangle parsing HandleUltraZipBPP() iterates over sub-rectangles using numCacheRects (derived from the attacker-controlled rect.r.x) without validating that the pointer stays within the decompressed data buffer. A malicious server can set a large numCacheRects value, causing heap out-of-bounds reads via the memcpy calls in the parsing loop. Add bounds checks before reading the 12-byte subrect header and before advancing the pointer by the raw pixel data size. Use uint64_t for the raw data size calculation to prevent integer overflow on 32-bit platforms. Upstream: https://github.com/LibVNC/libvncserver/commit/009008e2f4d5a54dd71f422070df3af7b3dbc931 CVE: CVE-2026-32853 Signed-off-by: Thomas Perale --- libvncclient/ultra.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/libvncclient/ultra.c b/libvncclient/ultra.c index 1d3aaba6a..5633b8cbb 100644 --- a/libvncclient/ultra.c +++ b/libvncclient/ultra.c @@ -126,6 +126,7 @@ HandleUltraZipBPP (rfbClient* client, int rx, int ry, int rw, int rh) int toRead=0; int inflateResult=0; unsigned char *ptr=NULL; + unsigned char *ptr_end=NULL; lzo_uint uncompressedBytes = ry + (rw * 65535); unsigned int numCacheRects = rx; @@ -194,11 +195,18 @@ HandleUltraZipBPP (rfbClient* client, int rx, int ry, int rw, int rh) /* Put the uncompressed contents of the update on the screen. */ ptr = (unsigned char *)client->raw_buffer; + ptr_end = ptr + uncompressedBytes; for (i=0; i ptr_end) { + rfbClientLog("UltraZip: subrect %d header exceeds decompressed data bounds\n", i); + return FALSE; + } + memcpy((char *)&sx, ptr, 2); ptr += 2; memcpy((char *)&sy, ptr, 2); ptr += 2; memcpy((char *)&sw, ptr, 2); ptr += 2; @@ -213,8 +221,13 @@ HandleUltraZipBPP (rfbClient* client, int rx, int ry, int rw, int rh) if (se == rfbEncodingRaw) { + uint64_t rawBytes = (uint64_t)sw * sh * (BPP / 8); + if (rawBytes > (size_t)(ptr_end - ptr)) { + rfbClientLog("UltraZip: subrect %d raw data exceeds decompressed data bounds\n", i); + return FALSE; + } client->GotBitmap(client, (unsigned char *)ptr, sx, sy, sw, sh); - ptr += ((sw * sh) * (BPP / 8)); + ptr += (size_t)rawBytes; } } @@ -222,3 +235,4 @@ HandleUltraZipBPP (rfbClient* client, int rx, int ry, int rw, int rh) } #undef CARDBPP +