Skip to content

Commit 8f0e614

Browse files
committed
Fix multiple heap-based buffer overflows in CmtkLoader::load()
Changes in src/mtk.cpp for loading files: * Fail early if the (decompressed) size is too small to hold mtkdata minus patterns. That avoids attempts to copy data from beyond allocated memory. * In the data decompression section, there are multiple cases where the code actually has checks for available space before copying data, but the size of the copy is increased after the check, so a buffer overflow is still possible (issue adplug#90). Fix that by moving the check after the size computation, and also check for a valid source offset where applicable. * Also add several checks whether source data is exhausted during decompession, so * When copying the patterns, don't copy more data than the "pattern" array can hold. In src/mtk.h, method getinstrument(), check for valid instrument number to avoid accessing the array with an invalid index. This commit fixes CVE-2019-14734. Fixes: adplug#90
1 parent 322c2e1 commit 8f0e614

File tree

2 files changed

+18
-8
lines changed

2 files changed

+18
-8
lines changed

src/mtk.cpp

+17-7
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ bool CmtkLoader::load(const std::string &filename, const CFileProvider &fp)
3939
struct mtkdata {
4040
char songname[34],composername[34],instname[0x80][34];
4141
unsigned char insts[0x80][12],order[0x80],dummy,patterns[0x32][0x40][9];
42+
// HSC pattern has different type and size from patterns, but that
43+
// doesn't matter much since we memcpy() the data. Still confusing.
4244
} *data;
4345
unsigned char *cmp,*org;
4446
unsigned int i;
@@ -51,8 +53,10 @@ bool CmtkLoader::load(const std::string &filename, const CFileProvider &fp)
5153
header.size = f->readInt(2);
5254

5355
// file validation section
54-
if(strncmp(header.id,"mpu401tr\x92kk\xeer@data",18))
55-
{ fp.close(f); return false; }
56+
if (memcmp(header.id, "mpu401tr\x92kk\xeer@data", 18) ||
57+
header.size < sizeof(*data) - sizeof(data->patterns)) {
58+
fp.close(f); return false;
59+
}
5660

5761
// load section
5862
cmpsize = fp.filesize(f) - 22;
@@ -64,6 +68,7 @@ bool CmtkLoader::load(const std::string &filename, const CFileProvider &fp)
6468
while(cmpptr < cmpsize) { // decompress
6569
ctrlmask >>= 1;
6670
if(!ctrlmask) {
71+
if (cmpptr + 2 > cmpsize) goto err;
6772
ctrlbits = cmp[cmpptr] + (cmp[cmpptr + 1] << 8);
6873
cmpptr += 2;
6974
ctrlmask = 0x8000;
@@ -81,37 +86,40 @@ bool CmtkLoader::load(const std::string &filename, const CFileProvider &fp)
8186
cmd = (cmp[cmpptr] >> 4) & 0x0f;
8287
cnt = cmp[cmpptr] & 0x0f;
8388
cmpptr++;
89+
if (cmpptr >= cmpsize) goto err;
8490
switch(cmd) {
8591
case 0:
86-
if(orgptr + cnt > header.size) goto err;
8792
cnt += 3;
93+
if (orgptr + cnt > header.size) goto err;
8894
memset(&org[orgptr],cmp[cmpptr],cnt);
8995
cmpptr++; orgptr += cnt;
9096
break;
9197

9298
case 1:
93-
if(orgptr + cnt > header.size) goto err;
9499
cnt += (cmp[cmpptr] << 4) + 19;
100+
if (orgptr + cnt > header.size || cmpptr >= cmpsize) goto err;
95101
memset(&org[orgptr],cmp[++cmpptr],cnt);
96102
cmpptr++; orgptr += cnt;
97103
break;
98104

99105
case 2:
100-
if(orgptr + cnt > header.size) goto err;
106+
if (cmpptr + 2 > cmpsize) goto err;
101107
offs = (cnt+3) + (cmp[cmpptr] << 4);
102108
cnt = cmp[++cmpptr] + 16; cmpptr++;
109+
if (orgptr + cnt > header.size || offs > orgptr) goto err;
103110
memcpy(&org[orgptr],&org[orgptr - offs],cnt);
104111
orgptr += cnt;
105112
break;
106113

107114
default:
108-
if(orgptr + cmd > header.size) goto err;
109115
offs = (cnt+3) + (cmp[cmpptr++] << 4);
116+
if (orgptr + cmd > header.size || offs > orgptr) goto err;
110117
memcpy(&org[orgptr],&org[orgptr-offs],cmd);
111118
orgptr += cmd;
112119
break;
113120
}
114121
}
122+
// orgptr should match header.size; add a check?
115123
delete [] cmp;
116124
data = (struct mtkdata *) org;
117125

@@ -123,12 +131,14 @@ bool CmtkLoader::load(const std::string &filename, const CFileProvider &fp)
123131
strncpy(instname[i],data->instname[i]+1,33);
124132
memcpy(instr,data->insts,0x80 * 12);
125133
memcpy(song,data->order,0x80);
126-
memcpy(patterns,data->patterns,header.size-6084);
127134
for (i=0;i<128;i++) { // correct instruments
128135
instr[i][2] ^= (instr[i][2] & 0x40) << 1;
129136
instr[i][3] ^= (instr[i][3] & 0x40) << 1;
130137
instr[i][11] >>= 4; // make unsigned
131138
}
139+
cnt = header.size - (sizeof(*data) - sizeof(data->patterns)); // was off by 1
140+
if (cnt > sizeof(patterns)) cnt = sizeof(patterns); // fail?
141+
memcpy(patterns, data->patterns, cnt);
132142

133143
delete [] org;
134144
rewind(0);

src/mtk.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ class CmtkLoader: public ChscPlayer
4343
unsigned int getinstruments()
4444
{ return 128; };
4545
std::string getinstrument(unsigned int n)
46-
{ return std::string(instname[n]); };
46+
{ return n < 128 ? std::string(instname[n]) : std::string(); };
4747

4848
private:
4949
char title[34],composer[34],instname[0x80][34];

0 commit comments

Comments
 (0)