Merge pull request #9759 from Techjar/netplay-sanitize-gci
NetPlay: Check file names when receiving GCI folder
This commit is contained in:
commit
c404452d3e
|
@ -95,6 +95,13 @@ bool IsTitlePath(const std::string& path, std::optional<FromWhichRoot> from, u64
|
||||||
return true;
|
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)
|
std::string EscapeFileName(const std::string& filename)
|
||||||
{
|
{
|
||||||
// Prevent paths from containing special names like ., .., ..., ...., and so on
|
// 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__");
|
std::string filename_with_escaped_double_underscores = ReplaceAll(filename, "__", "__5f____5f__");
|
||||||
|
|
||||||
// Escape all other characters that need to be escaped
|
// Escape all other characters that need to be escaped
|
||||||
static const std::unordered_set<char> chars_to_replace = {'\"', '*', '/', ':', '<',
|
|
||||||
'>', '?', '\\', '|', '\x7f'};
|
|
||||||
std::string result;
|
std::string result;
|
||||||
result.reserve(filename_with_escaped_double_underscores.size());
|
result.reserve(filename_with_escaped_double_underscores.size());
|
||||||
for (char c : filename_with_escaped_double_underscores)
|
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));
|
result.append(fmt::format("__{:02x}__", c));
|
||||||
else
|
else
|
||||||
result.push_back(c);
|
result.push_back(c);
|
||||||
|
@ -151,4 +156,11 @@ std::string UnescapeFileName(const std::string& filename)
|
||||||
|
|
||||||
return result;
|
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
|
} // namespace Common
|
||||||
|
|
|
@ -43,4 +43,6 @@ std::string EscapeFileName(const std::string& filename);
|
||||||
std::string EscapePath(const std::string& path);
|
std::string EscapePath(const std::string& path);
|
||||||
// Reverses escaping done by EscapeFileName
|
// Reverses escaping done by EscapeFileName
|
||||||
std::string UnescapeFileName(const std::string& filename);
|
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
|
} // namespace Common
|
||||||
|
|
|
@ -905,7 +905,8 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
|
||||||
std::string file_name;
|
std::string file_name;
|
||||||
packet >> 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);
|
SyncSaveDataResponse(false);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in New Issue