Karsten Desler wrote:

I don't know much about the postgres architecture and I don't know if bounds
checking on-disk values on a read makes a lot of sense since usually one
should be able to assume that there are no randomly flipped bits; but it
would've been nice to have a sensible log entry as to what really
happened.

I attached backported patch from head to 8.2. You can try it. It has small performance penalty, but it does not crash on corrupted data.

                Zdenek
*** src/backend/utils/adt/pg_lzcompress.c	2006/10/05 23:33:33	1.23
--- src/backend/utils/adt/pg_lzcompress.c	2008/03/08 01:09:36	1.31
*************** pglz_compress(const char *source, int32 
*** 631,656 ****
  void
  pglz_decompress(const PGLZ_Header *source, char *dest)
  {
! 	const unsigned char *dp;
! 	const unsigned char *dend;
! 	unsigned char *bp;
! 	unsigned char ctrl;
! 	int32		ctrlc;
! 	int32		len;
! 	int32		off;
! 	int32		destsize;
! 
! 	dp = ((const unsigned char *) source) + sizeof(PGLZ_Header);
! 	dend = ((const unsigned char *) source) + VARATT_SIZE(source);
! 	bp = (unsigned char *) dest;
  
! 	while (dp < dend)
  	{
  		/*
! 		 * Read one control byte and process the next 8 items.
  		 */
! 		ctrl = *dp++;
! 		for (ctrlc = 0; ctrlc < 8 && dp < dend; ctrlc++)
  		{
  			if (ctrl & 1)
  			{
--- 641,666 ----
  void
  pglz_decompress(const PGLZ_Header *source, char *dest)
  {
! 	const unsigned char *sp;
! 	const unsigned char *srcend;
! 	unsigned char *dp;
! 	unsigned char *destend;
! 
! 	sp = ((const unsigned char *) source) + sizeof(PGLZ_Header);
! 	srcend = ((const unsigned char *) source) + VARATT_SIZE(source);
! 	dp = (unsigned char *) dest;
! 	destend = dp + source->rawsize;
  
! 	while (sp < srcend && dp < destend)
  	{
  		/*
! 		 * Read one control byte and process the next 8 items (or as many
! 		 * as remain in the compressed input).
  		 */
! 		unsigned char ctrl = *sp++;
! 		int		ctrlc;
! 
! 		for (ctrlc = 0; ctrlc < 8 && sp < srcend; ctrlc++)
  		{
  			if (ctrl & 1)
  			{
*************** pglz_decompress(const PGLZ_Header *sourc
*** 661,671 ****
  				 * coded as 18, another extension tag byte tells how much
  				 * longer the match really was (0-255).
  				 */
! 				len = (dp[0] & 0x0f) + 3;
! 				off = ((dp[0] & 0xf0) << 4) | dp[1];
! 				dp += 2;
  				if (len == 18)
! 					len += *dp++;
  
  				/*
  				 * Now we copy the bytes specified by the tag from OUTPUT to
--- 671,697 ----
  				 * coded as 18, another extension tag byte tells how much
  				 * longer the match really was (0-255).
  				 */
! 				int32		len;
! 				int32		off;
! 
! 				len = (sp[0] & 0x0f) + 3;
! 				off = ((sp[0] & 0xf0) << 4) | sp[1];
! 				sp += 2;
  				if (len == 18)
! 					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
*************** pglz_decompress(const PGLZ_Header *sourc
*** 675,682 ****
  				 */
  				while (len--)
  				{
! 					*bp = bp[-off];
! 					bp++;
  				}
  			}
  			else
--- 701,708 ----
  				 */
  				while (len--)
  				{
! 					*dp = dp[-off];
! 					dp++;
  				}
  			}
  			else
*************** pglz_decompress(const PGLZ_Header *sourc
*** 685,691 ****
  				 * An unset control bit means LITERAL BYTE. So we just copy
  				 * one from INPUT to OUTPUT.
  				 */
! 				*bp++ = *dp++;
  			}
  
  			/*
--- 711,720 ----
  				 * An unset control bit means LITERAL BYTE. So we just copy
  				 * one from INPUT to OUTPUT.
  				 */
! 				if (dp >= destend)	/* check for buffer overrun */
! 					break;			/* do not clobber memory */
! 
! 				*dp++ = *sp++;
  			}
  
  			/*
*************** pglz_decompress(const PGLZ_Header *sourc
*** 696,709 ****
  	}
  
  	/*
! 	 * Check we decompressed the right amount, else die.  This is a FATAL
! 	 * 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 (destsize != source->rawsize)
! 		elog(destsize > source->rawsize ? FATAL : ERROR,
! 			 "compressed data is corrupt");
  
  	/*
  	 * That's it.
--- 725,734 ----
  	}
  
  	/*
! 	 * Check we decompressed the right amount.
! 	 */
! 	if (dp != destend || sp != srcend)
! 		elog(ERROR, "compressed data is corrupt");
  
  	/*
  	 * That's it.
-- 
Sent via pgsql-bugs mailing list (pgsql-bugs@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-bugs

Reply via email to