42 Commits
Author SHA1 Message Date
Henrik RydgårdandClaude Opus 5 b42a03e095 Add savestate serializer tests, fix three bounds-check bugs
PointerWrap and the Do() overloads around it are how every savestate is
written and read, and had no direct coverage. Everything read back came off
disk, so the corrupt-input paths matter as much as the round trips.

Three bugs, all in the bounds checking added in 58d4759ceb:

1. sizeof(T) is not a lower bound on how many bytes an element serializes to.
   It only holds for the types DoHelper_ writes out raw. A std::string is 32-40
   bytes in memory and serializes to as few as five; a T* serializes to whatever
   T::DoState() writes. So DoVector/DoList/DoSet/DoMap could reject a perfectly
   valid savestate whenever count * sizeof(element) exceeded the bytes left in
   the buffer. That is not hypothetical: pspFileSystem is serialized dead last
   in SaveStart::DoState, and MetaFileSystem::DoState does Do(p, currentDir) on
   a std::map<int, std::string>, so the check runs with only a few hundred bytes
   remaining and claims 44 bytes per entry against roughly 22 actual. Added
   SerializeMinElemSize<T>(), mirroring DoHelper_'s own condition, and used it
   in all five containers. The bound is only loosened, so nothing that loaded
   before can stop loading.

2. Do(p, std::map<K, T *> &) deletes every value before reading the new ones,
   and DoMap then returned on a bad count without clearing - leaving the map
   full of freed pointers to be used or deleted again. Six live maps go through
   this (sceMpeg, sceMp3, sceAac, sceFont, sceHeap, sceKernelThread's pending
   calls), so a corrupt savestate meant a use-after-free. Clear before the guard
   can bail out, in DoMap, DoMultimap and DoSet.

3. The wstring and u16string overloads validated stringLen < 0 but not 0, and
   didn't require a whole number of characters. read() computes
   stringLen / sizeof(char) - 1, so a length of 0 resized to SIZE_MAX and
   memcpy'd with a wrapped-around size. PSPOskDialog::DoState serializes both
   (inputChars at v2, a legacy wstring below that), so this was reachable: the
   test aborts the process without the fix.

The test covers round trips of PODs, strings (empty, embedded NUL), vector,
map, set, list and map-of-pointers, section titles and version gating in both
directions, marker mismatches, measure-vs-write checkpoint disagreement, the
error latch dropping to MODE_NOOP, every truncation of a valid buffer, and
hand-corrupted counts and lengths.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
2026-08-17 14:50:57 +02:00
Henrik RydgårdandClaude Sonnet 5 1eab737e4d Serialize: guard List/Deque/Map/Set against corrupted size fields
DoVector already rejects an attacker/corruption-controlled size that
would resize far beyond what's actually left in the savestate buffer.
DoList/DoDeque/DoMap/DoMultimap/DoSet never got the same treatment -
a corrupted count field (e.g. 0xFFFFFFFF) drove an immediate huge
resize (list/deque) or an unbounded loop of allocations (map/set)
before any per-element bounds checking kicked in. All five now check
the declared count against PointerWrap::Remaining() first.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4QAoxV2KY7ek4PcZw3WvY
2026-08-10 01:00:28 +02:00
Henrik RydgårdandClaude Sonnet 5 60796e08f9 Serializer: fix OOB read loading a std::string from a savestate
MODE_READ built the string via x = (char*)*p.ptr, which strlen()s for
a NUL terminator. CheckRead(stringLen) only guarantees stringLen bytes
are available in the buffer, not that one of them is a NUL - a
corrupted savestate missing the terminator caused strlen to scan past
the checked region. Now uses a length-bounded assign(), matching how
the wstring/u16string siblings already do this correctly via memcpy.
Also tightens the stringLen validity check to require >= 1 (matching
what a real serialized string always has), so stringLen - 1 can't
go negative for a corrupted stringLen of 0.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4QAoxV2KY7ek4PcZw3WvY
2026-08-10 01:00:28 +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 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 63c997b973 Fix an ordering issue in Atrac context creation 2025-03-16 22:46:44 +01:00
Henrik Rydgård b3346df646 ImDebugger: Add a window to inspect upcoming CoreTiming events 2024-12-07 16:28:27 +01:00
Herman Semenov 4ef014cb73 [Common] Fixes from Unknown W. Brackets: <checkins@unknownbrackets.org> 2024-09-18 11:11:25 +02:00
Herman Semenov 192650f551 [Core/HLE/GPU/D3D11/GLES] Using for based loop C++17 and replaced on structured binding map C++17 2024-09-18 11:10:10 +02:00
Herman Semenov 45429bcd85 [Common/Data/File/Input/Net/Serialize/System/UI] Using for based loop C++17 and replaced on structured binding map C++17 2024-09-17 17:42:08 +02:00
Herman Semenov 3c66f149d3 [Common/Core/Windows] Removed excess check pointer before delete or free() 2024-09-17 11:34:42 +02:00
Henrik Rydgård cf49ff04ca More accurate error reporting for savestate loads 2024-07-20 10:55:16 +02:00
Henrik Rydgård a1010e3b2e Add some more checks in sceFont 2024-07-20 10:42:01 +02:00
Henrik Rydgård e01ca5b057 Logging API change (refactor) (#19324)
* Rename LogType to Log

* Explicitly use the Log:: enum when logging. Allows for autocomplete when editing.

* Mac/ARM64 buildfix

* Do the same with the hle result log macros

* Rename the log names to mixed case while at it.

* iOS buildfix

* Qt buildfix attempt, ARM32 buildfix
2024-07-14 14:42:59 +02:00
Henrik Rydgård 6c648a2cdd Use AtracBase instead of Atrac in sceAtrac (so now we can replace it) 2024-04-15 12:50:51 +02:00
Henrik Rydgård 7e427e41d1 Remove a bunch of dead code from CoreTiming ("threadsafe" events)
We haven't used these "threadsafe" events since we removed our first attempt
at GPU threading, so like 10 years, and maybe some experimentation in the
networking code according to some comments. It's unlikely that any
savestates that used these events would load anyway.
2024-01-16 09:06:03 +01:00
Henrik Rydgård 9bd67df5b2 Achievement savestate fixes 2023-07-08 21:47:16 +02:00
Henrik Rydgård 132e8eeccd Now these variables need to be initialized 2023-02-14 22:46:32 +01:00
Henrik Rydgård cebb885e84 Address feedback 2023-02-14 10:09:54 +01:00
Henrik Rydgård a7baa3580b Some code cleanups around rewind. 2023-02-14 10:09:36 +01:00
Unknown W. Brackets ef04c4f55c Utility: Report YugiohSaveFix usage. 2022-12-19 07:56:23 -08:00
Unknown W. Brackets e49668eea7 SaveState: Correct missing switch case warnings. 2022-12-04 07:57:30 -08:00
Unknown W. Brackets 0556ee67fc SaveState: Fix a format type error. 2022-12-04 07:57:09 -08:00
Henrik Rydgård c7041d6e97 Reserve some space in the checkpoints vector 2022-12-02 22:46:39 +01:00
Henrik Rydgård f5a7661c51 Add a NOOP state to reduce logspam after error 2022-12-02 22:46:38 +01:00
Henrik Rydgård 52a684644d Verify that the Measure and Save passes match accurately through checkpointing
Adding this after seeing some very suspicious behavior in Ratchet &
Clank.
2022-12-02 22:46:38 +01:00
Henrik Rydgård 237fbca979 Savestate: Prepare some sanity checks 2022-12-02 22:46:38 +01:00
Unknown W. Brackets 3e5d77ab46 SaveState: Switch from deprecated is_pod. 2022-11-12 12:30:04 -08:00
Henrik Rydgård 36ada6308d Sanity check string lengths in save state code 2021-10-07 21:08:46 +02:00
Unknown W. Brackets a1b88bedd9 SaveState: Validate size matches measured.
In #14653, a save state appears to have been generated truncated.
This attempts to detect that at generation time.
2021-08-07 13:55:29 -07:00
Unknown W. Brackets dc12b3a7c8 SaveState: Use default ZSTD compress level. 2021-08-06 23:46:07 -07:00
Unknown W. Brackets 0097772d3c SaveState: Ask to include xxhash in frames.
Hopefully this should detect any decompression errors better.
2021-08-06 23:42:43 -07:00
Unknown W. Brackets 1e9a391f65 SaveState: Add const for save compression. 2021-08-06 23:39:36 -07:00
Henrik Rydgård c6c5a93bf4 Couple of minor things, crashfix on deserialization failure 2021-07-25 15:42:12 +02:00
Henrik Rydgård 025bcb1673 Introduce Path, start using it all over the place.
Still lots left to convert!

Convert GetSysDirectory to return Path.

More buildfixing

Remove unnecessary Path( constructors
2021-05-13 10:39:16 +02:00
Unknown W. Brackets 7a719dc245 SaveState: Switch to zstd.
Choose a level that is just slightly slower than snappy, but much smaller
typically.
2021-04-11 09:13:10 -07:00
Henrik Rydgård 5d62610a93 Merge pull request #14038 from unknownbrackets/savestate-str
SaveState: Load misaligned wide strings properly
2021-02-15 18:50:23 +01:00
Unknown W. Brackets 45f3f4554b SaveState: Prevent crash on bad cookie marker.
Just fail to load the save state.
2021-02-09 07:14:07 -08:00
Unknown W. Brackets be4c905373 SaveState: Load misaligned wide strings properly. 2021-01-31 08:55:54 -08:00
Henrik Rydgård 74f8b3c69a Yet another one 2020-10-15 00:03:47 +02:00
Henrik Rydgård 4f43cff5ca Move fileutil, net, image loaders, ui to Common. (#13506)
* Move and rename file_util/fd_util to Common/File/FileUtil and DirListing

Let's also move net while we're at it.

Move the ZIM/PNG loaders over to Common.

Move the UI framework into Common

iOS buildfix

* Buildfix

* Buildfixes

* Apple buildfix

* This typo again..

* UWP buildfix

* Fix build of PPSSPPQt, such as it is (it's not in good condition...)

* Guess what? Another buildfix.
2020-10-04 20:48:47 +02:00
Unknown W. Brackets b8342fb8ec SaveState: Rename ChunkFile files to Serialize.
Makes more sense and less weird than ChunkFileDoMap, etc.
2020-08-10 08:04:05 +00:00