mirror of
https://github.com/postgres/postgres.git
synced 2026-05-28 04:35:45 -04:00
Fix heap-buffer-overflow in pglz_decompress() on corrupt input.
When decoding a match tag, pglz_decompress() reads 2 bytes (or 3 for extended-length matches) from the source buffer before checking whether enough data remains. The existing bounds check (sp > srcend) occurs after the reads, so truncated compressed data that ends mid-tag causes a read past the allocated buffer. Fix by validating that sufficient source bytes are available before reading each part of the match tag. The post-read sp > srcend check is no longer needed and is removed. Found by fuzz testing with libFuzzer and AddressSanitizer.
This commit is contained in:
parent
2478bd5db0
commit
2b5ba2a0a1
1 changed files with 19 additions and 8 deletions
|
|
@ -727,22 +727,33 @@ pglz_decompress(const char *source, int32 slen, char *dest,
|
||||||
int32 len;
|
int32 len;
|
||||||
int32 off;
|
int32 off;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A match tag is at least 2 bytes; if the length nibble is
|
||||||
|
* 0x0f the tag is 3 bytes (extended length). Verify we have
|
||||||
|
* enough source data before reading them.
|
||||||
|
*/
|
||||||
|
if (unlikely(sp + 2 > srcend))
|
||||||
|
return -1;
|
||||||
|
|
||||||
len = (sp[0] & 0x0f) + 3;
|
len = (sp[0] & 0x0f) + 3;
|
||||||
off = ((sp[0] & 0xf0) << 4) | sp[1];
|
off = ((sp[0] & 0xf0) << 4) | sp[1];
|
||||||
sp += 2;
|
sp += 2;
|
||||||
if (len == 18)
|
if (len == 18)
|
||||||
|
{
|
||||||
|
if (unlikely(sp >= srcend))
|
||||||
|
return -1;
|
||||||
len += *sp++;
|
len += *sp++;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for corrupt data: if we fell off the end of the
|
* Check for corrupt data: if we obtained off = 0, or if off
|
||||||
* source, or if we obtained off = 0, or if off is more than
|
* is more than the distance back to the buffer start, we have
|
||||||
* the distance back to the buffer start, we have problems.
|
* problems. (We must check for off = 0, else we risk an
|
||||||
* (We must check for off = 0, else we risk an infinite loop
|
* infinite loop below in the face of corrupt data. Likewise,
|
||||||
* below in the face of corrupt data. Likewise, the upper
|
* the upper limit on off prevents accessing outside the
|
||||||
* limit on off prevents accessing outside the buffer
|
* buffer boundaries.)
|
||||||
* boundaries.)
|
|
||||||
*/
|
*/
|
||||||
if (unlikely(sp > srcend || off == 0 ||
|
if (unlikely(off == 0 ||
|
||||||
off > (dp - (unsigned char *) dest)))
|
off > (dp - (unsigned char *) dest)))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue