diff options
author | Bastien Bouclet | 2017-11-08 20:27:47 +0100 |
---|---|---|
committer | Bastien Bouclet | 2017-11-08 20:57:24 +0100 |
commit | bf3c98815fa25a1af6544dc3a30636743aa81996 (patch) | |
tree | ca26b6c350132e479f69de4894e4e060b4d6f618 | |
parent | 8e8ec3900c90fc9e18571df84c5e9e754479052b (diff) | |
download | scummvm-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.cpp | 69 |
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"); } |