Skip to content

Vulnerability fixes 1/3 - #22008

Merged
hrydgard merged 7 commits into
masterfrom
vuln-fixes-1
Jul 31, 2026
Merged

Vulnerability fixes 1/3#22008
hrydgard merged 7 commits into
masterfrom
vuln-fixes-1

Conversation

@hrydgard

@hrydgard hrydgard commented Jul 31, 2026

Copy link
Copy Markdown
Owner

TristanInSec emailed me a bunch of AI-detected possible security vulnerabilities in the code.

The vulnerability descriptions are actually really detailed and perfect for feeding into another AI for fixing them, so I had Deepseek do it. I've manually checked the fixes too, of course.

Here's the first batch of fixes, out of 3 or so.

All the reports: vulns-by-tristan.zip

@hrydgard hrydgard added this to the v1.21 milestone Jul 31, 2026
hrydgard added 4 commits July 31, 2026 20:35
A crafted .cso compressed ISO could trigger a heap buffer overflow on any
sector read, reachable via ordinary gameplay.

Two root causes:
1. Unvalidated frame index deltas. ReadBlock/ReadBlocks computed a
   compressed read range from two adjacent frame-index-table entries.
   With non-monotonic entries, compressedReadEnd - compressedReadPos
   underflows as u64, producing a huge read size that fileLoader->ReadAt()
   wrote into the fixed-size readBuffer.
2. hdr.align (indexShift, 0-255) used as '1 << indexShift' was undefined
   behavior at >= 32, and frameSize + (1 << indexShift) could wrap,
   undersizing the buffer while inflate() was configured with the full
   frameSize.

Fixes:
- Validate the index table is monotonically non-decreasing in the
  constructor.
- Reject files with indexShift > 20.
- Use unsigned shift for buffer size math and store readBufferSize.
- Clamp compressed read sizes to readBufferSize in both ReadBlock and
  ReadBlocks.
The /unittest subdirectory contains a separate binary with C++ unit tests
alongside the pspautotests runner. Document how to build and run them
(UnitTest.exe on Windows, PPSSPPUnitTest on Linux/Mac), and that they
should be run after substantial changes at the end of a chunk of work.
…olders

If there's demand for this feature, we'll bring it back and put it
behind a developer option.

Fixes vuln #7 from the recent collection
A crafted zip with a parent-directory ("..") entry name could escape the
destination directory during extraction, writing arbitrary files on the
host (e.g. into startup/autostart folders). ExtractZipContents built the
output path by concatenating the raw zip entry name onto the destination
with no traversal check.

Changes:
- Add HasParentDirComponent() utility in Core/Util/PathUtil and use it in
  GameManager::ExtractZipContents to reject entries with a ".." component.
  Guard both the directory-creation and file-writing passes.
- Expose ExtractZipContents as public for testing.
- Add unittest/TestZipSlip which crafts a zip with a "../evil.txt" entry
  and verifies it is not written outside the destination directory.
hrydgard added 3 commits July 31, 2026 20:54
The LZRC decompressor's only bounds check for output (and input) was a
debug-only _dbg_assert_msg_, which is a no-op in release builds. The
NPDRM demo block device also passed a hardcoded 1 MiB output length
while the real destination buffer (blockBuf_) could be as small as 2048
bytes, allowing a crafted NPDRM image to trigger an unbounded heap
overflow during game load.

Changes:
- rc_putbyte/rc_getbyte now enforce real bounds and set an error flag
  instead of relying on debug asserts; decompression aborts with -1 on
  overflow or truncated input.
- normalize() reads via rc_getbyte so it stays in bounds.
- Plain-text path clamps the copy size to both the output buffer and the
  remaining input (and no longer interprets the size as signed).
- NPDRMDemoBlockDevice::ReadBlock passes blockSize_ (the real buffer
  size) instead of 0x00100000 to lzrc_decompress.
- Add unittest/TestLzrc (synthetic input, no test data files): checks the
  plain-text clamp, truncated input, and output overflow all fail safely.
- AGENTS.md: note to reuse existing format handlers/decompressors before
  writing new ones.
A crafted blockAlign could overflow the fixed 1000-byte assembly stack
buffer in Atrac2::DecodeForSas. Bail out if the packet can't fit.
ReadSFO dereferenced index table entries without checking the table fit
within the buffer, and GetDataOffset had no bounds checks at all (reading
attacker-controlled offsets and strcmp'ing without a terminator guard).

- Validate the index table fits entirely within the buffer in ReadSFO.
- Add a size parameter to GetDataOffset and validate the index table,
  key/data table positions, and key string termination before use.
@hrydgard
hrydgard merged commit e41a16a into master Jul 31, 2026
23 checks passed
@hrydgard
hrydgard deleted the vuln-fixes-1 branch July 31, 2026 19:18
@daniloxavier183-max

Copy link
Copy Markdown

O PPSSPP CONTINUA FECHANDO SOZINHO PORQUE SÓ O SUA VERSÃO O SITE OFICIAL E NÃO DA PLAY STORE TAMBÉM QUANDO APERTA PARA PAUSAR O JOGO NO MENU DO APLICATIVO ELE FECHA

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants