mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
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.
This commit is contained in:
1 parent
a67fc2300d
commit
779cae6232
2 files changed
+34
No files matched your search
@@ -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);
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user