Savedata: Keep the list count at 0 when a name in the list is rejected

The multi-name path counted names straight into saveDataListCount, so
returning on a path traversal name left a count behind with the list
already freed by Clear(). The next savestate then serialized that many
entries from a null list and crashed in Do(std::string). Count on the
side, and don't write entries for a list that isn't there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Henrik RydgårdandClaude Opus 5.5 committed 2026-10-27 22:04:45 +01:00
1 parent 476d020c58
commit e10ebbeb44
1 file changed
+10 -5
+10 -5
View File
@@ -1557,18 +1557,20 @@ int SavedataParam::SetPspParam(SceUtilitySavedataParam *param) {
saveNameListData = param->saveNameList;
// Get number of fileName in array
saveDataListCount = 0;
while (saveNameListData[saveDataListCount][0] != 0) {
// Get number of fileName in array. Counted on the side, so a rejected name leaves the
// count at 0 to match the list Clear() freed (a savestate walks that many entries).
int count = 0;
while (saveNameListData[count][0] != 0) {
// saveName entries become part of host filesystem paths; reject
// path separators and bare dot components (path traversal).
const std::string_view entry = StringViewFromFixedSizeField(saveNameListData[saveDataListCount]);
const std::string_view entry = StringViewFromFixedSizeField(saveNameListData[count]);
if (HasPathTraversal(entry)) {
ERROR_LOG(Log::sceUtility, "SavedataParam: invalid saveName in list: %s", std::string(entry).c_str());
return SCE_ERROR_UTILITY_INVALID_PARAM_SIZE;
}
saveDataListCount++;
count++;
}
saveDataListCount = count;
if (saveDataListCount > 0) {
hasMultipleFileName = true;
@@ -2015,6 +2017,9 @@ void SavedataParam::DoState(PointerWrap &p) {
// pspParam is handled in PSPSaveDialog.
Do(p, selectedSave);
if (p.mode != p.MODE_READ && !saveDataList) {
saveDataListCount = 0;
}
Do(p, saveDataListCount);
Do(p, saveNameListDataCount);
if (p.mode == p.MODE_READ) {