mirror of
https://github.com/postgres/postgres.git
synced 2025-05-03 22:24:49 +03:00
Backpatch Zdenek Kotala's fix to prevent pglz_decompress from stomping on
memory if the compressed data is corrupt. Backpatch as far as 8.2. The issue exists in older branches too, but given the lack of field reports, it's not clear it's worth any additional effort to adapt the patch to the slightly different code in older branches.
This commit is contained in:
parent
85a24f0dd9
commit
f26cbcab75
@ -166,7 +166,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 1999-2008, PostgreSQL Global Development Group
|
* Copyright (c) 1999-2008, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/adt/pg_lzcompress.c,v 1.29 2008/01/01 19:45:52 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/adt/pg_lzcompress.c,v 1.29.2.1 2008/05/28 21:58:03 tgl Exp $
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
@ -631,26 +631,26 @@ pglz_compress(const char *source, int32 slen, PGLZ_Header *dest,
|
|||||||
void
|
void
|
||||||
pglz_decompress(const PGLZ_Header *source, char *dest)
|
pglz_decompress(const PGLZ_Header *source, char *dest)
|
||||||
{
|
{
|
||||||
const unsigned char *dp;
|
const unsigned char *sp;
|
||||||
const unsigned char *dend;
|
const unsigned char *srcend;
|
||||||
unsigned char *bp;
|
unsigned char *dp;
|
||||||
unsigned char ctrl;
|
unsigned char *destend;
|
||||||
int32 ctrlc;
|
|
||||||
int32 len;
|
|
||||||
int32 off;
|
|
||||||
int32 destsize;
|
|
||||||
|
|
||||||
dp = ((const unsigned char *) source) + sizeof(PGLZ_Header);
|
sp = ((const unsigned char *) source) + sizeof(PGLZ_Header);
|
||||||
dend = ((const unsigned char *) source) + VARSIZE(source);
|
srcend = ((const unsigned char *) source) + VARSIZE(source);
|
||||||
bp = (unsigned char *) dest;
|
dp = (unsigned char *) dest;
|
||||||
|
destend = dp + source->rawsize;
|
||||||
|
|
||||||
while (dp < dend)
|
while (sp < srcend && dp < destend)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Read one control byte and process the next 8 items.
|
* Read one control byte and process the next 8 items (or as many
|
||||||
|
* as remain in the compressed input).
|
||||||
*/
|
*/
|
||||||
ctrl = *dp++;
|
unsigned char ctrl = *sp++;
|
||||||
for (ctrlc = 0; ctrlc < 8 && dp < dend; ctrlc++)
|
int ctrlc;
|
||||||
|
|
||||||
|
for (ctrlc = 0; ctrlc < 8 && sp < srcend; ctrlc++)
|
||||||
{
|
{
|
||||||
if (ctrl & 1)
|
if (ctrl & 1)
|
||||||
{
|
{
|
||||||
@ -661,11 +661,27 @@ pglz_decompress(const PGLZ_Header *source, char *dest)
|
|||||||
* coded as 18, another extension tag byte tells how much
|
* coded as 18, another extension tag byte tells how much
|
||||||
* longer the match really was (0-255).
|
* longer the match really was (0-255).
|
||||||
*/
|
*/
|
||||||
len = (dp[0] & 0x0f) + 3;
|
int32 len;
|
||||||
off = ((dp[0] & 0xf0) << 4) | dp[1];
|
int32 off;
|
||||||
dp += 2;
|
|
||||||
|
len = (sp[0] & 0x0f) + 3;
|
||||||
|
off = ((sp[0] & 0xf0) << 4) | sp[1];
|
||||||
|
sp += 2;
|
||||||
if (len == 18)
|
if (len == 18)
|
||||||
len += *dp++;
|
len += *sp++;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check for output buffer overrun, to ensure we don't
|
||||||
|
* clobber memory in case of corrupt input. Note: we must
|
||||||
|
* advance dp here to ensure the error is detected below
|
||||||
|
* the loop. We don't simply put the elog inside the loop
|
||||||
|
* since that will probably interfere with optimization.
|
||||||
|
*/
|
||||||
|
if (dp + len > destend)
|
||||||
|
{
|
||||||
|
dp += len;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now we copy the bytes specified by the tag from OUTPUT to
|
* Now we copy the bytes specified by the tag from OUTPUT to
|
||||||
@ -675,8 +691,8 @@ pglz_decompress(const PGLZ_Header *source, char *dest)
|
|||||||
*/
|
*/
|
||||||
while (len--)
|
while (len--)
|
||||||
{
|
{
|
||||||
*bp = bp[-off];
|
*dp = dp[-off];
|
||||||
bp++;
|
dp++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -685,7 +701,10 @@ pglz_decompress(const PGLZ_Header *source, char *dest)
|
|||||||
* An unset control bit means LITERAL BYTE. So we just copy
|
* An unset control bit means LITERAL BYTE. So we just copy
|
||||||
* one from INPUT to OUTPUT.
|
* one from INPUT to OUTPUT.
|
||||||
*/
|
*/
|
||||||
*bp++ = *dp++;
|
if (dp >= destend) /* check for buffer overrun */
|
||||||
|
break; /* do not clobber memory */
|
||||||
|
|
||||||
|
*dp++ = *sp++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -696,14 +715,10 @@ pglz_decompress(const PGLZ_Header *source, char *dest)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check we decompressed the right amount, else die. This is a FATAL
|
* Check we decompressed the right amount.
|
||||||
* condition if we tromped on more memory than expected (we assume we have
|
|
||||||
* not tromped on shared memory, though, so need not PANIC).
|
|
||||||
*/
|
*/
|
||||||
destsize = (char *) bp - dest;
|
if (dp != destend || sp != srcend)
|
||||||
if (destsize != source->rawsize)
|
elog(ERROR, "compressed data is corrupt");
|
||||||
elog(destsize > source->rawsize ? FATAL : ERROR,
|
|
||||||
"compressed data is corrupt");
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* That's it.
|
* That's it.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user