summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/atrac/at1/atrac1.cpp11
-rw-r--r--src/atrac1denc.cpp20
-rw-r--r--src/lib/bitstream/bitstream.cpp11
3 files changed, 36 insertions, 6 deletions
diff --git a/src/atrac/at1/atrac1.cpp b/src/atrac/at1/atrac1.cpp
index b361ad5..fd11c66 100644
--- a/src/atrac/at1/atrac1.cpp
+++ b/src/atrac/at1/atrac1.cpp
@@ -19,6 +19,8 @@
#include "atrac1.h"
#include "bitstream/bitstream.h"
+#include <stdexcept>
+
namespace NAtracDEnc {
namespace NAtrac1 {
@@ -38,6 +40,15 @@ std::array<int, 3> TAtrac1Data::TBlockSizeMod::Parse(NBitStream::TBitStream* str
tmp[1] = 2 - stream->Read(2);
tmp[2] = 3 - stream->Read(2);
stream->Read(2); //skip unused 2 bits
+
+ // LogCount is used as the shift count for the number of MDCT blocks
+ // (1 << LogCount). A malformed frame can encode a value that makes this
+ // negative, which is undefined behaviour and leads to out-of-bounds
+ // access during the (I)MDCT. Reject such frames.
+ for (int i = 0; i < 3; i++) {
+ if (tmp[i] < 0)
+ throw std::runtime_error("invalid ATRAC1 block size mode");
+ }
return tmp;
}
diff --git a/src/atrac1denc.cpp b/src/atrac1denc.cpp
index 5c362fd..b30b72f 100644
--- a/src/atrac1denc.cpp
+++ b/src/atrac1denc.cpp
@@ -145,11 +145,21 @@ TPCMEngine::TProcessLambda TAtrac1Decoder::GetLambda() {
TBitStream bitstream(frame->Get(), frame->Size());
- TAtrac1Data::TBlockSizeMod mode(&bitstream);
- TAtrac1Dequantiser dequantiser;
- vector<float> specs;
- specs.resize(512);;
- dequantiser.Dequant(&bitstream, mode, &specs[0]);
+ vector<float> specs(512, 0.0f);
+ TAtrac1Data::TBlockSizeMod mode;
+
+ try {
+ mode = TAtrac1Data::TBlockSizeMod(&bitstream);
+ TAtrac1Dequantiser dequantiser;
+ dequantiser.Dequant(&bitstream, mode, &specs[0]);
+ } catch (const std::exception& e) {
+ // Malformed frame: decode it as a silent frame (zero spectrum,
+ // neutral block size) so the per-channel overlap/QMF state stays
+ // consistent for the frames that follow.
+ std::cerr << "Skipping invalid ATRAC1 frame: " << e.what() << std::endl;
+ specs.assign(512, 0.0f);
+ mode = TAtrac1Data::TBlockSizeMod();
+ }
IMdct(&specs[0], mode, &PcmBufLow[channel][0], &PcmBufMid[channel][0], &PcmBufHi[channel][0]);
SynthesisFilterBank[channel].Synthesis(&sum[0], &PcmBufLow[channel][0], &PcmBufMid[channel][0], &PcmBufHi[channel][0]);
diff --git a/src/lib/bitstream/bitstream.cpp b/src/lib/bitstream/bitstream.cpp
index ddff907..f731c0a 100644
--- a/src/lib/bitstream/bitstream.cpp
+++ b/src/lib/bitstream/bitstream.cpp
@@ -16,6 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <cstdint>
+#include <stdexcept>
#include "bitstream.h"
#ifndef BIGENDIAN_ORDER
@@ -67,8 +68,16 @@ uint32_t TBitStream::Read(int n) {
const int bytesPos = ReadPos / 8;
const int overlap = ReadPos % 8;
+ // A malformed frame can request more bits than it actually contains.
+ // Reading past the end of the buffer would be out-of-bounds access.
+ if (ReadPos + n > (int)Buf.size() * 8)
+ throw std::runtime_error("read past the end of the bitstream");
+
+ // Number of bytes the requested value actually spans, starting at bytesPos.
+ const int bytesToRead = (overlap + n + 7) / 8;
+
UBytes t;
- for (int i = 0; i < n/8 + (overlap ? 2 : 1); ++i) {
+ for (int i = 0; i < bytesToRead; ++i) {
#ifdef NBITSTREAM__LITTLE_ENDIAN_CPU
t.bytes[3-i] = (uint8_t)Buf[bytesPos+i];
#else