mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-02-23 06:40:49 +00:00
cellSaveData: Check filename format of savedata files (#11502)
This commit is contained in:
parent
2d5d5746d1
commit
fd6c33980b
@ -120,6 +120,91 @@ struct savedata_manager
|
|||||||
atomic_t<s32> last_cbresult_error_dialog{0}; // CBRESULT errors are negative
|
atomic_t<s32> last_cbresult_error_dialog{0}; // CBRESULT errors are negative
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int check_filename(std::string_view file_path, bool disallow_system_files, bool account_sfo_pfd)
|
||||||
|
{
|
||||||
|
if (file_path.size() >= CELL_SAVEDATA_FILENAME_SIZE)
|
||||||
|
{
|
||||||
|
// ****** sysutil savedata parameter error : 71 ******
|
||||||
|
return 71;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto dotpos = file_path.find_last_of('.');
|
||||||
|
|
||||||
|
if (dotpos == umax)
|
||||||
|
{
|
||||||
|
// Point to end of string instead
|
||||||
|
dotpos = file_path.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_path.empty() || dotpos > 8u || file_path.size() - dotpos > 4u)
|
||||||
|
{
|
||||||
|
// ****** sysutil savedata parameter error : 70 ******
|
||||||
|
return 70;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_path == "."sv || (!account_sfo_pfd && (file_path == "PARAM.SFO"sv || file_path == "PARAM.PFD"sv)))
|
||||||
|
{
|
||||||
|
// ****** sysutil savedata parameter error : 70 ******
|
||||||
|
return 70;
|
||||||
|
}
|
||||||
|
|
||||||
|
char name[CELL_SAVEDATA_FILENAME_SIZE - 3];
|
||||||
|
|
||||||
|
if (dotpos)
|
||||||
|
{
|
||||||
|
// Copy file name
|
||||||
|
std::span dst(name, dotpos + 1);
|
||||||
|
strcpy_trunc(dst, file_path);
|
||||||
|
|
||||||
|
// Allow multiple '.' even though sysutil_check_name_string does not
|
||||||
|
std::replace(name, name + dotpos, '.', '-');
|
||||||
|
|
||||||
|
// Allow '_' at start even though sysutil_check_name_string does not
|
||||||
|
if (name[0] == '_')
|
||||||
|
{
|
||||||
|
name[0] = '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (disallow_system_files && ((dotpos >= 5u && std::memcmp(name, "PARAM", 5) == 0) ||
|
||||||
|
(dotpos >= 4u && std::memcmp(name, "ICON", 4) == 0) ||
|
||||||
|
(dotpos >= 3u && std::memcmp(name, "PIC", 3) == 0) ||
|
||||||
|
(dotpos >= 3u && std::memcmp(name, "SND", 3) == 0)))
|
||||||
|
{
|
||||||
|
// ****** sysutil savedata parameter error : 70 ******
|
||||||
|
return 70;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check filename
|
||||||
|
if (sysutil_check_name_string(name, 1, 9) == -1)
|
||||||
|
{
|
||||||
|
// ****** sysutil savedata parameter error : 70 ******
|
||||||
|
return 70;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_path.size() > dotpos + 1)
|
||||||
|
{
|
||||||
|
// Copy file extension
|
||||||
|
std::span dst(name, file_path.size() - dotpos);
|
||||||
|
strcpy_trunc(dst, file_path.substr(dotpos + 1));
|
||||||
|
|
||||||
|
// Allow '_' at start even though sysutil_check_name_string does not
|
||||||
|
if (name[0] == '_')
|
||||||
|
{
|
||||||
|
name[0] = '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check file extension
|
||||||
|
if (sysutil_check_name_string(name, 1, 4) == -1)
|
||||||
|
{
|
||||||
|
// ****** sysutil savedata parameter error : 70 ******
|
||||||
|
return 70;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static std::vector<SaveDataEntry> get_save_entries(const std::string& base_dir, const std::string& prefix)
|
static std::vector<SaveDataEntry> get_save_entries(const std::string& base_dir, const std::string& prefix)
|
||||||
{
|
{
|
||||||
std::vector<SaveDataEntry> save_entries;
|
std::vector<SaveDataEntry> save_entries;
|
||||||
@ -159,7 +244,7 @@ static std::vector<SaveDataEntry> get_save_entries(const std::string& base_dir,
|
|||||||
|
|
||||||
for (const auto& entry2 : fs::dir(base_dir + entry.name))
|
for (const auto& entry2 : fs::dir(base_dir + entry.name))
|
||||||
{
|
{
|
||||||
if (entry2.is_directory)
|
if (entry2.is_directory || check_filename(vfs::unescape(entry2.name), false, true))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -686,7 +771,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
|
|||||||
|
|
||||||
for (const auto& entry2 : fs::dir(base_dir + entry.name))
|
for (const auto& entry2 : fs::dir(base_dir + entry.name))
|
||||||
{
|
{
|
||||||
if (entry2.is_directory)
|
if (entry2.is_directory || check_filename(vfs::unescape(entry2.name), false, true))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -1350,12 +1435,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
|
|||||||
|
|
||||||
if (!entry.is_directory)
|
if (!entry.is_directory)
|
||||||
{
|
{
|
||||||
if (entry.name == "."sv)
|
if (check_filename(entry.name, false, false))
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry.name == "PARAM.SFO"sv || entry.name == "PARAM.PFD"sv)
|
|
||||||
{
|
{
|
||||||
continue; // system files are not included in the file list
|
continue; // system files are not included in the file list
|
||||||
}
|
}
|
||||||
@ -1575,7 +1655,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
|
|||||||
// Read file into a vector and make a memory file
|
// Read file into a vector and make a memory file
|
||||||
entry.name = vfs::unescape(entry.name);
|
entry.name = vfs::unescape(entry.name);
|
||||||
|
|
||||||
if (entry.name == ".")
|
if (check_filename(entry.name, false, true))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -1647,85 +1727,12 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto dotpos = file_path.find_last_of('.');
|
if (int error = check_filename(file_path, true, false))
|
||||||
|
|
||||||
if (dotpos == umax)
|
|
||||||
{
|
{
|
||||||
// Point to end of string instead
|
savedata_result = {CELL_SAVEDATA_ERROR_PARAM, "%d", error};
|
||||||
dotpos = file_path.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file_path.empty() || dotpos > 8u || file_path.size() - dotpos > 4u)
|
|
||||||
{
|
|
||||||
cellSaveData.error("savedata_op(): fileSet->fileName is illegal ('%s')", file_path);
|
|
||||||
|
|
||||||
// ****** sysutil savedata parameter error : 70 ******
|
|
||||||
savedata_result = {CELL_SAVEDATA_ERROR_PARAM, "70"};
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
char name[10];
|
|
||||||
|
|
||||||
if (dotpos)
|
|
||||||
{
|
|
||||||
// Copy file name
|
|
||||||
std::span dst(name, dotpos + 1);
|
|
||||||
strcpy_trunc(dst, file_path);
|
|
||||||
|
|
||||||
// Allow multiple '.' even though sysutil_check_name_string does not
|
|
||||||
std::replace(name, name + dotpos, '.', '-');
|
|
||||||
|
|
||||||
// Allow '_' at start even though sysutil_check_name_string does not
|
|
||||||
if (name[0] == '_')
|
|
||||||
{
|
|
||||||
name[0] = '-';
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((dotpos >= 5u && std::memcmp(name, "PARAM", 5) == 0) ||
|
|
||||||
(dotpos >= 4u && std::memcmp(name, "ICON", 4) == 0) ||
|
|
||||||
(dotpos >= 3u && std::memcmp(name, "PIC", 3) == 0) ||
|
|
||||||
(dotpos >= 3u && std::memcmp(name, "SND", 3) == 0))
|
|
||||||
{
|
|
||||||
// ****** sysutil savedata parameter error : 70 ******
|
|
||||||
cellSaveData.error("savedata_op(): fileSet->fileName is set to a system file name (%s)", file_path);
|
|
||||||
savedata_result = {CELL_SAVEDATA_ERROR_PARAM, "70"};
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check filename
|
|
||||||
if (sysutil_check_name_string(name, 1, 9) == -1)
|
|
||||||
{
|
|
||||||
cellSaveData.error("savedata_op(): fileSet->fileName is illegal due to file name ('%s')", file_path);
|
|
||||||
|
|
||||||
// ****** sysutil savedata parameter error : 70 ******
|
|
||||||
savedata_result = {CELL_SAVEDATA_ERROR_PARAM, "70"};
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file_path.size() > dotpos + 1)
|
|
||||||
{
|
|
||||||
// Copy file extension
|
|
||||||
std::span dst(name, file_path.size() - dotpos);
|
|
||||||
strcpy_trunc(dst, file_path.operator std::string_view().substr(dotpos + 1));
|
|
||||||
|
|
||||||
// Allow '_' at start even though sysutil_check_name_string does not
|
|
||||||
if (name[0] == '_')
|
|
||||||
{
|
|
||||||
name[0] = '-';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check file extension
|
|
||||||
if (sysutil_check_name_string(name, 1, 4) == -1)
|
|
||||||
{
|
|
||||||
cellSaveData.error("savedata_op(): fileSet->fileName is illegal due to file extension ('%s')", file_path);
|
|
||||||
|
|
||||||
// ****** sysutil savedata parameter error : 70 ******
|
|
||||||
savedata_result = {CELL_SAVEDATA_ERROR_PARAM, "70"};
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == CELL_SAVEDATA_FILETYPE_SECUREFILE)
|
if (type == CELL_SAVEDATA_FILETYPE_SECUREFILE)
|
||||||
{
|
{
|
||||||
cellSaveData.notice("SECUREFILE: %s -> %s", file_path, fileSet->secureFileId);
|
cellSaveData.notice("SECUREFILE: %s -> %s", file_path, fileSet->secureFileId);
|
||||||
@ -2087,7 +2094,7 @@ static NEVER_INLINE error_code savedata_get_list_item(vm::cptr<char> dirName, vm
|
|||||||
|
|
||||||
for (const auto& entry : fs::dir(save_path))
|
for (const auto& entry : fs::dir(save_path))
|
||||||
{
|
{
|
||||||
if (entry.is_directory)
|
if (entry.is_directory || check_filename(vfs::unescape(entry.name), false, false))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -2095,7 +2102,8 @@ static NEVER_INLINE error_code savedata_get_list_item(vm::cptr<char> dirName, vm
|
|||||||
size_kbytes += ::narrow<u32>((entry.size + 1023) / 1024); // firmware rounds this value up
|
size_kbytes += ::narrow<u32>((entry.size + 1023) / 1024); // firmware rounds this value up
|
||||||
}
|
}
|
||||||
|
|
||||||
*sizeKB = size_kbytes;
|
// Add a seemingly constant allocation disk space of PARAM.SFO + PARAM.PFD
|
||||||
|
*sizeKB = size_kbytes + 35;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bind)
|
if (bind)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user