From 53cd8ffa3f798e9d4f6b263c7abafbc20a32489d Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Tue, 11 Aug 2026 12:30:54 +1200 Subject: [PATCH] Fix stack overflow in ZeldaHLE Independently spotted by both @Dentomologist and me while reviewing PR #14805 The previous limit was correct for valid VPBs, but an invalid VPB controlled by a malicious game could contain a non-fractional value in current_pos_frac, which would allow writing an extra 15 samples (30 bytes) into the stack. With AFC encoding, this is rounded up to 16 samples, but with much less control over which bytes are written. Maybe we should be doing some validation, or bounds checking, but I'm pretty sure this issue was copied from the original ucode, and we kinda want to stay compatible. The simpler fix is to just increase the size of raw_input_samples. I've checked other code paths, and 0x514 samples seems to be the limit. --- Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp index 5db3c55aa8..2ea037b9d3 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp +++ b/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp @@ -1468,9 +1468,16 @@ void ZeldaAudioRenderer::LoadInputSamples(MixingBuffer* buffer, VPB* vpb) // the end of processing, if needed. // // Maximum of 0x500 samples here - see NeededRawSamplesCount to understand - // this practical limit (resampling_ratio = 0xFFFF -> 0x500 samples). Add a - // margin of 4 that is needed for samples source that do resampling. - std::array raw_input_samples; + // this practical limit (resampling_ratio = 0xFFFF -> 0x500 samples). + // + // If current_pos_frac contains an (invalid) non-fractional part, it can push + // this up by another 15 samples. Which DownloadAFCSamplesFromARAM then rounds + // up to the next multiple of 16. So add an extra 0x10 samples to be safe. + // + // Plus we need an extra four samples at the start to hold the last four + // samples from the previous frame. + + std::array raw_input_samples; for (size_t i = 0; i < 4; ++i) raw_input_samples[i] = vpb->resample_buffer[i];