Skip to content

Commit 2a82774

Browse files
AliceLRsezero
authored andcommitted
Fix misc. loader crashes and leaks found by libFuzzer.
* AMF (DSMI): fix out-of-bounds reads caused by missing order list bounds checks. * DBM: fix leaks caused by duplicate instrument chunks being loaded. * FAR: fix out-of-bounds reads due to not correctly bounding the maximum pattern read size. * IT: fix out-of-bounds reads in the IT sample decompressors caused by allowing ITReadBits to read past the end of the buffer. * MED: fix out-of-bounds reads due to a faulty MMD2PLAYSEQ bounds check. * MED: fix out-of-bounds reads due to bad sample bounding. * MED: fix out-of-bounds reads due to bad block name bounding (and potential missing nul terminators). * OKT: fix out-of-bounds reads due to incorrect OKTSAMPLE bounding. * OKT: fix out-of-bounds reads due to bad chunk header and order list bounding. * OKT: fix playback errors caused by skipping the first two orders in the order list. * S3M: fix out-of-bounds reads due to missing order list bounds check. * S3M: fix out-of-bounds reads due to missing offset list bounds check. * S3M: fix out-of-bounds reads due to missing panning table check. * STM: fix pattern leaks and pattern size corruption caused by missing MAX_PATTERNS check. * ULT: fix out-of-bounds reads due to incorrect event bounding. * WAV: fix out-of-bounds reads due to not bounds checking the fmt chunk. * WAV: fix hangs caused by missing chunk length bounds check. * WAV: constify pointers derived from lpStream. * XM: fix out-of-bounds reads due to broken XMSAMPLEHEADER check. * XM: fix out-of-bounds reads due to missing pattern data checks. * XM: fix slow loads caused by bad bounding in instrument/sample loops, add other various missing bounds checks. Konstanty#58
1 parent e2261af commit 2a82774

11 files changed

Lines changed: 82 additions & 46 deletions

src/load_amf.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,8 +315,12 @@ BOOL CSoundFile::ReadAMF(LPCBYTE lpStream, const DWORD dwMemLength)
315315
PatternSize[iOrd] = 64;
316316
if (pfh->version >= 14)
317317
{
318+
if (dwMemPos + m_nChannels * sizeof(USHORT) + 2 > dwMemLength) return FALSE;
318319
PatternSize[iOrd] = bswapLE16(*(USHORT *)(lpStream+dwMemPos));
319320
dwMemPos += 2;
321+
} else
322+
{
323+
if (dwMemPos + m_nChannels * sizeof(USHORT) > dwMemLength) return FALSE;
320324
}
321325
ptracks[iOrd] = (USHORT *)(lpStream+dwMemPos);
322326
dwMemPos += m_nChannels * sizeof(USHORT);

src/load_dbm.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ BOOL CSoundFile::ReadDBM(const BYTE *lpStream, DWORD dwMemLength)
136136
// Instruments
137137
if (chunk_id == bswapLE32(DBM_ID_INST))
138138
{
139+
// Skip duplicate chunks.
140+
if (m_nInstruments) continue;
141+
139142
if (nInstruments >= MAX_INSTRUMENTS) nInstruments = MAX_INSTRUMENTS-1;
140143
for (UINT iIns=0; iIns<nInstruments; iIns++)
141144
{
@@ -239,6 +242,9 @@ BOOL CSoundFile::ReadDBM(const BYTE *lpStream, DWORD dwMemLength)
239242
DWORD pksize;
240243
UINT nRows;
241244

245+
// Skip duplicate chunks.
246+
if (Patterns[iPat]) break;
247+
242248
if (chunk_pos + sizeof(DBMPATTERN) > dwMemPos) break;
243249
pph = (DBMPATTERN *)(lpStream+chunk_pos);
244250
pksize = bswapBE32(pph->packedsize);

src/load_far.cpp

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*/
66

77
////////////////////////////////////////
8-
// Farandole (FAR) module loader //
8+
// Farandole (FAR) module loader //
99
////////////////////////////////////////
1010
#include "stdafx.h"
1111
#include "sndfile.h"
@@ -113,8 +113,6 @@ BOOL CSoundFile::ReadFAR(const BYTE *lpStream, DWORD dwMemLength)
113113
dwMemPos += headerlen - (869 + stlen);
114114
if (dwMemPos >= dwMemLength) return TRUE;
115115

116-
// end byteswap of pattern data
117-
118116
WORD *patsiz = (WORD *)pmh2->patsiz;
119117
for (UINT ipat=0; ipat<256; ipat++) if (patsiz[ipat])
120118
{
@@ -125,6 +123,7 @@ BOOL CSoundFile::ReadFAR(const BYTE *lpStream, DWORD dwMemLength)
125123
continue;
126124
}
127125
if (dwMemPos + patlen >= dwMemLength) return TRUE;
126+
UINT max = (patlen - 2) & ~3;
128127
UINT rows = (patlen - 2) >> 6;
129128
if (!rows)
130129
{
@@ -133,13 +132,12 @@ BOOL CSoundFile::ReadFAR(const BYTE *lpStream, DWORD dwMemLength)
133132
}
134133
if (rows > 256) rows = 256;
135134
if (rows < 16) rows = 16;
135+
if (max > rows*16*4) max = rows*16*4;
136136
PatternSize[ipat] = rows;
137137
if ((Patterns[ipat] = AllocatePattern(rows, m_nChannels)) == NULL) return TRUE;
138138
MODCOMMAND *m = Patterns[ipat];
139139
UINT patbrk = lpStream[dwMemPos];
140140
const BYTE *p = lpStream + dwMemPos + 2;
141-
UINT max = rows*16*4;
142-
if (max > patlen-2) max = patlen-2;
143141
for (UINT len=0; len<max; len += 4, m++)
144142
{
145143
BYTE note = p[len];
@@ -235,10 +233,10 @@ BOOL CSoundFile::ReadFAR(const BYTE *lpStream, DWORD dwMemLength)
235233
dwMemPos += sizeof(FARSAMPLE);
236234
m_nSamples = ismp + 1;
237235
memcpy(m_szNames[ismp+1], pfs->samplename, 32);
238-
const DWORD length = bswapLE32( pfs->length ) ; /* endian fix - Toad */
239-
pins->nLength = length ;
240-
pins->nLoopStart = bswapLE32(pfs->reppos) ;
241-
pins->nLoopEnd = bswapLE32(pfs->repend) ;
236+
const DWORD length = bswapLE32(pfs->length); /* endian fix - Toad */
237+
pins->nLength = length;
238+
pins->nLoopStart = bswapLE32(pfs->reppos);
239+
pins->nLoopEnd = bswapLE32(pfs->repend);
242240
pins->nFineTune = 0;
243241
pins->nC4Speed = 8363*2;
244242
pins->nGlobalVol = 64;
@@ -261,4 +259,3 @@ BOOL CSoundFile::ReadFAR(const BYTE *lpStream, DWORD dwMemLength)
261259
}
262260
return TRUE;
263261
}
264-

src/load_it.cpp

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,7 @@ BOOL CSoundFile::ReadIT(const BYTE *lpStream, DWORD dwMemLength)
580580
//////////////////////////////////////////////////////////////////////////////
581581
// IT 2.14 compression
582582

583-
DWORD ITReadBits(DWORD &bitbuf, UINT &bitnum, LPBYTE &ibuf, CHAR n)
583+
DWORD ITReadBits(DWORD &bitbuf, UINT &bitnum, LPBYTE &ibuf, LPBYTE ibufend, CHAR n)
584584
//-----------------------------------------------------------------
585585
{
586586
DWORD retval = 0;
@@ -596,6 +596,9 @@ DWORD ITReadBits(DWORD &bitbuf, UINT &bitnum, LPBYTE &ibuf, CHAR n)
596596
{
597597
if (!bitnum)
598598
{
599+
if (ibuf >= ibufend)
600+
return 0;
601+
599602
bitbuf = *ibuf++;
600603
bitnum = 8;
601604
}
@@ -616,6 +619,7 @@ void ITUnpack8Bit(signed char *pSample, DWORD dwLen, LPBYTE lpMemFile, DWORD dwM
616619
{
617620
signed char *pDst = pSample;
618621
LPBYTE pSrc = lpMemFile;
622+
LPBYTE pStop = lpMemFile + dwMemLength;
619623
// DWORD wHdr = 0;
620624
DWORD wCount = 0;
621625
DWORD bitbuf = 0;
@@ -639,13 +643,13 @@ void ITUnpack8Bit(signed char *pSample, DWORD dwLen, LPBYTE lpMemFile, DWORD dwM
639643
DWORD dwPos = 0;
640644
do
641645
{
642-
WORD wBits = (WORD)ITReadBits(bitbuf, bitnum, pSrc, bLeft);
646+
WORD wBits = (WORD)ITReadBits(bitbuf, bitnum, pSrc, pStop, bLeft);
643647
if (bLeft < 7)
644648
{
645649
DWORD i = 1 << (bLeft-1);
646650
DWORD j = wBits & 0xFFFF;
647651
if (i != j) goto UnpackByte;
648-
wBits = (WORD)(ITReadBits(bitbuf, bitnum, pSrc, 3) + 1) & 0xFF;
652+
wBits = (WORD)(ITReadBits(bitbuf, bitnum, pSrc, pStop, 3) + 1) & 0xFF;
649653
bLeft = ((BYTE)wBits < bLeft) ? (BYTE)wBits : (BYTE)((wBits+1) & 0xFF);
650654
goto Next;
651655
}
@@ -683,7 +687,7 @@ void ITUnpack8Bit(signed char *pSample, DWORD dwLen, LPBYTE lpMemFile, DWORD dwM
683687
SkipByte:
684688
dwPos++;
685689
Next:
686-
if (pSrc >= lpMemFile+dwMemLength+1) return;
690+
if (pSrc >= pStop + 1) return;
687691
} while (dwPos < d);
688692
// Move On
689693
wCount -= d;
@@ -698,6 +702,7 @@ void ITUnpack16Bit(signed char *pSample, DWORD dwLen, LPBYTE lpMemFile, DWORD dw
698702
{
699703
signed short *pDst = (signed short *)pSample;
700704
LPBYTE pSrc = lpMemFile;
705+
LPBYTE pStop = lpMemFile + dwMemLength;
701706
// DWORD wHdr = 0;
702707
DWORD wCount = 0;
703708
DWORD bitbuf = 0;
@@ -722,13 +727,13 @@ void ITUnpack16Bit(signed char *pSample, DWORD dwLen, LPBYTE lpMemFile, DWORD dw
722727
DWORD dwPos = 0;
723728
do
724729
{
725-
DWORD dwBits = ITReadBits(bitbuf, bitnum, pSrc, bLeft);
730+
DWORD dwBits = ITReadBits(bitbuf, bitnum, pSrc, pStop, bLeft);
726731
if (bLeft < 7)
727732
{
728733
DWORD i = 1 << (bLeft-1);
729734
DWORD j = dwBits;
730735
if (i != j) goto UnpackByte;
731-
dwBits = ITReadBits(bitbuf, bitnum, pSrc, 4) + 1;
736+
dwBits = ITReadBits(bitbuf, bitnum, pSrc, pStop, 4) + 1;
732737
bLeft = ((BYTE)(dwBits & 0xFF) < bLeft) ? (BYTE)(dwBits & 0xFF) : (BYTE)((dwBits+1) & 0xFF);
733738
goto Next;
734739
}
@@ -766,13 +771,13 @@ void ITUnpack16Bit(signed char *pSample, DWORD dwLen, LPBYTE lpMemFile, DWORD dw
766771
SkipByte:
767772
dwPos++;
768773
Next:
769-
if (pSrc >= lpMemFile+dwMemLength+1) return;
774+
if (pSrc >= pStop + 1) return;
770775
} while (dwPos < d);
771776
// Move On
772777
wCount -= d;
773778
dwLen -= d;
774779
pDst += d;
775-
if (pSrc >= lpMemFile+dwMemLength) break;
780+
if (pSrc >= pStop) break;
776781
}
777782
}
778783

src/load_med.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -662,7 +662,7 @@ BOOL CSoundFile::ReadMed(const BYTE *lpStream, DWORD dwMemLength)
662662
}
663663
UINT pseq = 0;
664664

665-
if ((playseqtable) && (playseqtable < dwMemLength) && (nplayseq*4 < dwMemLength - playseqtable))
665+
if ((playseqtable) && (playseqtable < dwMemLength) && (nplayseq*4 + 4 < dwMemLength - playseqtable))
666666
{
667667
pseq = bswapBE32(((LPDWORD)(lpStream+playseqtable))[nplayseq]);
668668
}
@@ -789,10 +789,11 @@ BOOL CSoundFile::ReadMed(const BYTE *lpStream, DWORD dwMemLength)
789789
#endif
790790
if ((len > MAX_SAMPLE_LENGTH) || (dwPos + len + 6 > dwMemLength)) len = 0;
791791
UINT flags = RS_PCM8S, stype = bswapBE16(psdh->type);
792-
LPSTR psdata = (LPSTR)(lpStream + dwPos + 6);
792+
dwPos += 6;
793793
if (stype & 0x80)
794794
{
795-
psdata += (stype & 0x20) ? 14 : 6;
795+
dwPos += (stype & 0x20) ? 14 : 6;
796+
if (dwPos >= dwMemLength) continue;
796797
} else
797798
{
798799
if (stype & 0x10)
@@ -807,7 +808,7 @@ BOOL CSoundFile::ReadMed(const BYTE *lpStream, DWORD dwMemLength)
807808
if (stype & 0x20) len /= 2;
808809
}
809810
Ins[iSmp+1].nLength = len;
810-
ReadSample(&Ins[iSmp+1], flags, psdata, dwMemLength - dwPos - 6);
811+
ReadSample(&Ins[iSmp+1], flags, (const char *)(lpStream + dwPos), dwMemLength - dwPos);
811812
}
812813
// Reading patterns (blocks)
813814
if (wNumBlocks > MAX_PATTERNS) wNumBlocks = MAX_PATTERNS;
@@ -876,9 +877,15 @@ BOOL CSoundFile::ReadMed(const BYTE *lpStream, DWORD dwMemLength)
876877
{
877878
DWORD nameofs = bswapBE32(pbi->blockname);
878879
UINT namelen = bswapBE32(pbi->blocknamelen);
879-
if ((nameofs < dwMemLength) && (namelen < dwMemLength - nameofs))
880+
if ((namelen < dwMemLength) && (nameofs < dwMemLength - namelen))
880881
{
881-
SetPatternName(iBlk, (LPCSTR)(lpStream+nameofs));
882+
// SetPatternName expects a nul-terminated string.
883+
char blockname[MAX_PATTERNNAME];
884+
if (namelen >= MAX_PATTERNNAME) namelen = MAX_PATTERNNAME - 1;
885+
memcpy(blockname, lpStream + nameofs, namelen);
886+
blockname[namelen] = '\0';
887+
888+
SetPatternName(iBlk, blockname);
882889
}
883890
}
884891
if (pbi->cmdexttable)

src/load_okt.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ BOOL CSoundFile::ReadOKT(const BYTE *lpStream, DWORD dwMemLength)
5959
// Reading samples
6060
for (UINT smp=1; smp <= nsamples; smp++)
6161
{
62-
if (dwMemPos >= dwMemLength) return TRUE;
62+
if (dwMemPos + sizeof(OKTSAMPLE) >= dwMemLength) return TRUE;
6363
if (smp < MAX_SAMPLES)
6464
{
6565
OKTSAMPLE *psmp = (OKTSAMPLE *)(lpStream + dwMemPos);
@@ -78,32 +78,35 @@ BOOL CSoundFile::ReadOKT(const BYTE *lpStream, DWORD dwMemLength)
7878
dwMemPos += sizeof(OKTSAMPLE);
7979
}
8080
// SPEE
81-
if (dwMemPos >= dwMemLength) return TRUE;
81+
if (dwMemPos + 10 > dwMemLength) return TRUE;
8282
if (*((DWORD *)(lpStream + dwMemPos)) == 0x45455053)
8383
{
8484
m_nDefaultSpeed = lpStream[dwMemPos+9];
8585
dwMemPos += bswapBE32(*((DWORD *)(lpStream + dwMemPos + 4))) + 8;
8686
}
8787
// SLEN
88-
if (dwMemPos >= dwMemLength) return TRUE;
88+
if (dwMemPos + 10 > dwMemLength) return TRUE;
8989
if (*((DWORD *)(lpStream + dwMemPos)) == 0x4E454C53)
9090
{
91+
if (dwMemPos + 10 > dwMemLength) return TRUE;
9192
// npatterns = lpStream[dwMemPos+9];
9293
dwMemPos += bswapBE32(*((DWORD *)(lpStream + dwMemPos + 4))) + 8;
9394
}
9495
// PLEN
95-
if (dwMemPos >= dwMemLength) return TRUE;
96+
if (dwMemPos + 10 > dwMemLength) return TRUE;
9697
if (*((DWORD *)(lpStream + dwMemPos)) == 0x4E454C50)
9798
{
99+
if (dwMemPos + 10 > dwMemLength) return TRUE;
98100
norders = lpStream[dwMemPos+9];
99101
dwMemPos += bswapBE32(*((DWORD *)(lpStream + dwMemPos + 4))) + 8;
100102
}
101103
// PATT
102-
if (dwMemPos >= dwMemLength) return TRUE;
104+
if (dwMemPos + 8 > dwMemLength) return TRUE;
103105
if (*((DWORD *)(lpStream + dwMemPos)) == 0x54544150)
104106
{
105107
UINT orderlen = norders;
106108
if (orderlen >= MAX_ORDERS) orderlen = MAX_ORDERS-1;
109+
if (dwMemPos + 8 + orderlen > dwMemLength) return TRUE;
107110
for (UINT i=0; i<orderlen; i++) Order[i] = lpStream[dwMemPos+8+i];
108111
for (UINT j=orderlen; j>1; j--) { if (Order[j-1]) break; Order[j-1] = 0xFF; }
109112
dwMemPos += bswapBE32(*((DWORD *)(lpStream + dwMemPos + 4))) + 8;

src/load_s3m.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ BOOL CSoundFile::ReadS3M(const BYTE *lpStream, DWORD dwMemLength)
173173
if (iord > MAX_ORDERS) iord = MAX_ORDERS;
174174
if (iord)
175175
{
176+
if (dwMemPos + iord > dwMemLength) return FALSE;
176177
memcpy(Order, lpStream+dwMemPos, iord);
177178
dwMemPos += iord;
178179
}
@@ -190,13 +191,17 @@ BOOL CSoundFile::ReadS3M(const BYTE *lpStream, DWORD dwMemLength)
190191

191192
if (nins+npat)
192193
{
194+
if (2*(nins+npat) + dwMemPos > dwMemLength) return FALSE;
195+
193196
memcpy(ptr, lpStream+dwMemPos, 2*(nins+npat));
194197
dwMemPos += 2*(nins+npat);
195198
for (UINT j = 0; j < (nins+npat); ++j) {
196199
ptr[j] = bswapLE16(ptr[j]);
197200
}
198201
if (psfh.panning_present == 252)
199202
{
203+
if (dwMemPos + 32 > dwMemLength) return FALSE;
204+
200205
const BYTE *chnpan = lpStream+dwMemPos;
201206
for (UINT i=0; i<32; i++) if (chnpan[i] & 0x20)
202207
{

src/load_stm.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ BOOL CSoundFile::ReadSTM(const BYTE *lpStream, DWORD dwMemLength)
107107
dwMemPos = sizeof(STMHEADER);
108108
for (UINT nOrd=0; nOrd<MAX_ORDERS; nOrd++) if (Order[nOrd] >= 99) Order[nOrd] = 0xFF;
109109
UINT nPatterns = phdr->numpat;
110+
if (nPatterns > MAX_PATTERNS) nPatterns = MAX_PATTERNS;
110111
for (UINT nPat=0; nPat<nPatterns; nPat++)
111112
{
112113
if (dwMemPos + 64*4*4 > dwMemLength) return TRUE;

src/load_ult.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,11 +155,12 @@ BOOL CSoundFile::ReadUlt(const BYTE *lpStream, DWORD dwMemLength)
155155
UINT row = 0;
156156
while (row < 64)
157157
{
158-
if (dwMemPos + 6 > dwMemLength) return TRUE;
158+
if (dwMemPos + 5 > dwMemLength) return TRUE;
159159
UINT rep = 1;
160160
UINT note = lpStream[dwMemPos++];
161161
if (note == 0xFC)
162162
{
163+
if (dwMemPos + 7 > dwMemLength) return TRUE;
163164
rep = lpStream[dwMemPos];
164165
note = lpStream[dwMemPos+1];
165166
dwMemPos += 2;

src/load_wav.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ BOOL CSoundFile::ReadWav(const BYTE *lpStream, DWORD dwMemLength)
2424
//---------------------------------------------------------------
2525
{
2626
DWORD dwMemPos = 0;
27-
WAVEFILEHEADER *phdr = (WAVEFILEHEADER *)lpStream;
28-
WAVEFORMATHEADER *pfmt = (WAVEFORMATHEADER *)(lpStream + sizeof(WAVEFILEHEADER));
29-
if ((!lpStream) || (dwMemLength < (DWORD)sizeof(WAVEFILEHEADER))) return FALSE;
27+
const WAVEFILEHEADER *phdr = (WAVEFILEHEADER *)lpStream;
28+
const WAVEFORMATHEADER *pfmt = (WAVEFORMATHEADER *)(lpStream + sizeof(WAVEFILEHEADER));
29+
if ((!lpStream) || (dwMemLength < sizeof(WAVEFILEHEADER)+sizeof(WAVEFORMATHEADER))) return FALSE;
3030
if ((phdr->id_RIFF != IFFID_RIFF) || (phdr->id_WAVE != IFFID_WAVE)
3131
|| (pfmt->id_fmt != IFFID_fmt)) return FALSE;
3232
dwMemPos = sizeof(WAVEFILEHEADER) + 8 + pfmt->hdrlen;
@@ -38,11 +38,12 @@ BOOL CSoundFile::ReadWav(const BYTE *lpStream, DWORD dwMemLength)
3838
|| (pfmt->bitspersample & 7)
3939
|| (pfmt->bitspersample < 8)
4040
|| (pfmt->bitspersample > 32)) return FALSE;
41-
WAVEDATAHEADER *pdata;
41+
const WAVEDATAHEADER *pdata;
4242
for (;;)
4343
{
4444
pdata = (WAVEDATAHEADER *)(lpStream + dwMemPos);
4545
if (pdata->id_data == IFFID_data) break;
46+
if (pdata->length >= dwMemLength || dwMemPos > dwMemLength - pdata->length) return FALSE;
4647
dwMemPos += pdata->length + 8;
4748
if (dwMemPos >= dwMemLength - 8) return FALSE;
4849
}

0 commit comments

Comments
 (0)