Merge pull request #15039 from MarcZX10/fix/p15-ngs2-waveform-bounds

fix(libSceNgs2): reject ATRAC9 data chunks larger than the buffer
This commit is contained in:
Dean authored and GitHub committed 2026-11-05 08:20:26 +13:00
commit 3aeaadbeba
2 files changed
+15 -3

No files matched your search

@@ -413,9 +413,10 @@ static int ParseAtrac9Loop(const RiffChunks& chunks, Ngs2WaveformInfo& info) {
return SCE_NGS2_OK;
}
static int ParseAtrac9(const RiffChunks& chunks, Ngs2WaveformInfo& info) {
static int ParseAtrac9(const RiffChunks& chunks, std::size_t size, Ngs2WaveformInfo& info) {
const auto* format = chunks.format;
if (chunks.formatSize < FMT_ATRAC9_SIZE || chunks.fact == nullptr || chunks.factSize < FACT_ATRAC9_SIZE) return SCE_NGS2_ERROR_INVALID_WAVEFORM_FORMAT;
if (chunks.dataSize > size - chunks.dataOffset) return SCE_NGS2_ERROR_INVALID_WAVEFORM_DATA;
std::uint8_t config[4];
std::memcpy(config, format + FMT_CONFIG_OFFSET, sizeof(config));
Atrac9CodecInfo codec{};
@@ -507,7 +508,7 @@ static int ParseWaveform(const RiffChunks& chunks, std::size_t size, Ngs2Wavefor
if (chunks.formatSize < FMT_EXTENSIBLE_SIZE) return SCE_NGS2_ERROR_UNKNOWN_WAVEFORM_FORMAT;
const auto* guid = chunks.format + FMT_GUID_OFFSET;
if (std::memcmp(guid, PCM_GUID, sizeof(PCM_GUID)) == 0) return ParsePcm(chunks, size, info, false);
if (std::memcmp(guid, ATRAC9_GUID, sizeof(ATRAC9_GUID)) == 0) return ParseAtrac9(chunks, info);
if (std::memcmp(guid, ATRAC9_GUID, sizeof(ATRAC9_GUID)) == 0) return ParseAtrac9(chunks, size, info);
if (chunks.formatSize == FMT_ATRAC9_SIZE) throw std::runtime_error("NGS2: parsing an extensible waveform of format size 0x34 without the ATRAC9 GUID is not implemented");
if (std::memcmp(guid, TYPE_43_GUID, sizeof(TYPE_43_GUID)) == 0) throw std::runtime_error("NGS2: parsing waveform type 0x43 is not implemented");
return SCE_NGS2_ERROR_UNKNOWN_WAVEFORM_FORMAT;
@@ -376,7 +376,7 @@ static void TestParseLoops() {
}
const auto file = LoopedFile(100, 700, 0);
Ngs2WaveformInfo info{};
Require(sceNgs2ParseWaveformData(file.data(), 168, &info) == SCE_NGS2_OK);
Require(sceNgs2ParseWaveformData(file.data(), file.size(), &info) == SCE_NGS2_OK);
Require(info.block[1].num_repeats == UINT32_MAX);
const auto system = CreateSystem();
const auto voice = Voice(CreateRack(system, SCE_NGS2_RACK_ID_SAMPLER));
@@ -743,6 +743,16 @@ static void TestStreamingReplay() {
}
}
static void TestDataChunkBeyondBuffer() {
const auto file = At9File(48000);
Ngs2WaveformInfo info{};
Require(sceNgs2ParseWaveformData(file.data(), file.size(), &info) == SCE_NGS2_OK && info.data_size == SuperframeBytes);
auto truncated = file;
Set32(truncated, 4, static_cast<std::uint32_t>(truncated.size() - 8 + 16));
Set32(truncated, 96, SuperframeBytes + 16);
Require(sceNgs2ParseWaveformData(truncated.data(), truncated.size(), &info) == SCE_NGS2_ERROR_INVALID_WAVEFORM_DATA);
}
int main() {
const auto reference = Reference();
TestSkipAndBlockEnd(reference);
@@ -764,5 +774,6 @@ int main() {
TestBlockOnEmptyAtrac9Voice();
TestEmptyAddsCloseLikePcm();
TestSilenceFlagRejected();
TestDataChunkBeyondBuffer();
return 0;
}