NetPlay: Check file names when receiving GCI folder

This commit is contained in:
Techjar 2021-05-28 07:11:52 -04:00
parent b3a414ea9d
commit 1377f31cf8
3 changed files with 19 additions and 4 deletions

View File

@ -95,6 +95,13 @@ bool IsTitlePath(const std::string& path, std::optional<FromWhichRoot> from, u64
return true;
}
static bool IsIllegalCharacter(char c)
{
static const std::unordered_set<char> illegal_chars = {'\"', '*', '/', ':', '<',
'>', '?', '\\', '|', '\x7f'};
return (c >= 0 && c <= 0x1F) || illegal_chars.find(c) != illegal_chars.end();
}
std::string EscapeFileName(const std::string& filename)
{
// Prevent paths from containing special names like ., .., ..., ...., and so on
@ -105,13 +112,11 @@ std::string EscapeFileName(const std::string& filename)
std::string filename_with_escaped_double_underscores = ReplaceAll(filename, "__", "__5f____5f__");
// Escape all other characters that need to be escaped
static const std::unordered_set<char> chars_to_replace = {'\"', '*', '/', ':', '<',
'>', '?', '\\', '|', '\x7f'};
std::string result;
result.reserve(filename_with_escaped_double_underscores.size());
for (char c : filename_with_escaped_double_underscores)
{
if ((c >= 0 && c <= 0x1F) || chars_to_replace.find(c) != chars_to_replace.end())
if (IsIllegalCharacter(c))
result.append(fmt::format("__{:02x}__", c));
else
result.push_back(c);
@ -151,4 +156,11 @@ std::string UnescapeFileName(const std::string& filename)
return result;
}
bool IsFileNameSafe(const std::string_view filename)
{
return !filename.empty() &&
!std::all_of(filename.begin(), filename.end(), [](char c) { return c == '.'; }) &&
std::none_of(filename.begin(), filename.end(), IsIllegalCharacter);
}
} // namespace Common

View File

@ -43,4 +43,6 @@ std::string EscapeFileName(const std::string& filename);
std::string EscapePath(const std::string& path);
// Reverses escaping done by EscapeFileName
std::string UnescapeFileName(const std::string& filename);
// Tests for a file name being "safe" as per the escaping defined in EscapeFileName
bool IsFileNameSafe(const std::string_view filename);
} // namespace Common

View File

@ -905,7 +905,8 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
std::string file_name;
packet >> file_name;
if (!DecompressPacketIntoFile(packet, path + DIR_SEP + file_name))
if (!Common::IsFileNameSafe(file_name) ||
!DecompressPacketIntoFile(packet, path + DIR_SEP + file_name))
{
SyncSaveDataResponse(false);
return 0;