From 366c8315f97c715da70d6572e2d80bd3edcfb9a3 Mon Sep 17 00:00:00 2001 From: Michal Kulakowski Date: Fri, 11 Sep 2026 14:56:16 +0200 Subject: [PATCH 1/3] Improve OMNI input validation --- src/audio/audio_utils.cpp | 16 ++++++++++++---- src/test/audio/audio_utils_test.cpp | 20 ++++++++++++++++++++ 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/audio/audio_utils.cpp b/src/audio/audio_utils.cpp index 5c0136c1a6..080678d018 100644 --- a/src/audio/audio_utils.cpp +++ b/src/audio/audio_utils.cpp @@ -105,12 +105,20 @@ std::vector readWav(const std::string_view& wavData, uint32_t targetSampl drwav_uninit(&wav); throw std::runtime_error("WAV file header claims more frames than possible from data chunk size"); } - // Validate decoded buffer size before resampling (float32 mono output) + // Validate decoded buffer size before any large allocations. This must also run in + // no-resample mode, which is used by Omni audio input requests and should respect the + // same `OVMS_AUDIO_MAX_FILE_SIZE_BYTES` limit. + const uint64_t n = wav.totalPCMFrameCount; + size_t decodedSamples = static_cast(n); + if (decodedSamples > std::numeric_limits::max() / sizeof(float)) { + drwav_uninit(&wav); + throw std::overflow_error("Decoded audio buffer size overflow"); + } if (targetSampleRate > 0) { - validateAudioFileSize(wav.totalPCMFrameCount, wav.sampleRate, targetSampleRate, /*will be downmixed to mono*/ 1, sizeof(float)); + validateAudioFileSize(n, wav.sampleRate, targetSampleRate, /*will be downmixed to mono*/ 1, sizeof(float)); + } else { + validateAudioFileSizeAgainstMaxValue(decodedSamples * sizeof(float)); } - - const uint64_t n = wav.totalPCMFrameCount; std::vector pcm16; if (n > AUDIO_BUFFER_SIZE_LIMIT / wav.channels) { drwav_uninit(&wav); diff --git a/src/test/audio/audio_utils_test.cpp b/src/test/audio/audio_utils_test.cpp index ede322830d..2161d20864 100644 --- a/src/test/audio/audio_utils_test.cpp +++ b/src/test/audio/audio_utils_test.cpp @@ -160,6 +160,26 @@ TEST_F(AudioUtilsSampleRateTest, wavFileAcceptedWhenAtMaxFileSizeEnv) { UnSetEnvironmentVar("OVMS_AUDIO_MAX_FILE_SIZE_BYTES"); } +TEST_F(AudioUtilsSampleRateTest, readWithoutResampleWavRejectedWhenExceedsMaxFileSizeEnv) { + const std::string wav = buildWavBuffer(/*sampleRate=*/16000, /*numSamples=*/16); + std::string_view view(wav); + size_t expectedDecodedSize = static_cast(16 * sizeof(float)); + SetEnvironmentVar("OVMS_AUDIO_MAX_FILE_SIZE_BYTES", std::to_string(expectedDecodedSize - 1)); + EXPECT_THROW({ auto decoded = readWithoutResample(view, "wav"); }, std::runtime_error); + UnSetEnvironmentVar("OVMS_AUDIO_MAX_FILE_SIZE_BYTES"); +} + +TEST_F(AudioUtilsSampleRateTest, readWithoutResampleWavAcceptedWhenAtMaxFileSizeEnv) { + const std::string wav = buildWavBuffer(/*sampleRate=*/32000, /*numSamples=*/16); + std::string_view view(wav); + size_t expectedDecodedSize = static_cast(8 * sizeof(float)); + SetEnvironmentVar("OVMS_AUDIO_MAX_FILE_SIZE_BYTES", std::to_string(expectedDecodedSize)); + std::vector decoded; + EXPECT_NO_THROW({ decoded = readWithoutResample(view, "wav"); }); + EXPECT_EQ(decoded.size(), 8u); + UnSetEnvironmentVar("OVMS_AUDIO_MAX_FILE_SIZE_BYTES"); +} + TEST_F(AudioUtilsSampleRateTest, mp3FileRejectedWhenExceedsMaxFileSizeEnv) { // Minimal valid MP3 frame (see previous test for structure) std::string mp3; From 928d2de441511dbab842343ee75728be05890400 Mon Sep 17 00:00:00 2001 From: Michal Kulakowski Date: Fri, 11 Sep 2026 14:57:01 +0200 Subject: [PATCH 2/3] fix --- src/audio/audio_utils.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/audio/audio_utils.cpp b/src/audio/audio_utils.cpp index 080678d018..6caaafa245 100644 --- a/src/audio/audio_utils.cpp +++ b/src/audio/audio_utils.cpp @@ -105,9 +105,7 @@ std::vector readWav(const std::string_view& wavData, uint32_t targetSampl drwav_uninit(&wav); throw std::runtime_error("WAV file header claims more frames than possible from data chunk size"); } - // Validate decoded buffer size before any large allocations. This must also run in - // no-resample mode, which is used by Omni audio input requests and should respect the - // same `OVMS_AUDIO_MAX_FILE_SIZE_BYTES` limit. + // Validate decoded buffer size before any large allocations. const uint64_t n = wav.totalPCMFrameCount; size_t decodedSamples = static_cast(n); if (decodedSamples > std::numeric_limits::max() / sizeof(float)) { From 3fa7dec38edf68552f28d44289e02c189e19ebc4 Mon Sep 17 00:00:00 2001 From: Michal Kulakowski Date: Fri, 11 Sep 2026 14:59:05 +0200 Subject: [PATCH 3/3] fix --- src/test/audio/audio_utils_test.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/test/audio/audio_utils_test.cpp b/src/test/audio/audio_utils_test.cpp index 2161d20864..d9a3200e84 100644 --- a/src/test/audio/audio_utils_test.cpp +++ b/src/test/audio/audio_utils_test.cpp @@ -172,11 +172,12 @@ TEST_F(AudioUtilsSampleRateTest, readWithoutResampleWavRejectedWhenExceedsMaxFil TEST_F(AudioUtilsSampleRateTest, readWithoutResampleWavAcceptedWhenAtMaxFileSizeEnv) { const std::string wav = buildWavBuffer(/*sampleRate=*/32000, /*numSamples=*/16); std::string_view view(wav); - size_t expectedDecodedSize = static_cast(8 * sizeof(float)); + // Native-rate WAV decode keeps the full 16 float samples, or 64 bytes total. + size_t expectedDecodedSize = static_cast(16 * sizeof(float)); SetEnvironmentVar("OVMS_AUDIO_MAX_FILE_SIZE_BYTES", std::to_string(expectedDecodedSize)); std::vector decoded; EXPECT_NO_THROW({ decoded = readWithoutResample(view, "wav"); }); - EXPECT_EQ(decoded.size(), 8u); + EXPECT_EQ(decoded.size(), 16u); UnSetEnvironmentVar("OVMS_AUDIO_MAX_FILE_SIZE_BYTES"); }