mirror of
				https://github.com/facebook/zstd.git
				synced 2025-10-31 08:37:43 +02:00 
			
		
		
		
	[legacy] Fix ZSTDv0*_decodeSequence()
* Version <= 0.5 could read beyond the end of `dumps`, which points into the input buffer. * Check the validity of `dumps` before using it, if it is out of bounds return garbage values. There is no return code for this function. * Introduce `MEM_readLE24()` for simplicity, since I don't want to trust that there is an extra byte after `dumps`.
This commit is contained in:
		| @@ -1358,8 +1358,6 @@ static unsigned ZSTD_isLittleEndian(void) | |||||||
|  |  | ||||||
| static U16    ZSTD_read16(const void* p) { U16 r; memcpy(&r, p, sizeof(r)); return r; } | static U16    ZSTD_read16(const void* p) { U16 r; memcpy(&r, p, sizeof(r)); return r; } | ||||||
|  |  | ||||||
| static U32    ZSTD_read32(const void* p) { U32 r; memcpy(&r, p, sizeof(r)); return r; } |  | ||||||
|  |  | ||||||
| static void   ZSTD_copy4(void* dst, const void* src) { memcpy(dst, src, 4); } | static void   ZSTD_copy4(void* dst, const void* src) { memcpy(dst, src, 4); } | ||||||
|  |  | ||||||
| static void   ZSTD_copy8(void* dst, const void* src) { memcpy(dst, src, 8); } | static void   ZSTD_copy8(void* dst, const void* src) { memcpy(dst, src, 8); } | ||||||
| @@ -1384,16 +1382,9 @@ static U16 ZSTD_readLE16(const void* memPtr) | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static U32 ZSTD_readLE24(const void* memPtr) | ||||||
| static U32 ZSTD_readLE32(const void* memPtr) |  | ||||||
| { | { | ||||||
|     if (ZSTD_isLittleEndian()) |     return ZSTD_readLE16(memPtr) + (((const BYTE*)memPtr)[2] << 16); | ||||||
|         return ZSTD_read32(memPtr); |  | ||||||
|     else |  | ||||||
|     { |  | ||||||
|         const BYTE* p = (const BYTE*)memPtr; |  | ||||||
|         return (U32)((U32)p[0] + ((U32)p[1]<<8) + ((U32)p[2]<<16) + ((U32)p[3]<<24)); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| static U32 ZSTD_readBE32(const void* memPtr) | static U32 ZSTD_readBE32(const void* memPtr) | ||||||
| @@ -1707,13 +1698,13 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState) | |||||||
|     seqState->prevOffset = seq->offset; |     seqState->prevOffset = seq->offset; | ||||||
|     if (litLength == MaxLL) |     if (litLength == MaxLL) | ||||||
|     { |     { | ||||||
|         U32 add = dumps<de ? *dumps++ : 0; |         const U32 add = dumps<de ? *dumps++ : 0; | ||||||
|         if (add < 255) litLength += add; |         if (add < 255) litLength += add; | ||||||
|         else |         else | ||||||
|         { |         { | ||||||
|             if (dumps<=(de-3)) |             if (dumps<=(de-3)) | ||||||
|             { |             { | ||||||
|                 litLength = ZSTD_readLE32(dumps) & 0xFFFFFF;  /* no pb : dumps is always followed by seq tables > 1 byte */ |                 litLength = ZSTD_readLE24(dumps); | ||||||
|                 dumps += 3; |                 dumps += 3; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @@ -1735,13 +1726,13 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState) | |||||||
|     matchLength = FSE_decodeSymbol(&(seqState->stateML), &(seqState->DStream)); |     matchLength = FSE_decodeSymbol(&(seqState->stateML), &(seqState->DStream)); | ||||||
|     if (matchLength == MaxML) |     if (matchLength == MaxML) | ||||||
|     { |     { | ||||||
|         U32 add = dumps<de ? *dumps++ : 0; |         const U32 add = dumps<de ? *dumps++ : 0; | ||||||
|         if (add < 255) matchLength += add; |         if (add < 255) matchLength += add; | ||||||
|         else |         else | ||||||
|         { |         { | ||||||
|             if (dumps<=(de-3)) |             if (dumps<=(de-3)) | ||||||
|             { |             { | ||||||
|                 matchLength = ZSTD_readLE32(dumps) & 0xFFFFFF;  /* no pb : dumps is always followed by seq tables > 1 byte */ |                 matchLength = ZSTD_readLE24(dumps); | ||||||
|                 dumps += 3; |                 dumps += 3; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -217,6 +217,11 @@ MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val) | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | MEM_STATIC U32 MEM_readLE24(const void* memPtr) | ||||||
|  | { | ||||||
|  |     return MEM_readLE16(memPtr) + (((const BYTE*)memPtr)[2] << 16); | ||||||
|  | } | ||||||
|  |  | ||||||
| MEM_STATIC U32 MEM_readLE32(const void* memPtr) | MEM_STATIC U32 MEM_readLE32(const void* memPtr) | ||||||
| { | { | ||||||
|     if (MEM_isLittleEndian()) |     if (MEM_isLittleEndian()) | ||||||
| @@ -3043,11 +3048,11 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState) | |||||||
|     seqState->prevOffset = seq->offset; |     seqState->prevOffset = seq->offset; | ||||||
|     if (litLength == MaxLL) |     if (litLength == MaxLL) | ||||||
|     { |     { | ||||||
|         U32 add = *dumps++; |         const U32 add = dumps<de ? *dumps++ : 0; | ||||||
|         if (add < 255) litLength += add; |         if (add < 255) litLength += add; | ||||||
|         else |         else if (dumps + 3 <= de) | ||||||
|         { |         { | ||||||
|             litLength = MEM_readLE32(dumps) & 0xFFFFFF;  /* no pb : dumps is always followed by seq tables > 1 byte */ |             litLength = MEM_readLE24(dumps); | ||||||
|             dumps += 3; |             dumps += 3; | ||||||
|         } |         } | ||||||
|         if (dumps >= de) dumps = de-1;   /* late correction, to avoid read overflow (data is now corrupted anyway) */ |         if (dumps >= de) dumps = de-1;   /* late correction, to avoid read overflow (data is now corrupted anyway) */ | ||||||
| @@ -3073,11 +3078,11 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState) | |||||||
|     matchLength = FSE_decodeSymbol(&(seqState->stateML), &(seqState->DStream)); |     matchLength = FSE_decodeSymbol(&(seqState->stateML), &(seqState->DStream)); | ||||||
|     if (matchLength == MaxML) |     if (matchLength == MaxML) | ||||||
|     { |     { | ||||||
|         U32 add = *dumps++; |         const U32 add = dumps<de ? *dumps++ : 0; | ||||||
|         if (add < 255) matchLength += add; |         if (add < 255) matchLength += add; | ||||||
|         else |         else if (dumps + 3 <= de) | ||||||
|         { |         { | ||||||
|             matchLength = MEM_readLE32(dumps) & 0xFFFFFF;  /* no pb : dumps is always followed by seq tables > 1 byte */ |             matchLength = MEM_readLE24(dumps); | ||||||
|             dumps += 3; |             dumps += 3; | ||||||
|         } |         } | ||||||
|         if (dumps >= de) dumps = de-1;   /* late correction, to avoid read overflow (data is now corrupted anyway) */ |         if (dumps >= de) dumps = de-1;   /* late correction, to avoid read overflow (data is now corrupted anyway) */ | ||||||
|   | |||||||
| @@ -219,6 +219,11 @@ MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val) | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | MEM_STATIC U32 MEM_readLE24(const void* memPtr) | ||||||
|  | { | ||||||
|  |     return MEM_readLE16(memPtr) + (((const BYTE*)memPtr)[2] << 16); | ||||||
|  | } | ||||||
|  |  | ||||||
| MEM_STATIC U32 MEM_readLE32(const void* memPtr) | MEM_STATIC U32 MEM_readLE32(const void* memPtr) | ||||||
| { | { | ||||||
|     if (MEM_isLittleEndian()) |     if (MEM_isLittleEndian()) | ||||||
| @@ -2684,11 +2689,11 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState) | |||||||
|     seqState->prevOffset = seq->offset; |     seqState->prevOffset = seq->offset; | ||||||
|     if (litLength == MaxLL) |     if (litLength == MaxLL) | ||||||
|     { |     { | ||||||
|         U32 add = *dumps++; |         const U32 add = dumps<de ? *dumps++ : 0; | ||||||
|         if (add < 255) litLength += add; |         if (add < 255) litLength += add; | ||||||
|         else |         else if (dumps + 3 <= de) | ||||||
|         { |         { | ||||||
|             litLength = MEM_readLE32(dumps) & 0xFFFFFF;  /* no pb : dumps is always followed by seq tables > 1 byte */ |             litLength = MEM_readLE24(dumps); | ||||||
|             dumps += 3; |             dumps += 3; | ||||||
|         } |         } | ||||||
|         if (dumps >= de) dumps = de-1;   /* late correction, to avoid read overflow (data is now corrupted anyway) */ |         if (dumps >= de) dumps = de-1;   /* late correction, to avoid read overflow (data is now corrupted anyway) */ | ||||||
| @@ -2714,11 +2719,11 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState) | |||||||
|     matchLength = FSE_decodeSymbol(&(seqState->stateML), &(seqState->DStream)); |     matchLength = FSE_decodeSymbol(&(seqState->stateML), &(seqState->DStream)); | ||||||
|     if (matchLength == MaxML) |     if (matchLength == MaxML) | ||||||
|     { |     { | ||||||
|         U32 add = *dumps++; |         const U32 add = dumps<de ? *dumps++ : 0; | ||||||
|         if (add < 255) matchLength += add; |         if (add < 255) matchLength += add; | ||||||
|         else |         else if (dumps + 3 <= de) | ||||||
|         { |         { | ||||||
|             matchLength = MEM_readLE32(dumps) & 0xFFFFFF;  /* no pb : dumps is always followed by seq tables > 1 byte */ |             matchLength = MEM_readLE24(dumps); | ||||||
|             dumps += 3; |             dumps += 3; | ||||||
|         } |         } | ||||||
|         if (dumps >= de) dumps = de-1;   /* late correction, to avoid read overflow (data is now corrupted anyway) */ |         if (dumps >= de) dumps = de-1;   /* late correction, to avoid read overflow (data is now corrupted anyway) */ | ||||||
|   | |||||||
| @@ -189,6 +189,11 @@ MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val) | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | MEM_STATIC U32 MEM_readLE24(const void* memPtr) | ||||||
|  | { | ||||||
|  |     return MEM_readLE16(memPtr) + (((const BYTE*)memPtr)[2] << 16); | ||||||
|  | } | ||||||
|  |  | ||||||
| MEM_STATIC U32 MEM_readLE32(const void* memPtr) | MEM_STATIC U32 MEM_readLE32(const void* memPtr) | ||||||
| { | { | ||||||
|     if (MEM_isLittleEndian()) |     if (MEM_isLittleEndian()) | ||||||
| @@ -2808,13 +2813,12 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState) | |||||||
|     litLength = FSE_decodeSymbol(&(seqState->stateLL), &(seqState->DStream)); |     litLength = FSE_decodeSymbol(&(seqState->stateLL), &(seqState->DStream)); | ||||||
|     prevOffset = litLength ? seq->offset : seqState->prevOffset; |     prevOffset = litLength ? seq->offset : seqState->prevOffset; | ||||||
|     if (litLength == MaxLL) { |     if (litLength == MaxLL) { | ||||||
|         U32 add = *dumps++; |         const U32 add = dumps<de ? *dumps++ : 0; | ||||||
|         if (add < 255) litLength += add; |         if (add < 255) litLength += add; | ||||||
|         else { |         else if (dumps + 3 <= de) { | ||||||
|             litLength = dumps[0] + (dumps[1]<<8) + (dumps[2]<<16); |             litLength = MEM_readLE24(dumps); | ||||||
|             dumps += 3; |             dumps += 3; | ||||||
|         } |         } | ||||||
|         if (dumps > de) { litLength = MaxLL+255; }  /* late correction, to avoid using uninitialized memory */ |  | ||||||
|         if (dumps >= de) { dumps = de-1; }  /* late correction, to avoid read overflow (data is now corrupted anyway) */ |         if (dumps >= de) { dumps = de-1; }  /* late correction, to avoid read overflow (data is now corrupted anyway) */ | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -2837,13 +2841,12 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState) | |||||||
|     /* MatchLength */ |     /* MatchLength */ | ||||||
|     matchLength = FSE_decodeSymbol(&(seqState->stateML), &(seqState->DStream)); |     matchLength = FSE_decodeSymbol(&(seqState->stateML), &(seqState->DStream)); | ||||||
|     if (matchLength == MaxML) { |     if (matchLength == MaxML) { | ||||||
|         U32 add = *dumps++; |         const U32 add = dumps<de ? *dumps++ : 0; | ||||||
|         if (add < 255) matchLength += add; |         if (add < 255) matchLength += add; | ||||||
|         else { |         else if (dumps + 3 <= de){ | ||||||
|             matchLength = dumps[0] + (dumps[1]<<8) + (dumps[2]<<16); |             matchLength = MEM_readLE24(dumps); | ||||||
|             dumps += 3; |             dumps += 3; | ||||||
|         } |         } | ||||||
|         if (dumps > de) { matchLength = MaxML+255; }  /* late correction, to avoid using uninitialized memory */ |  | ||||||
|         if (dumps >= de) { dumps = de-1; }  /* late correction, to avoid read overflow (data is now corrupted anyway) */ |         if (dumps >= de) { dumps = de-1; }  /* late correction, to avoid read overflow (data is now corrupted anyway) */ | ||||||
|     } |     } | ||||||
|     matchLength += MINMATCH; |     matchLength += MINMATCH; | ||||||
|   | |||||||
| @@ -218,6 +218,11 @@ MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val) | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | MEM_STATIC U32 MEM_readLE24(const void* memPtr) | ||||||
|  | { | ||||||
|  |     return MEM_readLE16(memPtr) + (((const BYTE*)memPtr)[2] << 16); | ||||||
|  | } | ||||||
|  |  | ||||||
| MEM_STATIC U32 MEM_readLE32(const void* memPtr) | MEM_STATIC U32 MEM_readLE32(const void* memPtr) | ||||||
| { | { | ||||||
|     if (MEM_isLittleEndian()) |     if (MEM_isLittleEndian()) | ||||||
| @@ -3151,14 +3156,13 @@ static void ZSTDv05_decodeSequence(seq_t* seq, seqState_t* seqState) | |||||||
|     litLength = FSEv05_peakSymbol(&(seqState->stateLL)); |     litLength = FSEv05_peakSymbol(&(seqState->stateLL)); | ||||||
|     prevOffset = litLength ? seq->offset : seqState->prevOffset; |     prevOffset = litLength ? seq->offset : seqState->prevOffset; | ||||||
|     if (litLength == MaxLL) { |     if (litLength == MaxLL) { | ||||||
|         U32 add = *dumps++; |         const U32 add = *dumps++; | ||||||
|         if (add < 255) litLength += add; |         if (add < 255) litLength += add; | ||||||
|         else { |         else if (dumps + 3 <= de) { | ||||||
|             litLength = MEM_readLE32(dumps) & 0xFFFFFF;  /* no risk : dumps is always followed by seq tables > 1 byte */ |             litLength = MEM_readLE24(dumps); | ||||||
|             if (litLength&1) litLength>>=1, dumps += 3; |             if (litLength&1) litLength>>=1, dumps += 3; | ||||||
|             else litLength = (U16)(litLength)>>1, dumps += 2; |             else litLength = (U16)(litLength)>>1, dumps += 2; | ||||||
|         } |         } | ||||||
|         if (dumps > de) { litLength = MaxLL+255; }  /* late correction, to avoid using uninitialized memory */ |  | ||||||
|         if (dumps >= de) { dumps = de-1; }  /* late correction, to avoid read overflow (data is now corrupted anyway) */ |         if (dumps >= de) { dumps = de-1; }  /* late correction, to avoid read overflow (data is now corrupted anyway) */ | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -3185,14 +3189,13 @@ static void ZSTDv05_decodeSequence(seq_t* seq, seqState_t* seqState) | |||||||
|     /* MatchLength */ |     /* MatchLength */ | ||||||
|     matchLength = FSEv05_decodeSymbol(&(seqState->stateML), &(seqState->DStream)); |     matchLength = FSEv05_decodeSymbol(&(seqState->stateML), &(seqState->DStream)); | ||||||
|     if (matchLength == MaxML) { |     if (matchLength == MaxML) { | ||||||
|         U32 add = *dumps++; |         const U32 add = dumps<de ? *dumps++ : 0; | ||||||
|         if (add < 255) matchLength += add; |         if (add < 255) matchLength += add; | ||||||
|         else { |         else if (dumps + 3 <= de) { | ||||||
|             matchLength = MEM_readLE32(dumps) & 0xFFFFFF;  /* no pb : dumps is always followed by seq tables > 1 byte */ |             matchLength = MEM_readLE24(dumps); | ||||||
|             if (matchLength&1) matchLength>>=1, dumps += 3; |             if (matchLength&1) matchLength>>=1, dumps += 3; | ||||||
|             else matchLength = (U16)(matchLength)>>1, dumps += 2; |             else matchLength = (U16)(matchLength)>>1, dumps += 2; | ||||||
|         } |         } | ||||||
|         if (dumps > de) { matchLength = MaxML+255; }  /* late correction, to avoid using uninitialized memory */ |  | ||||||
|         if (dumps >= de) { dumps = de-1; }  /* late correction, to avoid read overflow (data is now corrupted anyway) */ |         if (dumps >= de) { dumps = de-1; }  /* late correction, to avoid read overflow (data is now corrupted anyway) */ | ||||||
|     } |     } | ||||||
|     matchLength += MINMATCH; |     matchLength += MINMATCH; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user