From 2e7a348ea4ec1e040b286582b024af7650bf713b Mon Sep 17 00:00:00 2001 From: Akshay Sonawane Date: Thu, 11 Jun 2026 22:18:56 -0700 Subject: [PATCH 1/3] Add malformed audio check --- src/models/processor.cpp | 10 +++++++++- test/c_api_tests.cpp | 21 +++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/models/processor.cpp b/src/models/processor.cpp index 0b64e8b049..1b0ec859bd 100644 --- a/src/models/processor.cpp +++ b/src/models/processor.cpp @@ -58,9 +58,17 @@ std::unique_ptr LoadAudiosFromBuffers(std::span audio_data, if (audio_data.size() != audio_data_sizes.size()) throw std::runtime_error("Number of audio data buffers does not match the number of audio data sizes"); + // Minimum size to hold a valid audio header (WAV=44 bytes, FLAC=42 bytes, MP3 frame=4 bytes header + data). + // Reject trivially malformed buffers that cannot contain valid audio. + constexpr size_t kMinAudioBufferSize = 44; std::vector sizes; - for (size_t i = 0; i < audio_data_sizes.size(); ++i) + for (size_t i = 0; i < audio_data_sizes.size(); ++i) { + if (audio_data_sizes[i] < kMinAudioBufferSize) + throw std::runtime_error("Audio buffer " + std::to_string(i) + " is too small (" + + std::to_string(audio_data_sizes[i]) + " bytes). Minimum size is " + + std::to_string(kMinAudioBufferSize) + " bytes."); sizes.push_back(audio_data_sizes[i]); + } ort_extensions::OrtxObjectPtr audios; CheckResult(OrtxCreateRawAudios(audios.ToBeAssigned(), audio_data.data(), sizes.data(), audio_data.size())); diff --git a/test/c_api_tests.cpp b/test/c_api_tests.cpp index f6e952a9bd..4762692c75 100644 --- a/test/c_api_tests.cpp +++ b/test/c_api_tests.cpp @@ -1801,3 +1801,24 @@ TEST(CAPITests, ParakeetTdtTranscribeLong) { auto transcription = RunParakeetTdt(PARAKEET_TDT_AUDIO_TEDLIUM); EXPECT_FALSE(transcription.empty()); } + +// Regression test for MSRC: malformed audio buffers smaller than the minimum valid +// audio header size must be rejected with an error, not cause a crash. +TEST(CAPITests, LoadAudiosFromBuffersRejectsTooSmallBuffer) { + // 17 bytes of malformed data that previously triggered a heap-buffer-overflow. + const uint8_t crash_data[] = { + 0xff, 0xff, 0x07, 0xfa, 0xe6, 0xe6, 0xe6, 0xe6, + 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6}; + + const void* data_ptr = crash_data; + size_t data_size = sizeof(crash_data); + OgaAudios* audios = nullptr; + OgaResult* result = OgaLoadAudiosFromBuffers(&data_ptr, &data_size, 1, &audios); + + // Should return an error for buffers too small to be valid audio. + ASSERT_NE(result, nullptr); + EXPECT_NE(std::string(OgaResultGetError(result)).find("too small"), std::string::npos); + OgaDestroyResult(result); + // audios should not have been created + EXPECT_EQ(audios, nullptr); +} From 3d72a7a353dcd70ec406b7b73facccd835d87c20 Mon Sep 17 00:00:00 2001 From: Akshay Sonawane Date: Thu, 11 Jun 2026 22:55:47 -0700 Subject: [PATCH 2/3] Fix wording --- src/models/processor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/models/processor.cpp b/src/models/processor.cpp index 1b0ec859bd..37b64924c7 100644 --- a/src/models/processor.cpp +++ b/src/models/processor.cpp @@ -58,8 +58,8 @@ std::unique_ptr LoadAudiosFromBuffers(std::span audio_data, if (audio_data.size() != audio_data_sizes.size()) throw std::runtime_error("Number of audio data buffers does not match the number of audio data sizes"); - // Minimum size to hold a valid audio header (WAV=44 bytes, FLAC=42 bytes, MP3 frame=4 bytes header + data). - // Reject trivially malformed buffers that cannot contain valid audio. + // Conservative minimum buffer size to avoid decoder header parsing reading past the end of the buffer. + // 44 bytes matches the standard WAV header size; this is a safety check, not full format validation. constexpr size_t kMinAudioBufferSize = 44; std::vector sizes; for (size_t i = 0; i < audio_data_sizes.size(); ++i) { From 15cddfe6148a3bfa8e22530cb27a197e8d5f4510 Mon Sep 17 00:00:00 2001 From: Akshay Sonawane Date: Fri, 12 Jun 2026 16:30:43 -0700 Subject: [PATCH 3/3] Address comments --- src/models/processor.cpp | 9 ++------- test/c_api_tests.cpp | 15 +++++---------- 2 files changed, 7 insertions(+), 17 deletions(-) diff --git a/src/models/processor.cpp b/src/models/processor.cpp index 37b64924c7..361e8685f6 100644 --- a/src/models/processor.cpp +++ b/src/models/processor.cpp @@ -58,15 +58,10 @@ std::unique_ptr LoadAudiosFromBuffers(std::span audio_data, if (audio_data.size() != audio_data_sizes.size()) throw std::runtime_error("Number of audio data buffers does not match the number of audio data sizes"); - // Conservative minimum buffer size to avoid decoder header parsing reading past the end of the buffer. - // 44 bytes matches the standard WAV header size; this is a safety check, not full format validation. - constexpr size_t kMinAudioBufferSize = 44; std::vector sizes; for (size_t i = 0; i < audio_data_sizes.size(); ++i) { - if (audio_data_sizes[i] < kMinAudioBufferSize) - throw std::runtime_error("Audio buffer " + std::to_string(i) + " is too small (" + - std::to_string(audio_data_sizes[i]) + " bytes). Minimum size is " + - std::to_string(kMinAudioBufferSize) + " bytes."); + if (audio_data_sizes[i] == 0) + throw std::runtime_error("Audio buffer " + std::to_string(i) + " is empty."); sizes.push_back(audio_data_sizes[i]); } diff --git a/test/c_api_tests.cpp b/test/c_api_tests.cpp index 4762692c75..3a8fe46a04 100644 --- a/test/c_api_tests.cpp +++ b/test/c_api_tests.cpp @@ -1804,20 +1804,15 @@ TEST(CAPITests, ParakeetTdtTranscribeLong) { // Regression test for MSRC: malformed audio buffers smaller than the minimum valid // audio header size must be rejected with an error, not cause a crash. -TEST(CAPITests, LoadAudiosFromBuffersRejectsTooSmallBuffer) { - // 17 bytes of malformed data that previously triggered a heap-buffer-overflow. - const uint8_t crash_data[] = { - 0xff, 0xff, 0x07, 0xfa, 0xe6, 0xe6, 0xe6, 0xe6, - 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6}; - - const void* data_ptr = crash_data; - size_t data_size = sizeof(crash_data); +TEST(CAPITests, LoadAudiosFromBuffersRejectsEmptyBuffer) { + const void* data_ptr = nullptr; + size_t data_size = 0; OgaAudios* audios = nullptr; OgaResult* result = OgaLoadAudiosFromBuffers(&data_ptr, &data_size, 1, &audios); - // Should return an error for buffers too small to be valid audio. + // Should return an error for empty buffers. ASSERT_NE(result, nullptr); - EXPECT_NE(std::string(OgaResultGetError(result)).find("too small"), std::string::npos); + EXPECT_NE(std::string(OgaResultGetError(result)).find("empty"), std::string::npos); OgaDestroyResult(result); // audios should not have been created EXPECT_EQ(audios, nullptr);