diff --git a/Core/Dialog/PSPSaveDialog.cpp b/Core/Dialog/PSPSaveDialog.cpp index 0e59fb80a9..6ac1da55e2 100755 --- a/Core/Dialog/PSPSaveDialog.cpp +++ b/Core/Dialog/PSPSaveDialog.cpp @@ -136,6 +136,26 @@ int PSPSaveDialog::Init(int paramAddr) { Memory::Memcpy(&request, requestAddr, size); Memory::Memcpy(&originalRequest, requestAddr, size); + // gameName/saveName/fileName become parts of host filesystem paths. + // Reject path separators (either direction) and bare dot components so a + // crafted request can't escape the save directory (path traversal). + auto hasPathTraversal = [](const char *field, size_t fieldSize) { + size_t len = 0; + while (len < fieldSize && field[len] != 0) + len++; + for (size_t i = 0; i < len; i++) { + if (field[i] == '/' || field[i] == '\\') + return true; + } + return (len == 1 && field[0] == '.') || (len == 2 && field[0] == '.' && field[1] == '.'); + }; + if (hasPathTraversal(request.gameName, sizeof(request.gameName)) || + hasPathTraversal(request.saveName, sizeof(request.saveName)) || + hasPathTraversal(request.fileName, sizeof(request.fileName))) { + ERROR_LOG_REPORT(Log::sceUtility, "sceUtilitySavedataInitStart: path separator in name fields"); + return SCE_ERROR_UTILITY_INVALID_PARAM_SIZE; + } + param.SetIgnoreTextures(IsNotVisibleAction((SceUtilitySavedataType)(u32)request.mode)); param.ClearSFOCache(); int retval = param.SetPspParam(&request); diff --git a/Core/Dialog/SavedataParam.cpp b/Core/Dialog/SavedataParam.cpp index 08d7dcb4c0..1a7610d40c 100644 --- a/Core/Dialog/SavedataParam.cpp +++ b/Core/Dialog/SavedataParam.cpp @@ -1547,6 +1547,20 @@ int SavedataParam::SetPspParam(SceUtilitySavedataParam *param) { // Get number of fileName in array saveDataListCount = 0; while (saveNameListData[saveDataListCount][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]); + bool hasSeparator = false; + for (char c : entry) { + if (c == '/' || c == '\\') { + hasSeparator = true; + break; + } + } + if (hasSeparator || entry == "." || entry == "..") { + ERROR_LOG(Log::sceUtility, "SavedataParam: invalid saveName in list: %s", std::string(entry).c_str()); + return SCE_ERROR_UTILITY_INVALID_PARAM_SIZE; + } saveDataListCount++; }