aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastien Bouclet2017-11-08 20:27:47 +0100
committerBastien Bouclet2017-11-08 20:57:24 +0100
commitbf3c98815fa25a1af6544dc3a30636743aa81996 (patch)
treeca26b6c350132e479f69de4894e4e060b4d6f618
parent8e8ec3900c90fc9e18571df84c5e9e754479052b (diff)
downloadscummvm-rg350-bf3c98815fa25a1af6544dc3a30636743aa81996.tar.gz
scummvm-rg350-bf3c98815fa25a1af6544dc3a30636743aa81996.tar.bz2
scummvm-rg350-bf3c98815fa25a1af6544dc3a30636743aa81996.zip
AUDIO: Add some padding to the QDM2 decoder input buffer
Fixes out of bounds reads in the Myst ME intro videos. OOB reads may happen because: - The bitstream implementation reads 4 bytes at a time, and the buffer size is not guaranteed to be a multiple of 4. - The huffman parsing code reads a fixed amount of bits when it sometimes needs not all of them. Also fixed bits vs bytes mismatch for the size parameter of the calls to the bitstream constructor, and removed a few unnecessary heap allocations. Fixes #10220.
-rw-r--r--audio/decoders/qdm2.cpp69
1 files changed, 29 insertions, 40 deletions
diff --git a/audio/decoders/qdm2.cpp b/audio/decoders/qdm2.cpp
index 4454fd08c9..dd04e01e38 100644
--- a/audio/decoders/qdm2.cpp
+++ b/audio/decoders/qdm2.cpp
@@ -1210,7 +1210,7 @@ QDM2Stream::QDM2Stream(Common::SeekableReadStream *extraData, DisposeAfterUse::F
rndTableInit();
initNoiseSamples();
- _compressedData = new uint8[_packetSize];
+ _compressedData = new uint8[_packetSize + FF_INPUT_BUFFER_PADDING_SIZE];
if (disposeExtraData == DisposeAfterUse::YES)
delete extraData;
@@ -1885,7 +1885,7 @@ void QDM2Stream::init_tone_level_dequantization(Common::BitStream32LELSB *gb, in
void QDM2Stream::process_subpacket_9(QDM2SubPNode *node) {
int i, j, k, n, ch, run, level, diff;
- Common::MemoryReadStream d(node->packet->data, node->packet->size*8);
+ Common::MemoryReadStream d(node->packet->data, node->packet->size + FF_INPUT_BUFFER_PADDING_SIZE);
Common::BitStream32LELSB gb(&d);
n = coeff_per_sb_for_avg[_coeffPerSbSelect][QDM2_SB_USED(_subSampling) - 1] + 1; // same as averagesomething function
@@ -1919,7 +1919,7 @@ void QDM2Stream::process_subpacket_9(QDM2SubPNode *node) {
* @param length packet length in bits
*/
void QDM2Stream::process_subpacket_10(QDM2SubPNode *node, int length) {
- Common::MemoryReadStream d(((node == NULL) ? _emptyBuffer : node->packet->data), ((node == NULL) ? 0 : node->packet->size*8));
+ Common::MemoryReadStream d(((node == NULL) ? _emptyBuffer : node->packet->data), ((node == NULL) ? 0 : node->packet->size + FF_INPUT_BUFFER_PADDING_SIZE));
Common::BitStream32LELSB gb(&d);
if (length != 0) {
@@ -1937,7 +1937,7 @@ void QDM2Stream::process_subpacket_10(QDM2SubPNode *node, int length) {
* @param length packet length in bit
*/
void QDM2Stream::process_subpacket_11(QDM2SubPNode *node, int length) {
- Common::MemoryReadStream d(((node == NULL) ? _emptyBuffer : node->packet->data), ((node == NULL) ? 0 : node->packet->size*8));
+ Common::MemoryReadStream d(((node == NULL) ? _emptyBuffer : node->packet->data), ((node == NULL) ? 0 : node->packet->size + FF_INPUT_BUFFER_PADDING_SIZE));
Common::BitStream32LELSB gb(&d);
if (length >= 32) {
@@ -1958,7 +1958,7 @@ void QDM2Stream::process_subpacket_11(QDM2SubPNode *node, int length) {
* @param length packet length in bits
*/
void QDM2Stream::process_subpacket_12(QDM2SubPNode *node, int length) {
- Common::MemoryReadStream d(((node == NULL) ? _emptyBuffer : node->packet->data), ((node == NULL) ? 0 : node->packet->size*8));
+ Common::MemoryReadStream d(((node == NULL) ? _emptyBuffer : node->packet->data), ((node == NULL) ? 0 : node->packet->size + FF_INPUT_BUFFER_PADDING_SIZE));
Common::BitStream32LELSB gb(&d);
synthfilt_build_sb_samples(&gb, length, 8, QDM2_SB_USED(_subSampling));
@@ -2013,27 +2013,27 @@ void QDM2Stream::qdm2_decode_super_block(void) {
average_quantized_coeffs(); // average elements in quantized_coeffs[max_ch][10][8]
- Common::MemoryReadStream *d = new Common::MemoryReadStream(_compressedData, _packetSize*8);
- Common::BitStream32LELSB *gb = new Common::BitStream32LELSB(d);
+ Common::MemoryReadStream packetStream(_compressedData, _packetSize + FF_INPUT_BUFFER_PADDING_SIZE);
+ Common::BitStream32LELSB packetBitStream(packetStream);
//qdm2_decode_sub_packet_header
- header.type = gb->getBits(8);
+ header.type = packetBitStream.getBits(8);
if (header.type == 0) {
header.size = 0;
header.data = NULL;
} else {
- header.size = gb->getBits(8);
+ header.size = packetBitStream.getBits(8);
if (header.type & 0x80) {
header.size <<= 8;
- header.size |= gb->getBits(8);
+ header.size |= packetBitStream.getBits(8);
header.type &= 0x7f;
}
if (header.type == 0x7f)
- header.type |= (gb->getBits(8) << 8);
+ header.type |= (packetBitStream.getBits(8) << 8);
- header.data = &_compressedData[gb->pos() / 8];
+ header.data = &_compressedData[packetBitStream.pos() / 8];
}
if (header.type < 2 || header.type >= 8) {
@@ -2043,15 +2043,13 @@ void QDM2Stream::qdm2_decode_super_block(void) {
}
_superblocktype_2_3 = (header.type == 2 || header.type == 3);
- packet_bytes = (_packetSize - gb->pos() / 8);
+ packet_bytes = (_packetSize - packetBitStream.pos() / 8);
- delete gb;
- delete d;
- d = new Common::MemoryReadStream(header.data, header.size*8);
- gb = new Common::BitStream32LELSB(d);
+ Common::MemoryReadStream headerStream(header.data, header.size + FF_INPUT_BUFFER_PADDING_SIZE);
+ Common::BitStream32LELSB headerBitStream(headerStream);
if (header.type == 2 || header.type == 4 || header.type == 5) {
- int csum = 257 * gb->getBits(8) + 2 * gb->getBits(8);
+ int csum = 257 * headerBitStream.getBits(8) + 2 * headerBitStream.getBits(8);
csum = qdm2_packet_checksum(_compressedData, _packetSize, csum);
@@ -2077,41 +2075,37 @@ void QDM2Stream::qdm2_decode_super_block(void) {
if (i > 0) {
_subPacketListA[i - 1].next = &_subPacketListA[i];
- // seek to next block
- delete gb;
- delete d;
- d = new Common::MemoryReadStream(header.data, header.size*8);
- gb = new Common::BitStream32LELSB(d);
- gb->skip(next_index*8);
-
if (next_index >= header.size)
break;
+
+ // seek to next block
+ headerBitStream.skip(next_index * 8 - headerBitStream.pos());
}
// decode subpacket
packet = &_subPackets[i];
//qdm2_decode_sub_packet_header
- packet->type = gb->getBits(8);
+ packet->type = headerBitStream.getBits(8);
if (packet->type == 0) {
packet->size = 0;
packet->data = NULL;
} else {
- packet->size = gb->getBits(8);
+ packet->size = headerBitStream.getBits(8);
if (packet->type & 0x80) {
packet->size <<= 8;
- packet->size |= gb->getBits(8);
+ packet->size |= headerBitStream.getBits(8);
packet->type &= 0x7f;
}
if (packet->type == 0x7f)
- packet->type |= (gb->getBits(8) << 8);
+ packet->type |= (headerBitStream.getBits(8) << 8);
- packet->data = &header.data[gb->pos() / 8];
+ packet->data = &header.data[headerBitStream.pos() / 8];
}
- next_index = packet->size + gb->pos() / 8;
+ next_index = packet->size + headerBitStream.pos() / 8;
sub_packet_size = ((packet->size > 0xff) ? 1 : 0) + packet->size + 2;
if (packet->type == 0)
@@ -2131,22 +2125,18 @@ void QDM2Stream::qdm2_decode_super_block(void) {
// add subpacket to related list
if (packet->type == 8) {
error("Unsupported packet type 8");
- delete gb;
- delete d;
return;
} else if (packet->type >= 9 && packet->type <= 12) {
// packets for MPEG Audio like Synthesis Filter
QDM2_LIST_ADD(_subPacketListD, subPacketsD, packet);
} else if (packet->type == 13) {
for (j = 0; j < 6; j++)
- _fftLevelExp[j] = gb->getBits(6);
+ _fftLevelExp[j] = headerBitStream.getBits(6);
} else if (packet->type == 14) {
for (j = 0; j < 6; j++)
- _fftLevelExp[j] = qdm2_get_vlc(gb, &_fftLevelExpVlc, 0, 2);
+ _fftLevelExp[j] = qdm2_get_vlc(&headerBitStream, &_fftLevelExpVlc, 0, 2);
} else if (packet->type == 15) {
error("Unsupported packet type 15");
- delete gb;
- delete d;
return;
} else if (packet->type >= 16 && packet->type < 48 && !fft_subpackets[packet->type - 16]) {
// packets for FFT
@@ -2164,8 +2154,6 @@ void QDM2Stream::qdm2_decode_super_block(void) {
process_subpacket_12(NULL, 0);
}
// ****************************************************************
- delete gb;
- delete d;
}
void QDM2Stream::qdm2_fft_init_coefficient(int sub_packet, int offset, int duration,
@@ -2290,7 +2278,7 @@ void QDM2Stream::qdm2_decode_fft_packets(void) {
return;
// decode FFT tones
- Common::MemoryReadStream d(packet->data, packet->size*8);
+ Common::MemoryReadStream d(packet->data, packet->size + FF_INPUT_BUFFER_PADDING_SIZE);
Common::BitStream32LELSB gb(&d);
if (packet->type >= 32 && packet->type < 48 && !fft_subpackets[packet->type - 16])
@@ -2514,6 +2502,7 @@ bool QDM2Stream::qdm2_decodeFrame(Common::SeekableReadStream &in, QueuingAudioSt
if (!in.eos()) {
in.read(_compressedData, _packetSize);
+ memset(_compressedData + _packetSize, 0, FF_INPUT_BUFFER_PADDING_SIZE);
debug(1, "QDM2Stream::qdm2_decodeFrame constructed input data");
}