From c44d787df45b6d0f7f8925dd89a124c7fbda3a76 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 7 Aug 2022 14:58:14 -0700 Subject: [PATCH] Mpeg: Check memory access range on GetPointer(). --- Core/HLE/sceMpeg.cpp | 17 ++++++--- Core/HW/MediaEngine.cpp | 77 +++++++++++++++++++------------------- Core/HW/SimpleAudioDec.cpp | 13 +++++-- 3 files changed, 59 insertions(+), 48 deletions(-) diff --git a/Core/HLE/sceMpeg.cpp b/Core/HLE/sceMpeg.cpp index 5bfeb81dfb..02c66b6268 100644 --- a/Core/HLE/sceMpeg.cpp +++ b/Core/HLE/sceMpeg.cpp @@ -974,7 +974,9 @@ static bool decodePmpVideo(PSPPointer ringbuffer, u32 pmpctxA for (int i = 0; i < pmp_nBlocks; i++){ auto lli = PSPPointer::Create(pmp_videoSource); // add source block into pmpframes - pmpframes->add(Memory::GetPointerWrite(lli->pSrc), lli->iSize); + const uint8_t *ptr = Memory::GetPointerRange(lli->pSrc, lli->iSize); + if (ptr) + pmpframes->add(ptr, lli->iSize); // get next block pmp_videoSource += sizeof(SceMpegLLI); } @@ -1502,7 +1504,6 @@ void PostPutAction::run(MipsCall &call) { MpegContext *ctx = getMpegCtx(ringbuffer->mpeg); int writeOffset = ringbuffer->packetsWritePos % (s32)ringbuffer->packets; - const u8 *data = Memory::GetPointer(ringbuffer->data + writeOffset * 2048); int packetsAddedThisRound = currentMIPS->r[MIPS_REG_V0]; if (packetsAddedThisRound > 0) { @@ -1514,9 +1515,10 @@ void PostPutAction::run(MipsCall &call) { // TODO: Faster / less wasteful validation. std::unique_ptr demuxer(new MpegDemux(packetsAddedThisRound * 2048, 0)); int readOffset = ringbuffer->packetsRead % (s32)ringbuffer->packets; + uint32_t bufSize = Memory::ValidSize(ringbuffer->data + readOffset * 2048, packetsAddedThisRound * 2048); const u8 *buf = Memory::GetPointer(ringbuffer->data + readOffset * 2048); bool invalid = false; - for (int i = 0; i < packetsAddedThisRound; ++i) { + for (uint32_t i = 0; i < bufSize / 2048; ++i) { demuxer->addStreamData(buf, 2048); buf += 2048; @@ -1548,7 +1550,9 @@ void PostPutAction::run(MipsCall &call) { WARN_LOG(ME, "sceMpegRingbufferPut clamping packetsAdded old=%i new=%i", packetsAddedThisRound, ringbuffer->packets - ringbuffer->packetsAvail); packetsAddedThisRound = ringbuffer->packets - ringbuffer->packetsAvail; } - int actuallyAdded = ctx->mediaengine == NULL ? 8 : ctx->mediaengine->addStreamData(data, packetsAddedThisRound * 2048) / 2048; + const u8 *data = Memory::GetPointer(ringbuffer->data + writeOffset * 2048); + uint32_t dataSize = Memory::ValidSize(ringbuffer->data + writeOffset * 2048, packetsAddedThisRound * 2048); + int actuallyAdded = ctx->mediaengine == NULL ? 8 : ctx->mediaengine->addStreamData(data, dataSize) / 2048; if (actuallyAdded != packetsAddedThisRound) { WARN_LOG_REPORT(ME, "sceMpegRingbufferPut(): unable to enqueue all added packets, going to overwrite some frames."); } @@ -2175,10 +2179,13 @@ static int __MpegAvcConvertToYuv420(const void *data, u32 bufferOutputAddr, int u32 *imageBuffer = (u32*)data; int sizeY = width * height; int sizeCb = sizeY >> 2; - u8 *Y = (u8*)Memory::GetPointer(bufferOutputAddr); + u8 *Y = Memory::GetPointerWriteRange(bufferOutputAddr, sizeY + sizeCb + sizeCb); u8 *Cb = Y + sizeY; u8 *Cr = Cb + sizeCb; + if (!Y) + return hleLogError(ME, 0, "Bad output buffer pointer for yuv conv: %08x", bufferOutputAddr); + for (int y = 0; y < height; y += 2) { for (int x = 0; x < width; x += 2) { u32 abgr0 = imageBuffer[width * (y + 0) + x + 0]; diff --git a/Core/HW/MediaEngine.cpp b/Core/HW/MediaEngine.cpp index 53277b7ded..fa4b8191c4 100644 --- a/Core/HW/MediaEngine.cpp +++ b/Core/HW/MediaEngine.cpp @@ -777,24 +777,6 @@ inline void writeVideoLineABGR4444(void *destp, const void *srcp, int width) { } int MediaEngine::writeVideoImage(u32 bufferPtr, int frameWidth, int videoPixelMode) { - if (!Memory::IsValidAddress(bufferPtr) || frameWidth > 2048) { - // Clearly invalid values. Let's just not. - ERROR_LOG_REPORT(ME, "Ignoring invalid video decode address %08x/%x", bufferPtr, frameWidth); - return 0; - } - - u8 *buffer = Memory::GetPointerWrite(bufferPtr); - -#ifdef USE_FFMPEG - if (!m_pFrame || !m_pFrameRGB) - return 0; - - // lock the image size - int height = m_desHeight; - int width = m_desWidth; - u8 *imgbuf = buffer; - const u8 *data = m_pFrameRGB->data[0]; - int videoLineSize = 0; switch (videoPixelMode) { case GE_CMODE_32BIT_ABGR8888: @@ -807,7 +789,25 @@ int MediaEngine::writeVideoImage(u32 bufferPtr, int frameWidth, int videoPixelMo break; } - int videoImageSize = videoLineSize * height; + int videoImageSize = videoLineSize * m_desHeight; + + if (!Memory::IsValidRange(bufferPtr, videoImageSize) || frameWidth > 2048) { + // Clearly invalid values. Let's just not. + ERROR_LOG_REPORT(ME, "Ignoring invalid video decode address %08x/%x", bufferPtr, frameWidth); + return 0; + } + + u8 *buffer = Memory::GetPointerWriteUnchecked(bufferPtr); + +#ifdef USE_FFMPEG + if (!m_pFrame || !m_pFrameRGB) + return 0; + + // lock the image size + int height = m_desHeight; + int width = m_desWidth; + u8 *imgbuf = buffer; + const u8 *data = m_pFrameRGB->data[0]; bool swizzle = Memory::IsVRAMAddress(bufferPtr) && (bufferPtr & 0x00200000) == 0x00200000; if (swizzle) { @@ -867,22 +867,6 @@ int MediaEngine::writeVideoImage(u32 bufferPtr, int frameWidth, int videoPixelMo int MediaEngine::writeVideoImageWithRange(u32 bufferPtr, int frameWidth, int videoPixelMode, int xpos, int ypos, int width, int height) { - if (!Memory::IsValidAddress(bufferPtr) || frameWidth > 2048) { - // Clearly invalid values. Let's just not. - ERROR_LOG_REPORT(ME, "Ignoring invalid video decode address %08x/%x", bufferPtr, frameWidth); - return 0; - } - - u8 *buffer = Memory::GetPointerWrite(bufferPtr); - -#ifdef USE_FFMPEG - if (!m_pFrame || !m_pFrameRGB) - return 0; - - // lock the image size - u8 *imgbuf = buffer; - const u8 *data = m_pFrameRGB->data[0]; - int videoLineSize = 0; switch (videoPixelMode) { case GE_CMODE_32BIT_ABGR8888: @@ -894,8 +878,24 @@ int MediaEngine::writeVideoImageWithRange(u32 bufferPtr, int frameWidth, int vid videoLineSize = frameWidth * sizeof(u16); break; } - int videoImageSize = videoLineSize * height; + + if (!Memory::IsValidRange(bufferPtr, videoImageSize) || frameWidth > 2048) { + // Clearly invalid values. Let's just not. + ERROR_LOG_REPORT(ME, "Ignoring invalid video decode address %08x/%x", bufferPtr, frameWidth); + return 0; + } + + u8 *buffer = Memory::GetPointerWriteUnchecked(bufferPtr); + +#ifdef USE_FFMPEG + if (!m_pFrame || !m_pFrameRGB) + return 0; + + // lock the image size + u8 *imgbuf = buffer; + const u8 *data = m_pFrameRGB->data[0]; + bool swizzle = Memory::IsVRAMAddress(bufferPtr) && (bufferPtr & 0x00200000) == 0x00200000; if (swizzle) { imgbuf = new u8[videoImageSize]; @@ -1006,11 +1006,10 @@ int MediaEngine::getNextAudioFrame(u8 **buf, int *headerCode1, int *headerCode2) } int MediaEngine::getAudioSamples(u32 bufferPtr) { - if (!Memory::IsValidAddress(bufferPtr)) { + u8 *buffer = Memory::GetPointerWriteRange(bufferPtr, 8192); + if (buffer == nullptr) { ERROR_LOG_REPORT(ME, "Ignoring bad audio decode address %08x during video playback", bufferPtr); } - - u8 *buffer = Memory::GetPointerWrite(bufferPtr); if (!m_demux) { return 0; } diff --git a/Core/HW/SimpleAudioDec.cpp b/Core/HW/SimpleAudioDec.cpp index 0a19d92f85..8f250abdd8 100644 --- a/Core/HW/SimpleAudioDec.cpp +++ b/Core/HW/SimpleAudioDec.cpp @@ -252,7 +252,10 @@ bool SimpleAudio::Decode(const uint8_t *inbuf, int inbytes, uint8_t *outbuf, int } // convert audio to AV_SAMPLE_FMT_S16 - int swrRet = swr_convert(swrCtx_, &outbuf, frame_->nb_samples, (const u8 **)frame_->extended_data, frame_->nb_samples); + int swrRet = 0; + if (outbuf != nullptr) { + swrRet = swr_convert(swrCtx_, &outbuf, frame_->nb_samples, (const u8 **)frame_->extended_data, frame_->nb_samples); + } if (swrRet < 0) { ERROR_LOG(ME, "swr_convert: Error while converting: %d", swrRet); return false; @@ -338,7 +341,7 @@ size_t AuCtx::FindNextMp3Sync() { // return output pcm size, <0 error u32 AuCtx::AuDecode(u32 pcmAddr) { u32 outptr = PCMBuf + nextOutputHalf * PCMBufSize / 2; - auto outbuf = Memory::GetPointerWrite(outptr); + auto outbuf = Memory::GetPointerWriteRange(outptr, PCMBufSize / 2); int outpcmbufsize = 0; if (pcmAddr) @@ -380,10 +383,12 @@ u32 AuCtx::AuDecode(u32 pcmAddr) { if (outpcmbufsize == 0 && !end) { // If we didn't decode anything, we fill this half of the buffer with zeros. outpcmbufsize = PCMBufSize / 2; - memset(outbuf, 0, outpcmbufsize); + if (outbuf != nullptr) + memset(outbuf, 0, outpcmbufsize); } else if ((u32)outpcmbufsize < PCMBufSize) { // TODO: Not sure it actually zeros this out. - memset(outbuf + outpcmbufsize, 0, PCMBufSize / 2 - outpcmbufsize); + if (outbuf != nullptr) + memset(outbuf + outpcmbufsize, 0, PCMBufSize / 2 - outpcmbufsize); } if (outpcmbufsize != 0)