Fix crash when feeding invalid ranges into flac

This commit is contained in:
badaix 2021-05-05 11:29:42 +02:00
parent 1725cffc6e
commit 5d7aedeb31
5 changed files with 38 additions and 12 deletions

View file

@ -28,7 +28,7 @@ using namespace std;
namespace encoder namespace encoder
{ {
// static constexpr auto LOG_TAG = "FlacEnc"; static constexpr auto LOG_TAG = "FlacEnc";
FlacEncoder::FlacEncoder(const std::string& codecOptions) : Encoder(codecOptions), encoder_(nullptr), pcmBufferSize_(0), encodedSamples_(0), flacChunk_(nullptr) FlacEncoder::FlacEncoder(const std::string& codecOptions) : Encoder(codecOptions), encoder_(nullptr), pcmBufferSize_(0), encodedSamples_(0), flacChunk_(nullptr)
{ {
@ -76,8 +76,8 @@ void FlacEncoder::encode(const msg::PcmChunk& chunk)
int samples = chunk.getSampleCount(); int samples = chunk.getSampleCount();
int frames = chunk.getFrameCount(); int frames = chunk.getFrameCount();
// LOG(INFO, LOG_TAG) << "payload: " << chunk->payloadSize << "\tframes: " << frames << "\tsamples: " << samples << "\tduration: " << // LOG(TRACE, LOG_TAG) << "payload: " << chunk.payloadSize << "\tframes: " << frames << "\tsamples: " << samples
// chunk->duration<chronos::msec>().count() << "\n"; // << "\tduration: " << chunk.duration<chronos::msec>().count() << ", format: " << chunk.format.toString() << "\n";
if (pcmBufferSize_ < samples) if (pcmBufferSize_ < samples)
{ {
@ -85,23 +85,39 @@ void FlacEncoder::encode(const msg::PcmChunk& chunk)
pcmBuffer_ = static_cast<FLAC__int32*>(realloc(pcmBuffer_, pcmBufferSize_ * sizeof(FLAC__int32))); pcmBuffer_ = static_cast<FLAC__int32*>(realloc(pcmBuffer_, pcmBufferSize_ * sizeof(FLAC__int32)));
} }
auto clip = [](int32_t min, int32_t max, int32_t value) -> int32_t {
if (value < min)
return min;
if (value > max)
return max;
return value;
};
if (sampleFormat_.sampleSize() == 1) if (sampleFormat_.sampleSize() == 1)
{ {
auto* buffer = reinterpret_cast<FLAC__int8*>(chunk.payload); auto* buffer = reinterpret_cast<FLAC__int8*>(chunk.payload);
for (int i = 0; i < samples; i++) for (int i = 0; i < samples; i++)
pcmBuffer_[i] = static_cast<FLAC__int32>(buffer[i]); pcmBuffer_[i] = clip(-128, 127, static_cast<FLAC__int32>(buffer[i]));
} }
else if (sampleFormat_.sampleSize() == 2) else if (sampleFormat_.sampleSize() == 2)
{ {
auto* buffer = reinterpret_cast<FLAC__int16*>(chunk.payload); auto* buffer = reinterpret_cast<FLAC__int16*>(chunk.payload);
for (int i = 0; i < samples; i++) for (int i = 0; i < samples; i++)
pcmBuffer_[i] = static_cast<FLAC__int32>(buffer[i]); pcmBuffer_[i] = clip(-32768, 32767, static_cast<FLAC__int32>(buffer[i]));
} }
else if (sampleFormat_.sampleSize() == 4) else if (sampleFormat_.sampleSize() == 4)
{ {
auto* buffer = reinterpret_cast<FLAC__int32*>(chunk.payload); auto* buffer = reinterpret_cast<FLAC__int32*>(chunk.payload);
for (int i = 0; i < samples; i++) if (sampleFormat_.bits() == 24)
pcmBuffer_[i] = buffer[i]; {
for (int i = 0; i < samples; i++)
pcmBuffer_[i] = clip(-8388608, 8388607, buffer[i]);
}
else
{
for (int i = 0; i < samples; i++)
pcmBuffer_[i] = buffer[i];
}
} }
@ -150,20 +166,22 @@ FLAC__StreamEncoderWriteStatus write_callback(const FLAC__StreamEncoder* encoder
void FlacEncoder::initEncoder() void FlacEncoder::initEncoder()
{ {
int quality(2); int compression_level(2);
try try
{ {
quality = cpt::stoi(codecOptions_); compression_level = cpt::stoi(codecOptions_);
} }
catch (...) catch (...)
{ {
throw SnapException("Invalid codec option: \"" + codecOptions_ + "\""); throw SnapException("Invalid codec option: \"" + codecOptions_ + "\"");
} }
if ((quality < 0) || (quality > 8)) if ((compression_level < 0) || (compression_level > 8))
{ {
throw SnapException("compression level has to be between 0 and 8"); throw SnapException("compression level has to be between 0 and 8");
} }
LOG(INFO, LOG_TAG) << "Init - compression level: " << compression_level << "\n";
FLAC__bool ok = 1; FLAC__bool ok = 1;
FLAC__StreamEncoderInitStatus init_status; FLAC__StreamEncoderInitStatus init_status;
FLAC__StreamMetadata_VorbisComment_Entry entry; FLAC__StreamMetadata_VorbisComment_Entry entry;
@ -178,7 +196,7 @@ void FlacEncoder::initEncoder()
// latency: // latency:
// 0-2: 1152 frames, ~26.1224ms // 0-2: 1152 frames, ~26.1224ms
// 3-8: 4096 frames, ~92.8798ms // 3-8: 4096 frames, ~92.8798ms
ok &= FLAC__stream_encoder_set_compression_level(encoder_, quality); ok &= FLAC__stream_encoder_set_compression_level(encoder_, compression_level);
ok &= FLAC__stream_encoder_set_channels(encoder_, sampleFormat_.channels()); ok &= FLAC__stream_encoder_set_channels(encoder_, sampleFormat_.channels());
ok &= FLAC__stream_encoder_set_bits_per_sample(encoder_, sampleFormat_.bits()); ok &= FLAC__stream_encoder_set_bits_per_sample(encoder_, sampleFormat_.bits());
ok &= FLAC__stream_encoder_set_sample_rate(encoder_, sampleFormat_.rate()); ok &= FLAC__stream_encoder_set_sample_rate(encoder_, sampleFormat_.rate());

View file

@ -17,11 +17,13 @@
***/ ***/
#include "null_encoder.hpp" #include "null_encoder.hpp"
#include "common/aixlog.hpp"
namespace encoder namespace encoder
{ {
static constexpr auto LOG_TAG = "NullEnc";
NullEncoder::NullEncoder(const std::string& codecOptions) : Encoder(codecOptions) NullEncoder::NullEncoder(const std::string& codecOptions) : Encoder(codecOptions)
{ {
@ -37,6 +39,7 @@ void NullEncoder::encode(const msg::PcmChunk& chunk)
void NullEncoder::initEncoder() void NullEncoder::initEncoder()
{ {
LOG(INFO, LOG_TAG) << "Init\n";
} }

View file

@ -178,6 +178,8 @@ void OggEncoder::initEncoder()
throw SnapException("compression level has to be between -0.1 and 1.0"); throw SnapException("compression level has to be between -0.1 and 1.0");
} }
LOG(INFO, LOG_TAG) << "Init - quality: " << quality << "\n";
/********** Encode setup ************/ /********** Encode setup ************/
vorbis_info_init(&vi_); vorbis_info_init(&vi_);

View file

@ -144,7 +144,7 @@ void OpusEncoder::initEncoder()
throw SnapException("Opus error parsing options: " + codecOptions_); throw SnapException("Opus error parsing options: " + codecOptions_);
} }
LOG(INFO, LOG_TAG) << "Opus bitrate: " << bitrate << " bps, complexity: " << complexity << "\n"; LOG(INFO, LOG_TAG) << "Init - bitrate: " << bitrate << " bps, complexity: " << complexity << "\n";
int error; int error;
enc_ = opus_encoder_create(sampleFormat_.rate(), sampleFormat_.channels(), OPUS_APPLICATION_RESTRICTED_LOWDELAY, &error); enc_ = opus_encoder_create(sampleFormat_.rate(), sampleFormat_.channels(), OPUS_APPLICATION_RESTRICTED_LOWDELAY, &error);

View file

@ -17,6 +17,7 @@
***/ ***/
#include "pcm_encoder.hpp" #include "pcm_encoder.hpp"
#include "common/aixlog.hpp"
#include "common/endian.hpp" #include "common/endian.hpp"
#include <memory> #include <memory>
@ -29,6 +30,7 @@ static constexpr auto ID_WAVE = 0x45564157;
static constexpr auto ID_FMT = 0x20746d66; static constexpr auto ID_FMT = 0x20746d66;
static constexpr auto ID_DATA = 0x61746164; static constexpr auto ID_DATA = 0x61746164;
static constexpr auto LOG_TAG = "PcmEnc";
namespace namespace
{ {
@ -57,6 +59,7 @@ void PcmEncoder::encode(const msg::PcmChunk& chunk)
void PcmEncoder::initEncoder() void PcmEncoder::initEncoder()
{ {
LOG(INFO, LOG_TAG) << "Init\n";
headerChunk_->payloadSize = 44; headerChunk_->payloadSize = 44;
headerChunk_->payload = static_cast<char*>(realloc(headerChunk_->payload, headerChunk_->payloadSize)); headerChunk_->payload = static_cast<char*>(realloc(headerChunk_->payload, headerChunk_->payloadSize));
char* payload = headerChunk_->payload; char* payload = headerChunk_->payload;