[IO]: Add functions to read file streams safely (#862)

This commit is contained in:
Edo 2023-03-21 20:30:13 +00:00 committed by GitHub
parent ed9fc9aa7b
commit b89dd52118
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 94 additions and 8 deletions

View File

@ -6,15 +6,86 @@ namespace Components::GSC
{
const char* IO::ForbiddenStrings[] = { R"(..)", R"(../)", R"(..\)" };
FILE* IO::openScriptIOFileHandle;
std::filesystem::path IO::Path;
void IO::GScr_OpenFile()
{
const auto* filepath = Game::Scr_GetString(0);
const auto* mode = Game::Scr_GetString(1);
if (mode != "read"s)
{
Logger::PrintError(Game::CON_CHANNEL_PARSERSCRIPT, "Valid openfile modes are 'read'\n");
Game::Scr_AddInt(-1);
return;
}
if (openScriptIOFileHandle)
{
Logger::PrintError(Game::CON_CHANNEL_PARSERSCRIPT, "OpenFile failed. {} files already open\n", 1);
Game::Scr_AddInt(-1);
return;
}
const auto scriptData = Path / "scriptdata"s / filepath;
_set_errno(0);
const auto result = fopen_s(&openScriptIOFileHandle, scriptData.string().data(), "r");
if (result || !openScriptIOFileHandle)
{
Logger::PrintError(Game::CON_CHANNEL_PARSERSCRIPT, "OpenFile failed. '{}'", result);
Game::Scr_AddInt(-1);
return;
}
Game::Scr_AddInt(1);
}
void IO::GScr_ReadStream()
{
if (!openScriptIOFileHandle)
{
Logger::PrintError(Game::CON_CHANNEL_PARSERSCRIPT, "ReadStream failed. File stream was not opened\n");
return;
}
char line[1024]{};
if (std::fgets(line, sizeof(line), openScriptIOFileHandle) != nullptr)
{
Game::Scr_AddString(line);
return;
}
Logger::PrintError(Game::CON_CHANNEL_PARSERSCRIPT, "ReadStream failed.\n");
if (std::feof(openScriptIOFileHandle))
{
Logger::Print(Game::CON_CHANNEL_PARSERSCRIPT, "ReadStream: EOF reached\n");
}
}
void IO::GScr_CloseFile()
{
if (!openScriptIOFileHandle)
{
Logger::PrintError(Game::CON_CHANNEL_PARSERSCRIPT, "CloseFile failed. File stream was not opened\n");
Game::Scr_AddInt(-1);
return;
}
Game::Scr_AddInt(std::fclose(openScriptIOFileHandle));
openScriptIOFileHandle = nullptr;
}
void IO::AddScriptFunctions()
{
Script::AddFunction("FileWrite", [] // gsc: FileWrite(<filepath>, <string>, <mode>)
{
const auto* filepath = Game::Scr_GetString(0);
auto* text = Game::Scr_GetString(1);
auto* mode = Game::Scr_GetString(2);
const auto* text = Game::Scr_GetString(1);
const auto* mode = Game::Scr_GetString(2);
if (!filepath)
{
@ -32,14 +103,14 @@ namespace Components::GSC
{
if (std::strstr(filepath, ForbiddenStrings[i]) != nullptr)
{
Logger::PrintError(Game::CON_CHANNEL_ERROR, "FileWrite: directory traversal is not allowed!\n");
Logger::PrintError(Game::CON_CHANNEL_PARSERSCRIPT, "FileWrite: directory traversal is not allowed!\n");
return;
}
}
if (mode != "append"s && mode != "write"s)
{
Logger::Warning(Game::CON_CHANNEL_SCRIPT, "FileWrite: mode not defined or was wrong, defaulting to 'write'\n");
Logger::Warning(Game::CON_CHANNEL_PARSERSCRIPT, "FileWrite: mode not defined or was wrong, defaulting to 'write'\n");
mode = "write";
}
@ -61,7 +132,7 @@ namespace Components::GSC
{
if (std::strstr(filepath, ForbiddenStrings[i]) != nullptr)
{
Logger::PrintError(Game::CON_CHANNEL_ERROR, "FileRead: directory traversal is not allowed!\n");
Logger::PrintError(Game::CON_CHANNEL_PARSERSCRIPT, "FileRead: directory traversal is not allowed!\n");
return;
}
}
@ -71,7 +142,7 @@ namespace Components::GSC
std::string file;
if (!Utils::IO::ReadFile(scriptData.string(), &file))
{
Logger::PrintError(Game::CON_CHANNEL_ERROR, "FileRead: file '{}' not found!\n", scriptData.string());
Logger::PrintError(Game::CON_CHANNEL_PARSERSCRIPT, "FileRead: file '{}' not found!\n", scriptData.string());
return;
}
@ -92,7 +163,7 @@ namespace Components::GSC
{
if (std::strstr(filepath, ForbiddenStrings[i]) != nullptr)
{
Logger::PrintError(Game::CON_CHANNEL_ERROR, "FileExists: directory traversal is not allowed!\n");
Logger::PrintError(Game::CON_CHANNEL_PARSERSCRIPT, "FileExists: directory traversal is not allowed!\n");
return;
}
}
@ -114,7 +185,7 @@ namespace Components::GSC
{
if (std::strstr(filepath, ForbiddenStrings[i]) != nullptr)
{
Logger::Print("FileRemove: directory traversal is not allowed!\n");
Logger::PrintError(Game::CON_CHANNEL_PARSERSCRIPT, "FileRemove: directory traversal is not allowed!\n");
return;
}
}
@ -122,12 +193,21 @@ namespace Components::GSC
const auto scriptData = Path / "scriptdata"s / filepath;
Game::Scr_AddInt(Utils::IO::RemoveFile(scriptData.string()));
});
Script::AddFunction("ReadStream", GScr_ReadStream);
}
IO::IO()
{
openScriptIOFileHandle = nullptr;
Path = "userraw"s;
AddScriptFunctions();
Utils::Hook::Set<Game::BuiltinFunction>(0x79A858, GScr_OpenFile);
Utils::Hook::Set<int>(0x79A85C, 0);
Utils::Hook::Set<Game::BuiltinFunction>(0x79A864, GScr_CloseFile);
Utils::Hook::Set<int>(0x79A868, 0);
}
}

View File

@ -10,8 +10,14 @@ namespace Components::GSC
private:
static const char* ForbiddenStrings[];
static FILE* openScriptIOFileHandle;
static std::filesystem::path Path;
static void GScr_OpenFile();
static void GScr_ReadStream();
static void GScr_CloseFile();
static void AddScriptFunctions();
};
}