diff --git a/rpcs3/Emu/Cell/Modules/cellGame.cpp b/rpcs3/Emu/Cell/Modules/cellGame.cpp index 210cb95bb4..9a246860bc 100644 --- a/rpcs3/Emu/Cell/Modules/cellGame.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGame.cpp @@ -150,13 +150,16 @@ error_code cellHddGameCheck(ppu_thread& ppu, u32 version, vm::cptr dirName { cellGame.error("cellHddGameCheck(version=%d, dirName=%s, errDialog=%d, funcStat=*0x%x, container=%d)", version, dirName, errDialog, funcStat, container); - std::string dir = dirName.get_ptr(); - - if (dir.size() != 9) + if (!dirName || !funcStat || sysutil_check_name_string(dirName.get_ptr(), 1, CELL_GAME_DIRNAME_SIZE) != 0) { return CELL_HDDGAME_ERROR_PARAM; } + std::string dir = dirName.get_ptr(); + + // TODO: Find error code + verify(HERE), dir.size() == 9; + vm::var result; vm::var get; vm::var set; diff --git a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp index 2604767043..f5a7303c17 100644 --- a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp @@ -240,10 +240,29 @@ static s32 savedata_check_args(u32 operation, u32 version, vm::cptr dirNam return 5; } - if (operation <= SAVEDATA_OP_AUTO_LOAD && !dirName) + if (operation <= SAVEDATA_OP_AUTO_LOAD) { - // ****** sysutil savedata parameter error : 2 ****** - return 2; + if (!dirName) + { + // ****** sysutil savedata parameter error : 2 ****** + return 2; + } + + switch (sysutil_check_name_string(dirName.get_ptr(), 1, CELL_SAVEDATA_DIRNAME_SIZE)) + { + case -1: + { + // ****** sysutil savedata parameter error : 3 ****** + return 3; + } + case -2: + { + // ****** sysutil savedata parameter error : 4 ****** + return 4; + } + case 0: break; + default: ASSUME(0); + } } if ((operation >= SAVEDATA_OP_LIST_AUTO_SAVE && operation <= SAVEDATA_OP_FIXED_LOAD) || operation == SAVEDATA_OP_FIXED_DELETE) @@ -279,7 +298,50 @@ static s32 savedata_check_args(u32 operation, u32 version, vm::cptr dirNam return 17; } - // TODO: Theres some check here I've missed about dirNamePrefix + char cur, buf[CELL_SAVEDATA_DIRNAME_SIZE + 1]{}; + + for (s32 pos = 0, posprefix = 0; cur = setList->dirNamePrefix[pos++], true;) + { + if (cur == '\0' || cur == '|') + { + // Check prefix if not empty + if (posprefix) + { + switch (sysutil_check_name_string(buf, 1, CELL_SAVEDATA_DIRNAME_SIZE)) + { + case -1: + { + // ****** sysutil savedata parameter error : 16 ****** + return 16; + } + case -2: + { + // ****** sysutil savedata parameter error : 17 ****** + return 17; + } + case 0: break; + default: ASSUME(0); + } + } + + if (cur == '\0') + { + break; + } + + // Note: no need to reset buffer, only position + posprefix = 0; + continue; + } + + if (posprefix == CELL_SAVEDATA_DIRNAME_SIZE) + { + // ****** sysutil savedata parameter error : 17 ****** + return 17; + } + + buf[posprefix++] = cur; + } if (setList->reserved) { diff --git a/rpcs3/Emu/Cell/Modules/cellSysCache.cpp b/rpcs3/Emu/Cell/Modules/cellSysCache.cpp index b9f5cdaa1f..3077f63f2e 100644 --- a/rpcs3/Emu/Cell/Modules/cellSysCache.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSysCache.cpp @@ -115,13 +115,13 @@ error_code cellSysCacheMount(vm::ptr param) const auto cache = g_fxo->get(); - if (!param || !std::memchr(param->cacheId, '\0', CELL_SYSCACHE_ID_SIZE)) + if (!param || (param->cacheId[0] && sysutil_check_name_string(param->cacheId, 1, CELL_SYSCACHE_ID_SIZE) != 0)) { return CELL_SYSCACHE_ERROR_PARAM; } // Full virtualized cache id (with title id included) - std::string cache_id = vfs::escape(Emu.GetTitleID() + '_' + param->cacheId, true); + std::string cache_id = vfs::escape(Emu.GetTitleID() + '_' + param->cacheId); // Full path to virtual cache root (/dev_hdd1) std::string new_path = cache->cache_root + cache_id + '/'; diff --git a/rpcs3/Emu/Cell/Modules/cellSysutil.cpp b/rpcs3/Emu/Cell/Modules/cellSysutil.cpp index cfc3ffd6d6..e59a93bd32 100644 --- a/rpcs3/Emu/Cell/Modules/cellSysutil.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSysutil.cpp @@ -3,6 +3,7 @@ #include "Emu/IdManager.h" #include "Emu/Cell/PPUModule.h" +#include "Emu/Cell/lv2/sys_process.h" #include "cellSysutil.h" #include "Utilities/StrUtil.h" @@ -134,6 +135,64 @@ void fmt_class_string::format(std::string& out, u64 arg) }); } +// Common string checks used in libsysutil functions +s32 sysutil_check_name_string(const char* src, s32 minlen, s32 maxlen) +{ + s32 lastpos; + + if (g_ps3_process_info.sdk_ver > 0x36FFFF) + { + // Limit null terminator boundary to before buffer max size + lastpos = std::max(maxlen - 1, 0); + } + else + { + // Limit null terminator boundary to one after buffer max size + lastpos = maxlen; + } + + char cur = src[0]; + + if (cur == '_') + { + // Invalid character at start + return -1; + } + + for (u32 index = 0;; cur = src[++index]) + { + if (cur == '\0' || index == maxlen) + { + if (minlen > index || (maxlen == index && src[lastpos])) + { + // String length is invalid + return -2; + } + + // OK + return 0; + } + + if (cur >= 'A' && cur <= 'Z') + { + continue; + } + + if (cur >= '0' && cur <= '9') + { + continue; + } + + if (cur == '-' || cur == '_') + { + continue; + } + + // Invalid character found + return -1; + } +} + s32 _cellSysutilGetSystemParamInt() { UNIMPLEMENTED_FUNC(cellSysutil); diff --git a/rpcs3/Emu/Cell/Modules/cellSysutil.h b/rpcs3/Emu/Cell/Modules/cellSysutil.h index 6015e50b2b..fe5ff892e7 100644 --- a/rpcs3/Emu/Cell/Modules/cellSysutil.h +++ b/rpcs3/Emu/Cell/Modules/cellSysutil.h @@ -204,3 +204,4 @@ struct CellSysCacheParam extern void sysutil_register_cb(std::function&&); extern void sysutil_send_system_cmd(u64 status, u64 param); +s32 sysutil_check_name_string(const char* src, s32 minlen, s32 maxlen);