From ac3bd35e5a9877861ca3c701ae9cdf9147eb7b33 Mon Sep 17 00:00:00 2001
From: Ozkan Sezer <[EMAIL REDACTED]>
Date: Wed, 23 Jun 2021 07:50:02 +0300
Subject: [PATCH] libmodplug: Fix misc. loader crashes and leaks found by
libFuzzer:
Patchset by Alice Rowan: https://github.com/Konstanty/libmodplug/pull/58
* 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.
- Fix AMS loader crash and slow load bugs found by libFuzzer:
* AMS: fix AMS out-of-bounds reads due to missing song comments checks.
* AMS: fix AMS out-of-bounds reads due to missing order list check.
* AMS: fix AMS out-of-bounds reads due to missing pattern/track checks.
* AMS: fix AMS2 out-of-bounds reads due to missing/broken instrument
and envelope bounds checks.
* AMS: fix AMS2 out-of-bounds reads due to missing sample bounds checks.
* AMS: fix ReadSample out-of-bounds reads due to overflow in packed
size bounds check.
* AMS: fix AMSUnpack out-of-bounds reads due to missing RLE unpacking
bounds checks.
* AMS: reduce AMSUnpack slow loads by rejecting samples with truncated
or invalid RLE.
* AMS: reduce AMSUnpack slow loads by shrinking samples if their packed
size couldn't possibly store them.
* AMS: constify pointers derived from lpStream.
- Fix DMF loader crash/hang/slow load bugs found by libFuzzer:
* DMF: fix faulty bounds checks for INFO, SEQU, and SMPI chunks.
* DMF: add numerous missing bounds checks for patterns and track data.
* DMF: fix out-of-bounds reads caused by missing sample bounds check.
* DMF: fix hangs caused by duplicate PATT chunks.
* DMF: fix sample leaks caused by duplicate SMPD chunks.
* DMF: fix slow loads caused by missing EOF check in DMFUnpack.
* DMF: constify pointers derived from lpStream.
- Fix MDL loader crash bugs found by libFuzzer:
* MDL: fix out-of-bounds reads due to missing info chunk bounds check.
* MDL: fix out-of-bounds reads due to a missing bounds check when
loading instruments.
* MDL: fix out-of-bounds reads and other bugs due to bad envelope
bounding and missing duplicate envelope chunk checks.
* MDL: fix out-of-bounds reads due to broken track bounds checks.
- Fix MT2 loader crashes and hangs found by libFuzzer:
* MT2: fix out-of-bounds reads due to missing nDrumDataLen check.
* MT2: fix out-of-bounds reads due to missing pattern/track checks.
* MT2: fix out-of-bounds reads due to broken/nonsensical instrument
bounds checks.
* MT2: fix out-of-bounds reads due to missing sample data length
bounds check.
* MT2: fix out-of-bounds reads due to bad checks on group structs.
* MT2: fix hangs caused by overflows preventing the data chunk size
bounds check from working.
* MT2: constify pattern data pointer derived from lpStream.
- Fix PSM loader crash bugs found by libFuzzer:
* PSM: fix out-of-bounds reads due to dereferencing lpStream before
any bounds checks.
* PSM: fix out-of-bounds reads due to reading pPsmPat.data from the
stack instead of the input buffer.
* PSM: fix out-of-bounds reads due to invalid samples in patterns.
* PSM: fix missing pattern length byte-swapping.
* PSM: constify pattern data pointer derived from lpStream.
---
external/libmodplug-0.8.9.0/src/load_amf.cpp | 4 +
external/libmodplug-0.8.9.0/src/load_ams.cpp | 77 +++++++++++++---
external/libmodplug-0.8.9.0/src/load_dbm.cpp | 6 ++
external/libmodplug-0.8.9.0/src/load_dmf.cpp | 71 ++++++++++----
external/libmodplug-0.8.9.0/src/load_far.cpp | 17 ++--
external/libmodplug-0.8.9.0/src/load_it.cpp | 21 +++--
external/libmodplug-0.8.9.0/src/load_mdl.cpp | 20 ++--
external/libmodplug-0.8.9.0/src/load_med.cpp | 19 ++--
external/libmodplug-0.8.9.0/src/load_mid.cpp | 97 +++++++++++++-------
external/libmodplug-0.8.9.0/src/load_mt2.cpp | 37 +++++---
external/libmodplug-0.8.9.0/src/load_okt.cpp | 13 ++-
external/libmodplug-0.8.9.0/src/load_pat.cpp | 2 +-
external/libmodplug-0.8.9.0/src/load_psm.cpp | 13 ++-
external/libmodplug-0.8.9.0/src/load_s3m.cpp | 5 +
external/libmodplug-0.8.9.0/src/load_stm.cpp | 1 +
external/libmodplug-0.8.9.0/src/load_ult.cpp | 3 +-
external/libmodplug-0.8.9.0/src/load_wav.cpp | 9 +-
external/libmodplug-0.8.9.0/src/load_xm.cpp | 30 +++---
external/libmodplug-0.8.9.0/src/mmcmp.cpp | 39 ++++----
external/libmodplug-0.8.9.0/src/sndfile.cpp | 7 +-
20 files changed, 325 insertions(+), 166 deletions(-)
diff --git a/external/libmodplug-0.8.9.0/src/load_amf.cpp b/external/libmodplug-0.8.9.0/src/load_amf.cpp
index 82ea867..0b9356c 100644
--- a/external/libmodplug-0.8.9.0/src/load_amf.cpp
+++ b/external/libmodplug-0.8.9.0/src/load_amf.cpp
@@ -315,8 +315,12 @@ BOOL CSoundFile::ReadAMF(LPCBYTE lpStream, const DWORD dwMemLength)
PatternSize[iOrd] = 64;
if (pfh->version >= 14)
{
+ if (dwMemPos + m_nChannels * sizeof(USHORT) + 2 > dwMemLength) return FALSE;
PatternSize[iOrd] = bswapLE16(*(USHORT *)(lpStream+dwMemPos));
dwMemPos += 2;
+ } else
+ {
+ if (dwMemPos + m_nChannels * sizeof(USHORT) > dwMemLength) return FALSE;
}
ptracks[iOrd] = (USHORT *)(lpStream+dwMemPos);
dwMemPos += m_nChannels * sizeof(USHORT);
diff --git a/external/libmodplug-0.8.9.0/src/load_ams.cpp b/external/libmodplug-0.8.9.0/src/load_ams.cpp
index 1448f46..37eeae6 100644
--- a/external/libmodplug-0.8.9.0/src/load_ams.cpp
+++ b/external/libmodplug-0.8.9.0/src/load_ams.cpp
@@ -39,15 +39,16 @@ typedef struct AMSSAMPLEHEADER
#pragma pack()
+static BOOL AMSUnpackCheck(const BYTE *lpStream, DWORD dwMemLength, MODINSTRUMENT *ins);
BOOL CSoundFile::ReadAMS(LPCBYTE lpStream, DWORD dwMemLength)
//-----------------------------------------------------------
{
// BYTE pkinf[MAX_SAMPLES];
- AMSFILEHEADER *pfh = (AMSFILEHEADER *)lpStream;
+ const AMSFILEHEADER *pfh = (AMSFILEHEADER *)lpStream;
DWORD dwMemPos;
UINT tmp, tmp2;
-
+
if ((!lpStream) || (dwMemLength < 1024)) return FALSE;
if ((pfh->verhi != 0x01) || (strncmp(pfh->szHeader, "Extreme", 7))
|| (!pfh->patterns) || (!pfh->orders) || (!pfh->samples) || (pfh->samples >= MAX_SAMPLES)
@@ -63,7 +64,7 @@ BOOL CSoundFile::ReadAMS(LPCBYTE lpStream, DWORD dwMemLength)
m_nSamples = pfh->samples;
for (UINT nSmp=1; nSmp<=m_nSamples; nSmp++, dwMemPos += sizeof(AMSSAMPLEHEADER))
{
- AMSSAMPLEHEADER *psh = (AMSSAMPLEHEADER *)(lpStream + dwMemPos);
+ const AMSSAMPLEHEADER *psh = (AMSSAMPLEHEADER *)(lpStream + dwMemPos);
MODINSTRUMENT *pins = &Ins[nSmp];
pins->nLength = psh->length;
pins->nLoopStart = psh->loopstart;
@@ -115,9 +116,10 @@ BOOL CSoundFile::ReadAMS(LPCBYTE lpStream, DWORD dwMemLength)
dwMemPos += tmp;
}
// Read Song Comments
+ if (dwMemPos + 2 > dwMemLength) return TRUE;
tmp = *((WORD *)(lpStream+dwMemPos));
dwMemPos += 2;
- if (dwMemPos + tmp >= dwMemLength) return TRUE;
+ if (tmp >= dwMemLength || dwMemPos > dwMemLength - tmp) return TRUE;
if (tmp)
{
m_lpszSongComments = new char[tmp+1]; // changed from CHAR
@@ -127,6 +129,7 @@ BOOL CSoundFile::ReadAMS(LPCBYTE lpStream, DWORD dwMemLength)
dwMemPos += tmp;
}
// Read Order List
+ if (2*pfh->orders >= dwMemLength || dwMemPos > dwMemLength - 2*pfh->orders) return TRUE;
for (UINT iOrd=0; iOrd<pfh->orders; iOrd++, dwMemPos += 2)
{
UINT n = *((WORD *)(lpStream+dwMemPos));
@@ -138,7 +141,7 @@ BOOL CSoundFile::ReadAMS(LPCBYTE lpStream, DWORD dwMemLength)
if (dwMemPos + 4 >= dwMemLength) return TRUE;
UINT len = *((DWORD *)(lpStream + dwMemPos));
dwMemPos += 4;
- if ((len >= dwMemLength) || (dwMemPos + len > dwMemLength)) return TRUE;
+ if ((len >= dwMemLength) || (dwMemPos > dwMemLength - len)) return TRUE;
PatternSize[iPat] = 64;
MODCOMMAND *m = AllocatePattern(PatternSize[iPat], m_nChannels);
if (!m) return TRUE;
@@ -154,6 +157,7 @@ BOOL CSoundFile::ReadAMS(LPCBYTE lpStream, DWORD dwMemLength)
// Note+Instr
if (!(b0 & 0x40))
{
+ if (i+1 > len) break;
b2 = p[i++];
if (ch < m_nChannels)
{
@@ -162,6 +166,7 @@ BOOL CSoundFile::ReadAMS(LPCBYTE lpStream, DWORD dwMemLength)
}
if (b1 & 0x80)
{
+ if (i+1 > len) break;
b0 |= 0x40;
b1 = p[i++];
}
@@ -179,6 +184,7 @@ BOOL CSoundFile::ReadAMS(LPCBYTE lpStream, DWORD dwMemLength)
}
} else
{
+ if (i+1 > len) break;
b2 = p[i++];
if (ch < m_nChannels)
{
@@ -221,6 +227,7 @@ BOOL CSoundFile::ReadAMS(LPCBYTE lpStream, DWORD dwMemLength)
}
if (b1 & 0x80)
{
+ if (i+1 > len) break;
b1 = p[i++];
if (i <= len) goto anothercommand;
}
@@ -238,7 +245,8 @@ BOOL CSoundFile::ReadAMS(LPCBYTE lpStream, DWORD dwMemLength)
{
if (dwMemPos >= dwMemLength - 9) return TRUE;
UINT flags = (Ins[iSmp].uFlags & CHN_16BIT) ? RS_AMS16 : RS_AMS8;
- dwMemPos += ReadSample(&Ins[iSmp], flags, (LPSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos);
+ if (!AMSUnpackCheck(lpStream+dwMemPos, dwMemLength-dwMemPos, &Ins[iSmp])) break;
+ dwMemPos += ReadSample(&Ins[iSmp], flags, (LPCSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos);
}
return TRUE;
}
@@ -301,7 +309,6 @@ typedef struct AMS2SAMPLE
BYTE flags;
} AMS2SAMPLE;
-
#pragma pack()
@@ -309,7 +316,7 @@ BOOL CSoundFile::ReadAMS2(LPCBYTE lpStream, DWORD dwMemLength)
//------------------------------------------------------------
{
const AMS2FILEHEADER *pfh = (AMS2FILEHEADER *)lpStream;
- AMS2SONGHEADER *psh;
+ const AMS2SONGHEADER *psh;
DWORD dwMemPos;
BYTE smpmap[16];
BYTE packedsamples[MAX_SAMPLES];
@@ -335,19 +342,23 @@ BOOL CSoundFile::ReadAMS2(LPCBYTE lpStream, DWORD dwMemLength)
if (psh->flags & 0x40) m_dwSongFlags |= SONG_LINEARSLIDES;
for (UINT nIns=1; nIns<=m_nInstruments; nIns++)
{
+ if (dwMemPos >= dwMemLength) return TRUE;
UINT insnamelen = lpStream[dwMemPos];
- CHAR *pinsname = (CHAR *)(lpStream+dwMemPos+1);
+ const CHAR *pinsname = (CHAR *)(lpStream+dwMemPos+1);
dwMemPos += insnamelen + 1;
- AMS2INSTRUMENT *pins = (AMS2INSTRUMENT *)(lpStream + dwMemPos);
+ const AMS2INSTRUMENT *pins = (AMS2INSTRUMENT *)(lpStream + dwMemPos);
dwMemPos += sizeof(AMS2INSTRUMENT);
- if (dwMemPos + 1024 >= dwMemLength) return TRUE;
- AMS2ENVELOPE *volenv, *panenv, *pitchenv;
+ const AMS2ENVELOPE *volenv, *panenv, *pitchenv;
+ if (dwMemPos + sizeof(AMS2ENVELOPE) > dwMemLength) return TRUE;
volenv = (AMS2ENVELOPE *)(lpStream+dwMemPos);
dwMemPos += 5 + volenv->points*3;
+ if (dwMemPos + sizeof(AMS2ENVELOPE) > dwMemLength) return TRUE;
panenv = (AMS2ENVELOPE *)(lpStream+dwMemPos);
dwMemPos += 5 + panenv->points*3;
+ if (dwMemPos + sizeof(AMS2ENVELOPE) > dwMemLength) return TRUE;
pitchenv = (AMS2ENVELOPE *)(lpStream+dwMemPos);
dwMemPos += 5 + pitchenv->points*3;
+ if (dwMemPos >= dwMemLength) return TRUE;
INSTRUMENTHEADER *penv = new INSTRUMENTHEADER;
if (!penv) return TRUE;
memset(smpmap, 0, sizeof(smpmap));
@@ -387,6 +398,7 @@ BOOL CSoundFile::ReadAMS2(LPCBYTE lpStream, DWORD dwMemLength)
penv->VolPoints[i] = (WORD)pos;
}
}
+ if (dwMemPos + 5 > dwMemLength) return TRUE;
penv->nFadeOut = (((lpStream[dwMemPos+2] & 0x0F) << 8) | (lpStream[dwMemPos+1])) << 3;
UINT envflags = lpStream[dwMemPos+3];
if (envflags & 0x01) penv->dwFlags |= ENV_VOLLOOP;
@@ -396,16 +408,19 @@ BOOL CSoundFile::ReadAMS2(LPCBYTE lpStream, DWORD dwMemLength)
// Read Samples
for (UINT ismp=0; ismp<pins->samples; ismp++)
{
+ if (dwMemPos + 1 > dwMemLength) return TRUE;
MODINSTRUMENT *psmp = ((ismp < 16) && (smpmap[ismp])) ? &Ins[smpmap[ismp]] : NULL;
UINT smpnamelen = lpStream[dwMemPos];
+ if (dwMemPos + smpnamelen + 1 > dwMemLength) return TRUE;
if ((psmp) && (smpnamelen) && (smpnamelen <= 22))
{
memcpy(m_szNames[smpmap[ismp]], lpStream+dwMemPos+1, smpnamelen);
}
dwMemPos += smpnamelen + 1;
+ if (dwMemPos + sizeof(AMS2SAMPLE) > dwMemLength) return TRUE;
if (psmp)
{
- AMS2SAMPLE *pams = (AMS2SAMPLE *)(lpStream+dwMemPos);
+ const AMS2SAMPLE *pams = (AMS2SAMPLE *)(lpStream+dwMemPos);
psmp->nGlobalVol = 64;
psmp->nPan = 128;
psmp->nLength = pams->length;
@@ -545,16 +560,40 @@ BOOL CSoundFile::ReadAMS2(LPCBYTE lpStream, DWORD dwMemLength)
if (packedsamples[iSmp] & 0x03)
{
flags = (Ins[iSmp].uFlags & CHN_16BIT) ? RS_AMS16 : RS_AMS8;
+ if (!AMSUnpackCheck(lpStream+dwMemPos, dwMemLength-dwMemPos, &Ins[iSmp])) break;
} else
{
flags = (Ins[iSmp].uFlags & CHN_16BIT) ? RS_PCM16S : RS_PCM8S;
}
- dwMemPos += ReadSample(&Ins[iSmp], flags, (LPSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos);
+ dwMemPos += ReadSample(&Ins[iSmp], flags, (LPCSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos);
}
return TRUE;
}
+// Precheck AMS packed sample size to determine whether or not it could fit the actual size.
+static BOOL AMSUnpackCheck(const BYTE *lpStream, DWORD dwMemLength, MODINSTRUMENT *ins)
+// -----------------------------------------------------------------------------------
+{
+ if (dwMemLength < 9) return FALSE;
+ DWORD packedbytes = *((DWORD *)(lpStream + 4));
+
+ DWORD samplebytes = ins->nLength;
+ if (samplebytes > MAX_SAMPLE_LENGTH) samplebytes = MAX_SAMPLE_LENGTH;
+ if (ins->uFlags & CHN_16BIT) samplebytes *= 2;
+
+ // RLE can pack a run of up to 255 bytes into 3 bytes.
+ DWORD packedmin = (samplebytes * 3) >> 8;
+ if (packedbytes < packedmin)
+ {
+ samplebytes = packedbytes * (255 / 3) + 2;
+ ins->nLength = samplebytes;
+ if (ins->uFlags & CHN_16BIT) ins->nLength >>= 1;
+ }
+
+ return TRUE;
+}
+
/////////////////////////////////////////////////////////////////////
// AMS Sample unpacking
@@ -562,7 +601,7 @@ void AMSUnpack(const char *psrc, UINT inputlen, char *pdest, UINT dmax, char pac
{
UINT tmplen = dmax;
signed char *amstmp = new signed char[tmplen];
-
+
if (!amstmp) return;
// Unpack Loop
{
@@ -573,9 +612,11 @@ void AMSUnpack(const char *psrc, UINT inputlen, char *pdest, UINT dmax, char pac
signed char ch = psrc[i++];
if (ch == packcharacter)
{
+ if (i >= inputlen) break;
BYTE ch2 = psrc[i++];
if (ch2)
{
+ if (i >= inputlen) break;
ch = psrc[i++];
while (ch2--)
{
@@ -585,6 +626,12 @@ void AMSUnpack(const char *psrc, UINT inputlen, char *pdest, UINT dmax, char pac
} else p[j++] = packcharacter;
} else p[j++] = ch;
}
+ if (j < tmplen)
+ {
+ // Truncated or invalid; don't try to unpack this.
+ delete[] amstmp;
+ return;
+ }
}
// Bit Unpack Loop
{
diff --git a/external/libmodplug-0.8.9.0/src/load_dbm.cpp b/external/libmodplug-0.8.9.0/src/load_dbm.cpp
index 8bc9c9b..d8f770e 100644
--- a/external/libmodplug-0.8.9.0/src/load_dbm.cpp
+++ b/external/libmodplug-0.8.9.0/src/load_dbm.cpp
@@ -136,6 +136,9 @@ BOOL CSoundFile::ReadDBM(const BYTE *lpStream, DWORD dwMemLength)
// Instruments
if (chunk_id == bswapLE32(DBM_ID_INST))
{
+ // Skip duplicate chunks.
+ if (m_nInstruments) continue;
+
if (nInstruments >= MAX_INSTRUMENTS) nInstruments = MAX_INSTRUMENTS-1;
for (UINT iIns=0; iIns<nInstruments; iIns++)
{
@@ -239,6 +242,9 @@ BOOL CSoundFile::ReadDBM(const BYTE *lpStream, DWORD dwMemLength)
DWORD pksize;
UINT nRows;
+ // Skip duplicate chunks.
+ if (Patterns[iPat]) break;
+
if (chunk_pos + sizeof(DBMPATTERN) > dwMemPos) break;
pph = (DBMPATTERN *)(lpStream+chunk_pos);
pksize = bswapBE32(pph->packedsize);
diff --git a/external/libmodplug-0.8.9.0/src/load_dmf.cpp b/external/libmodplug-0.8.9.0/src/load_dmf.cpp
index 1d4f8a7..85d02f7 100644
--- a/external/libmodplug-0.8.9.0/src/load_dmf.cpp
+++ b/external/libmodplug-0.8.9.0/src/load_dmf.cpp
@@ -87,11 +87,12 @@ BOOL CSoundFile::ReadDMF(const BYTE *lpStream, DWORD dwMemLength)
//---------------------------------------------------------------
{
const DMFHEADER *pfh = (DMFHEADER *)lpStream;
- DMFINFO *psi;
- DMFSEQU *sequ;
+ const DMFINFO *psi;
+ const DMFPATT *patt;
+ const DMFSEQU *sequ;
DWORD dwMemPos;
BYTE infobyte[32];
- BYTE smplflags[MAX_SAMPLES], hasSMPI = 0;
+ BYTE smplflags[MAX_SAMPLES], hasSMPI = 0, hasSMPD = 0;
if ((!lpStream) || (dwMemLength < 1024)) return FALSE;
if ((pfh->id != 0x464d4444) || (!pfh->version) || (pfh->version & 0xF0)) return FALSE;
@@ -115,7 +116,7 @@ BOOL CSoundFile::ReadDMF(const BYTE *lpStream, DWORD dwMemLength)
case 0x47534d43:
psi = (DMFINFO *)(lpStream+dwMemPos);
if (id == 0x47534d43) dwMemPos++;
- if ((psi->infosize > dwMemLength) || (psi->infosize + dwMemPos + 8 > dwMemLength)) goto dmfexit;
+ if ((psi->infosize > dwMemLength) || (dwMemPos + 8 > dwMemLength - psi->infosize)) goto dmfexit;
if ((psi->infosize >= 8) && (!m_lpszSongComments))
{
m_lpszSongComments = new char[psi->infosize]; // changed from CHAR
@@ -138,9 +139,10 @@ BOOL CSoundFile::ReadDMF(const BYTE *lpStream, DWORD dwMemLength)
// "SEQU"
case 0x55514553:
sequ = (DMFSEQU *)(lpStream+dwMemPos);
- if ((sequ->seqsize >= dwMemLength) || (dwMemPos + sequ->seqsize + 12 > dwMemLength)) goto dmfexit;
+ if ((sequ->seqsize >= dwMemLength) || (dwMemPos + 8 > dwMemLength - sequ->seqsize)) goto dmfexit;
+ if (sequ->seqsize >= 4)
{
- UINT nseq = sequ->seqsize >> 1;
+ UINT nseq = (sequ->seqsize - 4) >> 1;
if (nseq >= MAX_ORDERS-1) nseq = MAX_ORDERS-1;
if (sequ->loopstart < nseq) m_nRestartPos = sequ->loopstart;
for (UINT i=0; i<nseq; i++) Order[i] = (BYTE)sequ->sequ[i];
@@ -150,12 +152,12 @@ BOOL CSoundFile::ReadDMF(const BYTE *lpStream, DWORD dwMemLength)
// "PATT"
case 0x54544150:
- if (!m_nChannels)
+ patt = (DMFPATT *)(lpStream+dwMemPos);
+ if ((patt->patsize >= dwMemLength) || (dwMemPos + 8 > dwMemLength - patt->patsize)) goto dmfexit;
+ if (patt->patsize >= 4 && !m_nChannels)
{
- DMFPATT *patt = (DMFPATT *)(lpStream+dwMemPos);
UINT numpat;
DWORD dwPos = dwMemPos + 11;
- if ((patt->patsize >= dwMemLength) || (dwMemPos + patt->patsize + 8 > dwMemLength)) goto dmfexit;
numpat = patt->numpat;
if (numpat > MAX_PATTERNS) numpat = MAX_PATTERNS;
m_nChannels = patt->tracks;
@@ -164,7 +166,8 @@ BOOL CSoundFile::ReadDMF(const BYTE *lpStream, DWORD dwMemLength)
if (m_nChannels < 4) m_nChannels = 4;
for (UINT npat=0; npat<numpat; npat++)
{
- DMFTRACK *pt = (DMFTRACK *)(lpStream+dwPos);
+ const DMFTRACK *pt = (DMFTRACK *)(lpStream+dwPos);
+ if (dwPos + 8 >= dwMemLength) break;
#ifdef DMFLOG
Log("Pattern #%d: %d tracks, %d rows\n", npat, pt->tracks, pt->ticks);
#endif
@@ -174,7 +177,7 @@ BOOL CSoundFile::ReadDMF(const BYTE *lpStream, DWORD dwMemLength)
if (ticks > 256) ticks = 256;
if (ticks < 16) ticks = 16;
dwPos += 8;
- if ((pt->jmpsize >= dwMemLength) || (dwPos + pt->jmpsize + 4 >= dwMemLength)) break;
+ if ((pt->jmpsize >= dwMemLength) || (dwPos + 4 > dwMemLength - pt->jmpsize)) break;
PatternSize[npat] = (WORD)ticks;
MODCOMMAND *m = AllocatePattern(PatternSize[npat], m_nChannels);
if (!m) goto dmfexit;
@@ -193,6 +196,7 @@ BOOL CSoundFile::ReadDMF(const BYTE *lpStream, DWORD dwMemLength)
// Parse track global effects
if (!glbinfobyte)
{
+ if (d+1 > dwPos) break;
BYTE info = lpStream[d++];
BYTE infoval = 0;
if ((info & 0x80) && (d < dwPos)) glbinfobyte = lpStream[d++];
@@ -214,17 +218,24 @@ BOOL CSoundFile::ReadDMF(const BYTE *lpStream, DWORD dwMemLength)
// Parse channels
for (UINT i=0; i<tracks; i++) if (!infobyte[i])
{
+ if (d+1 > dwPos) break;
MODCOMMAND cmd = {0,0,0,0,0,0};
BYTE info = lpStream[d++];
- if (info & 0x80) infobyte[i] = lpStream[d++];
+ if (info & 0x80)
+ {
+ if (d+1 > dwPos) break;
+ infobyte[i] = lpStream[d++];
+ }
// Instrument
if (info & 0x40)
{
+ if (d+1 > dwPos) break;
cmd.instr = lpStream[d++];
}
// Note
if (info & 0x20)
{
+ if (d+1 > dwPos) break;
cmd.note = lpStream[d++];
if ((cmd.note) && (cmd.note < 0xfe)) cmd.note &= 0x7f;
if ((cmd.note) && (cmd.note < 128)) cmd.note += 24;
@@ -232,12 +243,15 @@ BOOL CSoundFile::ReadDMF(const BYTE *lpStream, DWORD dwMemLength)
// Volume
if (info & 0x10)
{
+ if (d+1 > dwPos) break;
cmd.volcmd = VOLCMD_VOLUME;
cmd.vol = (lpStream[d++]+3)>>2;
}
// Effect 1
if (info & 0x08)
{
+ if (d+2 > dwPos) break;
+
BYTE efx = lpStream[d++];
BYTE eval = lpStream[d++];
switch(efx)
@@ -259,6 +273,8 @@ BOOL CSoundFile::ReadDMF(const BYTE *lpStream, DWORD dwMemLength)
// Effect 2
if (info & 0x04)
{
+ if (d+2 > dwPos) break;
+
BYTE efx = lpStream[d++];
BYTE eval = lpStream[d++];
switch(efx)
@@ -289,6 +305,8 @@ BOOL CSoundFile::ReadDMF(const BYTE *lpStream, DWORD dwMemLength)
// Effect 3
if (info & 0x02)
{
+ if (d+2 > dwPos) break;
+
BYTE efx = lpStream[d++];
BYTE eval = lpStream[d++];
switch(efx)
@@ -372,22 +390,24 @@ BOOL CSoundFile::ReadDMF(const BYTE *lpStream, DWORD dwMemLength)
#endif
if (dwPos + 8 >= dwMemLength) break;
}
- dwMemPos += patt->patsize + 8;
}
+ dwMemPos += patt->patsize + 8;
break;
// "SMPI": Sample Info
case 0x49504d53:
{
hasSMPI = 1;
- DMFSMPI *pds = (DMFSMPI *)(lpStream+dwMemPos);
- if (pds->size <= dwMemLength - dwMemPos)
+ const DMFSMPI *pds = (DMFSMPI *)(lpStream+dwMemPos);
+ if ((pds->size >= dwMemLength) || (dwMemPos + 8 > dwMemLength - pds->size)) goto dmfexit;
+ if (pds->size >= 1)
{
DWORD dwPos = dwMemPos + 9;
m_nSamples = pds->samples;
if (m_nSamples >= MAX_SAMPLES) m_nSamples = MAX_SAMPLES-1;
for (UINT iSmp=1; iSmp<=m_nSamples; iSmp++)
{
+ if (dwPos >= dwMemPos + pds->size + 8) break;
UINT namelen = lpStream[dwPos];
smplflags[iSmp] = 0;
if (dwPos+namelen+1+sizeof(DMFSAMPLE) > dwMemPos+pds->size+8) break;
@@ -398,7 +418,7 @@ BOOL CSoundFile::ReadDMF(const BYTE *lpStream, DWORD dwMemLength)
m_szNames[iSmp][rlen] = 0;
}
dwPos += namelen + 1;
- DMFSAMPLE *psh = (DMFSAMPLE *)(lpStream+dwPos);
+ const DMFSAMPLE *psh = (DMFSAMPLE *)(lpStream+dwPos);
MODINSTRUMENT *psmp = &Ins[iSmp];
psmp->nLength = psh->len;
psmp->nLoopStart = psh->loopstart;
@@ -425,7 +445,7 @@ BOOL CSoundFile::ReadDMF(const BYTE *lpStream, DWORD dwMemLength)
{
DWORD dwPos = dwMemPos + 8;
UINT ismpd = 0;
- for (UINT iSmp=1; iSmp<=m_nSamples; iSmp++)
+ for (UINT iSmp=1; iSmp<=m_nSamples && !hasSMPD; iSmp++)
{
ismpd++;
DWORD pksize;
@@ -458,6 +478,7 @@ BOOL CSoundFile::ReadDMF(const BYTE *lpStream, DWORD dwMemLength)
}
dwPos += pksize;
}
+ hasSMPD = 1;
dwMemPos = dwPos;
}
break;
@@ -520,8 +541,8 @@ static BYTE DMFReadBits(DMF_HTREE *tree, UINT nbits)
{
tree->bitnum--;
} else
- {
- tree->bitbuf = (tree->ibuf < tree->ibufmax) ? *(tree->ibuf++) : 0;
+ if (tree->ibuf < tree->ibufmax) {
+ tree->bitbuf = *(tree->ibuf++);
tree->bitnum = 7;
}
if (tree->bitbuf & 1) x |= bitv;
@@ -576,14 +597,24 @@ int DMFUnpack(LPBYTE psample, LPBYTE ibuf, LPBYTE ibufmax, UINT maxlen)
DMF_HTREE tree;
UINT actnode;
BYTE value, sign, delta = 0;
-
+
memset(&tree, 0, sizeof(tree));
tree.ibuf = ibuf;
tree.ibufmax = ibufmax;
DMFNewNode(&tree);
value = 0;
+
+ if (tree.ibuf >= ibufmax) return tree.ibuf - ibuf;
+
for (UINT i=0; i<maxlen; i++)
{
+ if ((tree.ibuf >= tree.ibufmax) && (!tree.bitnum))
+ {
+ #ifdef DMFLOG
+ Log("DMFUnpack: unexpected EOF at output byte %d / %d\n", i, maxlen);
+ #endif
+ break;
+ }
actnode = 0;
sign = DMFReadBits(&tree, 1);
do
diff --git a/external/libmodplug-0.8.9.0/src/load_far.cpp b/external/libmodplug-0.8.9.0/src/load_far.cpp
index a8245e5..11e676c 100644
--- a/external/libmodplug-0.8.9.0/src/load_far.cpp
+++ b/external/libmodplug-0.8.9.0/src/load_far.cpp
@@ -5,7 +5,7 @@
*/
////////////////////////////////////////
-// Farandole (FAR) module loader //
+// Farandole (FAR) module loader //
////////////////////////////////////////
#include "stdafx.h"
#include "sndfile.h"
@@ -113,8 +113,6 @@ BOOL CSoundFile::ReadFAR(const BYTE *lpStream, DWORD dwMemLength)
dwMemPos += headerlen - (869 + stlen);
if (dwMemPos >= dwMemLength) return TRUE;
- // end byteswap of pattern data
-
WORD *patsiz = (WORD *)pmh2->patsiz;
for (UINT ipat=0; ipat<256; ipat++) if (patsiz[ipat])
{
@@ -125,6 +123,7 @@ BOOL CSoundFile::ReadFAR(const BYTE *lpStream, DWORD dwMemLength)
continue;
}
if (dwMemPos + patlen >= dwMemLength) return TRUE;
+ UINT max = (patlen - 2) & ~3;
UINT rows = (patlen - 2) >> 6;
if (!rows)
{
@@ -133,13 +132,12 @@ BOOL CSoundFile::ReadFAR(const BYTE *lpStream, DWORD dwMemLength)
}
if (rows > 256) rows = 256;
if (rows < 16) rows = 16;
+ if (max > rows*16*4) max = rows*16*4;
PatternSize[ipat] = rows;
if ((Patterns[ipat] = AllocatePattern(rows, m_nChannels)) == NULL) return TRUE;
MODCOMMAND *m = Patterns[ipat];
UINT patbrk = lpStream[dwMemPos];
const BYTE *p = lpStream + dwMemPos + 2;
- UINT max = rows*16*4;
- if (max > patlen-2) max = patlen-2;
for (UINT len=0; len<max; len += 4, m++)
{
BYTE note = p[len];
@@ -235,10 +233,10 @@ BOOL CSoundFile::ReadFAR(const BYTE *lpStream, DWORD dwMemLength)
dwMemPos += sizeof(FARSAMPLE);
m_nSamples = ismp + 1;
memcpy(m_szNames[ismp+1], pfs->samplename, 32);
- const DWORD length = bswapLE32( pfs->length ) ; /* endian fix - Toad */
- pins->nLength = length ;
- pins->nLoopStart = bswapLE32(pfs->reppos) ;
- pins->nLoopEnd = bswapLE32(pfs->repend) ;
+ const DWORD length = bswapLE32(pfs->length); /* endian fix - Toad */
+ pins->nLength = length;
+ pins->nLoopStart = bswapLE32(pfs->reppos);
+ pins->nLoopEnd = bswapLE32(pfs->repend);
pins->nFineTune = 0;
pins->nC4Speed = 8363*2;
pins->nGlobalVol = 64;
@@ -261,4 +259,3 @@ BOOL CSoundFile::ReadFAR(const BYTE *lpStream, DWORD dwMemLength)
}
return TRUE;
}
-
diff --git a/external/libmodplug-0.8.9.0/src/load_it.cpp b/external/libmodplug-0.8.9.0/src/load_it.cpp
index ef1c4ef..89d934a 100644
--- a/external/libmodplug-0.8.9.0/src/load_it.cpp
+++ b/external/libmodplug-0.8.9.0/src/load_it.cpp
@@ -580,7 +580,7 @@ BOOL CSoundFile::ReadIT(const BYTE *lpStream, DWORD dwMemLength)
//////////////////////////////////////////////////////////////////////////////
// IT 2.14 compression
-DWORD ITReadBits(DWORD &bitbuf, UINT &bitnum, LPBYTE &ibuf, CHAR n)
+DWORD ITReadBits(DWORD &bitbuf, UINT &bitnum, LPBYTE &ibuf, LPBYTE ibufend, CHAR n)
//-----------------------------------------------------------------
{
DWORD retval = 0;
@@ -596,6 +596,9 @@ DWORD ITReadBits(DWORD &bitbuf, UINT &bitnum, LPBYTE &ibuf, CHAR n)
{
if (!bitnum)
{
+ if (ibuf >= ibufend)
+ return 0;
+
bitbuf = *ibuf++;
bitnum = 8;
}
@@ -616,6 +619,7 @@ void ITUnpack8Bit(signed char *pSample, DWORD dwLen, LPBYTE lpMemFile, DWORD dwM
{
signed char *pDst = pSample;
LPBYTE pSrc = lpMemFile;
+ LPBYTE pStop = lpMemFile + dwMemLength;
// DWORD wHdr = 0;
DWORD wCount = 0;
DWORD bitbuf = 0;
@@ -639,13 +643,13 @@ void ITUnpack8Bit(signed char *pSample, DWORD dwLen, LPBYTE lpMemFile, DWORD dwM
DWORD dwPos = 0;
do
{
- WORD wBits = (WORD)ITReadBits(bitbuf, bitnum, pSrc, bLeft);
+ WORD wBits = (WORD)ITReadBits(bitbuf, bitnum, pSrc, pStop, bLeft);
if (bLeft < 7)
{
DWORD i = 1 << (bLeft-1);
DWORD j = wBits & 0xFFFF;
if (i != j) goto UnpackByte;
- wBits = (WORD)(ITReadBits(bitbuf, bitnum, pSrc, 3) + 1) & 0xFF;
+ wBits = (WORD)(ITReadBits(bitbuf, bitnum, pSrc, pStop, 3) + 1) & 0xFF;
bLeft = ((BYTE)wBits < bLeft) ? (BYTE)wBits : (BYTE)((wBits+1) & 0xFF);
goto Next;
}
@@ -683,7 +687,7 @@ void ITUnpack8Bit(signed char *pSample, DWORD dwLen, LPBYTE lpMemFile, DWORD dwM
SkipByte:
dwPos++;
Next:
- if (pSrc >= lpMemFile+dwMemLength+1) return;
+ if (pSrc >= pStop + 1) return;
} while (dwPos < d);
// Move On
wCount -= d;
@@ -698,6 +702,7 @@ void ITUnpack16Bit(signed char *pSample, DWORD dwLen, LPBYTE lpMemFile, DWORD dw
{
signed short *pDst = (signed short *)pSample;
LPBYTE pSrc = lpMemFile;
+ LPBYTE pStop = lpMemFile + dwMemLength;
// DWORD wHdr = 0;
DWORD wCount = 0;
DWORD bitbuf = 0;
@@ -722,13 +727,13 @@ void ITUnpack16Bit(signed char *pSample, DWORD dwLen, LPBYTE lpMemFile, DWORD dw
DWORD dwPos = 0;
do
{
- DWORD dwBits = ITReadBits(bitbuf, bitnum, pSrc, bLeft);
+ DWORD dwBits = ITReadBits(bitbuf, bitnum, pSrc, pStop, bLeft);
if (bLeft < 7)
{
DWORD i = 1 << (bLeft-1);
DWORD j = dwBits;
if (i != j) goto UnpackByte;
- dwBits = ITReadBits(bitbuf, bitnum, pSrc, 4) + 1;
+ dwBits = ITReadBits(bitbuf, bitnum, pSrc, pStop, 4) + 1;
bLeft = ((BYTE)(dwBits & 0xFF) < bLeft) ? (BYTE)(dwBits & 0xFF) : (BYTE)((dwBits+1) & 0xFF);
goto Next;
}
@@ -766,13 +771,13 @@ void ITUnpack16Bit(signed char *pSample, DWORD dwLen, LPBYTE lpMemFile, DWORD dw
SkipByte:
dwPos++;
Next:
- if (pSrc >= lpMemFile+dwMemLength+1) return;
+ if (pSrc >= pStop + 1) return;
} while (dwPos < d);
// Move On
wCount -= d;
dwLen -= d;
pDst += d;
- if (pSrc >= lpMemFile+dwMemLength) break;
+ if (pSrc >= pStop) break;
}
}
diff --git a/external/libmodplug-0.8.9.0/src/load_mdl.cpp b/external/libmodplug-0.8.9.0/src/load_mdl.cpp
index 177f322..7e9f43b 100644
--- a/external/libmodplug-0.8.9.0/src/load_mdl.cpp
+++ b/external/libmodplug-0.8.9.0/src/load_mdl.cpp
@@ -216,6 +216,7 @@ BOOL CSoundFile::ReadMDL(const BYTE *lpStream, DWORD dwMemLength)
m_szNames[0][31] = 0;
norders = pmib->norders;
if (norders > MAX_ORDERS) norders = MAX_ORDERS;
+ if (blocklen < sizeof(MDLINFOBLOCK) + norders - sizeof(pmib->seq)) return FALSE;
m_nRestartPos = pmib->repeat
(Patch may be truncated, please check the link at the top of this post.)