Commit Graph
15020 Commits
Author SHA1 Message Date
Henrik Rydgård c1310ae4a5 Rework UPnP service thread sync
No longer waking up twice per second. Instead a slow 5s poll plus
wakeups if needed.
2026-08-07 11:24:22 +02:00
Henrik Rydgård 256e4082eb Merge branch 'master' into avoid-strlen-memblockinfo 2026-08-07 10:44:55 +02:00
Henrik Rydgård d87a98c4a8 Avoid wasting CPU on counting characters in the memblock management
Unittest and a bugfix by claude.
2026-08-07 08:56:41 +02:00
Henrik RydgårdandClaude Sonnet 5 510cfb421c Extend LoadExecForKernel with real VSH loadexec/exit syscalls
Adds SceKernelLoadExecVSHParam (matching JPCSP's reference layout - its
first four fields line up with the existing SceKernelLoadExecParam,
which is why the plain sceKernelLoadExec already worked for
sceKernelLoadExecVSHMs2) and fills in the rest of LoadExecForKernel's
NIDs from JPCSP: real implementations for sceKernelExitVSHVSH/Kernel
(mirrors sceKernelExitGame) and sceKernelLoadExecBufferVSHUsbWlan (loads
an exec from an in-RAM buffer instead of a file - the VSH's "push a game
over USB/WLAN" path), plus UNIMPL stubs for everything JPCSP itself only
knows by NID.

sceKernelLoadExecBufferVSHUsbWlan needed __KernelLoadExec split into a
file-reading front end and a shared __KernelLoadExecFromPtr back end
that both it and the new buffer-based path call into - a pure
extract-method refactor of the single most heavily used boot path in the
emulator. Verified no regression: same 11 passed / 9 pre-existing-failed
split on pspautotests/tests/cpu/*, and loader/bss still passes, before
and after this change.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSNaZnHCjmryS3ziVN9gZU
2026-08-07 08:49:25 +02:00
Henrik Rydgård 5f5130025c Merge pull request #22037 from hrydgard/hide-status-bar-ios
Add setting to hide/show the status bar on iOS
2026-08-07 07:24:25 +02:00
Henrik RydgårdandClaude Opus 5 8bfc151395 iOS: Hide the status bar when immersive mode is enabled
prefersStatusBarHidden was dead code - it computed an orientation and a
(commented out) user preference, then unconditionally returned false. So the
status bar was only ever hidden on iPhone in landscape, and only because iOS
does that on its own in compact height.

Now it honors bImmersiveMode from the DisplayLayoutConfig matching the current
orientation, so it also applies in portrait and on iPad. Adds the corresponding
checkbox to the iOS system settings, and updates the status bar on rotation and
when the setting is toggled.

Also fixes a missing break in the ROTATE_UPDATED case in System_Notify, and a
static/non-static mismatch on sceKernelLoadModuleBufferUsbWlan that broke the
build (the header intentionally exposes it for sceVshBridge).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JZk5y4Fzw811WJoNWZb8Sc
2026-08-06 20:56:37 +02:00
Henrik Rydgård 092ab42fe7 Clean up ugly usage of the g_nativeLibDir global. Now it's local in VulkanLoader. 2026-08-06 18:12:04 +02:00
Henrik Rydgård 60fc887306 Clean up Config::PostLoadCleanup, reject disabled GPU backends 2026-08-06 17:45:37 +02:00
Henrik RydgårdandClaude Sonnet 5 5bd1ff8066 Move remaining manual command line parsing into CmdLine.cpp
Headless.cpp, NativeApp.cpp, and SDLMain.cpp each still hand-parsed a few
argv flags directly (mount/log/state/ignore/loglevel in headless and the
app, xres/yres/dpi/scale in SDL), duplicating and in some cases conflicting
with the shared CommandLineOptions parser. Consolidate all of it into
CmdLine.cpp/.h so there's a single source of truth, and drop the now-dead
remain_argc/remain_argv filtering in SDLMain.cpp since NativeInit no longer
reads argv itself.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PfFvWzpHxErWgRhKqqSewN
2026-08-05 16:02:49 +02:00
Henrik Rydgård 16206d18ab Simplify the EmuThread API again 2026-08-05 09:48:51 +02:00
Henrik Rydgård ecae62e737 Fix headless with OpenGL for SDL 2026-08-05 00:15:56 +02:00
Henrik Rydgård 551e4cd0ab Headless: Make all GPU backends work correctly on Windows 2026-08-05 00:15:56 +02:00
Henrik Rydgård 25cf52176f Misc headless work 2026-08-05 00:15:56 +02:00
Henrik Rydgård 5eb4772644 Minor EmuThread refactor 2026-08-05 00:15:56 +02:00
Henrik Rydgård edd968062a Correct the Atrac3 security check that broke music in GTA
See 4cd611b71f
2026-08-05 00:15:38 +02:00
Henrik Rydgård be922eca62 Make OpenGL render thread shutdown more robust. 2026-08-04 16:44:55 +02:00
Henrik Rydgård 648560b2d3 Don't exit games when leaving the emuthread 2026-08-04 00:24:39 +02:00
Henrik Rydgård 68ec34ad54 Build and warning fixes 2026-08-03 19:11:07 +02:00
Henrik Rydgård 55eee26c52 Assorted warning fixes 2026-08-03 18:55:35 +02:00
Henrik Rydgård db30fabf03 Add a setting (defaulting to false) for enabling file handler plugins 2026-08-03 11:24:36 +02:00
Henrik Rydgård 317a06f2f6 Revert "Delete the ability to load file handler plugins from extracted game folders"
This reverts commit e806192154.
2026-08-03 11:22:05 +02:00
Henrik Rydgård 5e6a051952 Fix path traversal in texture pack filenames; use HasPathTraversal in savestate migration
Texture pack filenames/aliases from textures.ini were used to build read
and write paths with no '..' check, letting a malicious pack read or
write files outside the pack directory.

- LoadIniValues rejects entries with a parent dir component via
  HasParentDirComponent.
- ReplacedTexture::Prepare skips such filenames as defense in depth.
- PSPLoaders savestate migration now uses the shared HasPathTraversal
  helper instead of inline separator checks.
2026-08-01 13:16:22 +02:00
Henrik Rydgård 77ebdf2e80 Clamp segment count in PSPModule::GetLongInfo
nm.nsegment is attacker-controlled but segmentaddr/segmentsize are fixed
4-entry arrays; the debug info loop read past them. Clamp to 4 like the
other consumers.
2026-08-01 13:16:21 +02:00
Henrik Rydgård 942a76cfaa Fix heap overflow via unsigned underflow in legacy Atrac::EnqueueForSas
The space-left clamp was computed in unsigned 32-bit arithmetic, so a
crafted fileoffset/FirstOffsetExtra could underflow to a huge value and
leave addbytes unclamped, driving a Memory::Memcpy past dataBuf_.

Compute the clamp in signed 64-bit, clamp negatives to 0, and skip the
copy when there's nothing to write.
2026-08-01 13:16:21 +02:00
Henrik Rydgård 725cd691b3 Limit total extracted size when installing zips (zip bomb protection)
ExtractZipContents wrote every entry's declared size with no ceiling, so
a small high-ratio zip could decompress to fill the storage device.

- Add a maxTotalSize parameter to ExtractZipContents (default 4GB) and
  ExtractFile.
- Bail out in the size-summation pass when the total declared size
  exceeds the limit, and again per write chunk in case declared sizes
  are inaccurate.
2026-08-01 13:16:21 +02:00
Henrik Rydgård 6d43b6f531 Fix OOB read/write via negative seek wrap in VFSFileSystem
SeekFile stored a signed s32 position into the unsigned size_t seekPos,
so a negative position (e.g. from a truncating s32 cast of a large
lseek offset) wrapped seekPos to near 2^64. ReadFile's clamp arithmetic
then also wrapped, driving a memcpy from a wild pointer.

- Clamp the computed seek position to 0 in SeekFile.
- Clamp the read size against the remaining data in ReadFile, returning
  0 when seekPos is at or past the end.
2026-08-01 13:16:21 +02:00
Henrik Rydgård 0eef5d0164 Use shared HasPathTraversal utility for savedata name validation
Replace the inline lambdas in the savedata dialog with the new
HasPathTraversal() helper in Core/Util/PathUtil.
2026-08-01 13:16:21 +02:00
Henrik Rydgård 779cae6232 Reject path traversal in savedata name fields
gameName/saveName/fileName and the saveNameList entries are
guest-controlled and get concatenated into host filesystem paths, so a
crafted request could escape the save directory with ../ sequences.

- PSPSaveDialog::Init rejects requests whose name fields contain a path
  separator ('/' or '\') or are bare dot components.
- SavedataParam::SetPspParam rejects saveNameList entries the same way.
2026-08-01 13:16:21 +02:00
Henrik Rydgård 4cd611b71f Fix out-of-bounds reads in ATRAC track parsing
AnalyzeAtracTrack used max(fileSize, size) as the chunk-parse bound with
fileSize taken from the file's RIFF header, so a crafted inflated RIFF
size could push reads past the end of the buffer. Keep the real-library
behavior of tolerating a too-low size, but clamp the parse bound to the
actual mapped guest memory at the buffer.

Also guard ParseWaveAT3's RIFF scan against a blockSize < 4 underflow
that could make the offset negative and bypass the loop bounds check, and
clamp readSize to the mapped region in Atrac2::SetData before parsing.
2026-08-01 11:57:27 +02:00
Henrik Rydgård 32abdd63bf Fix EP-map parsing OOB read in PSMF video stream params
EP_MAP_STRIDE * EPMapEntriesNum was computed in 32-bit and could wrap,
passing the range check while the loop read the unwrapped count; and the
check was skipped entirely when headerOffset == 0 (the player tempbuf
path).

- Use 64-bit math for the EP map size.
- Keep the guest-RAM range check when headerOffset != 0.
- Cap the entry count for the headerOffset == 0 path so the reads stay
  within the player's 64KB tempbuf.
2026-08-01 11:57:27 +02:00
Henrik Rydgård 04d8613d81 Bounds-check charPtr inside PGF::ReadCharGlyph
ReadCharGlyph read glyph metadata at an attacker-controlled bit offset
with no validation, and ReadShadowGlyph only checked after delegating to
it. Validate charPtr (with margin for the header reads) at the top of
ReadCharGlyph so it is safe regardless of caller, and drop the now
redundant checks at the ReadPtr call sites.
2026-08-01 11:57:27 +02:00
Henrik Rydgård 788150c28e Fix out-of-bounds reads in PGF font parsing
PGF::ReadPtr walked four length-prefixed tables and computed table sizes
before any bounds check, and used signed 32-bit size math that could
overflow, allowing a crafted font to read past the input buffer.

- Validate the total size of all tables up front using 64-bit math.
- Check the rev3 extra header fits before reading it.
- Cap charPointerLength/charMapLength/shadowMapLength to avoid absurd
  allocations.
- Bounds-check glyph data offsets before reading each glyph.

Also throw in a warning fix
2026-08-01 11:57:27 +02:00
Henrik Rydgård a8195e7ca6 Clamp HTTP response body to the requested range in HTTPFileLoader
A malicious or MITM'd server could send a Content-Range header matching
the requested range but a larger entity body, overflowing the caller's
fixed-size buffer via output.Take. Clamp the copied size to the requested
range.
2026-08-01 11:57:27 +02:00
Henrik Rydgård 5d10f281ef Fix integer overflow in PMF video frame buffer allocation
pmf_init reported stream dimensions without a cap, and PMFView::Draw
allocated width * height * 4 with 32-bit int arithmetic, so a crafted
ICON1.PMF could overflow the allocation to a small buffer while
sws_scale wrote the full frame.

- Reject videos with dimensions outside 1..720x480 in pmf_init (PMFs on
  the PSP never exceed 720x480).
- Use size_t arithmetic for the frame buffer allocation.
2026-08-01 11:57:27 +02:00
Henrik Rydgård 983068b07a Fix OOB read on unterminated module names in PRX import debug reporter
The import debug reporter used IsValidAddress (start-address only) before
formatting module names with %s, so a crafted unterminated name could be
read past guest RAM. Use IsValidNullTerminatedString instead.
2026-08-01 11:57:27 +02:00
Henrik Rydgård 2100e4ec47 Reject ATRAC files with oversized packets at parse time; honor Verify errors
- InitContextFromTrackInfo now rejects files where sampleSize (from
  blockAlign) exceeds the buffer size, instead of only clamping later in
  DecodeForSas. Keep the DecodeForSas check as defense-in-depth since a
  large buffer could still allow a crafted packet to overflow the fixed
  assembly buffer.
- CChunkFileReader::Verify now returns ERROR_BROKEN_STATE if bounds
  checking fails, so modified savestates are rejected here too.
2026-08-01 11:57:27 +02:00
Henrik Rydgård 398a678b88 Fix null pointer deref in AtracSasAddStreamData
The null check for getAtrac() only logged a warning and fell through to
a virtual call on the null pointer. Return 0 on invalid atrac ID.
2026-08-01 11:57:27 +02:00
Henrik Rydgård 58d4759ceb Add bounds checking to savestate deserialization
PointerWrap tracked no end-of-buffer, so DoState() implementations could
read past the end of a crafted or truncated savestate via DoVoid's
unchecked memcpy, and DoVector could resize to an attacker-controlled
size before reading.

- PointerWrap now tracks a read end; DoVoid/ExpectVoid fail (MODE_NOOP)
  before reading out of bounds.
- String reads are bounds-checked for the whole string including NUL.
- DoVector rejects sizes that can't fit in the remaining buffer.
- LoadPtr takes the buffer size and sets the read end.
- Capping the decompression buffer allocation in LoadFile.
2026-08-01 11:57:24 +02:00
Henrik Rydgård 3ad08377c5 Clamp partial packet copy to main buffer size in Atrac2::DecodeInternal
The loop-with-trailer streaming path copied 'secondBufferByte % sampleSize'
bytes into the main buffer with no clamp. sampleSize is file-derived, so a
crafted value could overflow the destination. Clamp the copy length to
info.bufferByte.
2026-08-01 11:41:24 +02:00
Henrik Rydgård c0f5b3d3ee Skip savestate migration if game ID strings contain a path separator
DISC_ID/DISC_VERSION/homebrewName are attacker-controlled and were used
unsanitized to build migration rename paths. Skip the migration step if
any of them contain a '/' or '\' so the destination can't escape the
savestate directory.
2026-08-01 11:41:24 +02:00
Henrik Rydgård a0fe36f470 Fix mismatched new[]/delete in CachingFileLoader cache eviction
MakeCacheSpaceFor freed cache blocks (allocated with new u8[]) using
scalar delete instead of delete[]. Correct to delete[].
2026-08-01 11:41:24 +02:00
Henrik Rydgård 5194382b7b Fix out-of-bounds reads in PARAM.SFO parser
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.
2026-07-31 20:54:17 +02:00
Henrik Rydgård 6d231f3f45 Guard SAS assembly buffer against oversized ATRAC packets
A crafted blockAlign could overflow the fixed 1000-byte assembly stack
buffer in Atrac2::DecodeForSas. Bail out if the packet can't fit.
2026-07-31 20:54:17 +02:00
Henrik Rydgård b7b96c3374 Fix LZRC decompressor heap overflow and add unit test
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.
2026-07-31 20:54:13 +02:00
Henrik Rydgård f3d7d8bc0c Fix Zip Slip in zip extraction and add unit test
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.
2026-07-31 20:35:12 +02:00
Henrik Rydgård e806192154 Delete the ability to load file handler plugins from extracted game folders
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
2026-07-31 20:35:12 +02:00
Henrik Rydgård 6fb48fd45a Fix heap buffer overflow in CSO block device from crafted index table
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.
2026-07-31 20:35:12 +02:00
Henrik Rydgård ecce9baffa Fix some pause screen issues 2026-07-30 18:44:44 +02:00
Henrik Rydgård d6e0308c11 Merge pull request #21990 from Arkadyzja/savestate-compact-blockallocator
Savestate: compact BlockAllocator serialization (section v2)
2026-07-30 17:23:25 +02:00
Henrik Rydgård e3975c7aae Merge pull request #21988 from Arkadyzja/savestate-forget-stale-helper-threads
Savestate: don't let stale HLE helper threads mutate restored kernel state
2026-07-30 17:21:54 +02:00