Skip to content

Commit 009008e

Browse files
y637F9QQ2xbk138
authored andcommitted
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.
1 parent dc78dee commit 009008e

File tree

1 file changed

+15
-1
lines changed

1 file changed

+15
-1
lines changed

src/libvncclient/ultra.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ HandleUltraZipBPP (rfbClient* client, int rx, int ry, int rw, int rh)
126126
int toRead=0;
127127
int inflateResult=0;
128128
unsigned char *ptr=NULL;
129+
unsigned char *ptr_end=NULL;
129130
lzo_uint uncompressedBytes = ry + (rw * 65535);
130131
unsigned int numCacheRects = rx;
131132

@@ -194,11 +195,18 @@ HandleUltraZipBPP (rfbClient* client, int rx, int ry, int rw, int rh)
194195

195196
/* Put the uncompressed contents of the update on the screen. */
196197
ptr = (unsigned char *)client->raw_buffer;
198+
ptr_end = ptr + uncompressedBytes;
197199
for (i=0; i<numCacheRects; i++)
198200
{
199201
unsigned short sx, sy, sw, sh;
200202
unsigned int se;
201203

204+
/* subrect header: sx(2) + sy(2) + sw(2) + sh(2) + se(4) = 12 bytes */
205+
if (ptr + 12 > ptr_end) {
206+
rfbClientLog("UltraZip: subrect %d header exceeds decompressed data bounds\n", i);
207+
return FALSE;
208+
}
209+
202210
memcpy((char *)&sx, ptr, 2); ptr += 2;
203211
memcpy((char *)&sy, ptr, 2); ptr += 2;
204212
memcpy((char *)&sw, ptr, 2); ptr += 2;
@@ -213,12 +221,18 @@ HandleUltraZipBPP (rfbClient* client, int rx, int ry, int rw, int rh)
213221

214222
if (se == rfbEncodingRaw)
215223
{
224+
uint64_t rawBytes = (uint64_t)sw * sh * (BPP / 8);
225+
if (rawBytes > (size_t)(ptr_end - ptr)) {
226+
rfbClientLog("UltraZip: subrect %d raw data exceeds decompressed data bounds\n", i);
227+
return FALSE;
228+
}
216229
client->GotBitmap(client, (unsigned char *)ptr, sx, sy, sw, sh);
217-
ptr += ((sw * sh) * (BPP / 8));
230+
ptr += (size_t)rawBytes;
218231
}
219232
}
220233

221234
return TRUE;
222235
}
223236

224237
#undef CARDBPP
238+

0 commit comments

Comments
 (0)