[IO]: Add functions to read file streams safely (#862)
This commit is contained in:
parent
ed9fc9aa7b
commit
b89dd52118
@ -6,15 +6,86 @@ namespace Components::GSC
|
|||||||
{
|
{
|
||||||
const char* IO::ForbiddenStrings[] = { R"(..)", R"(../)", R"(..\)" };
|
const char* IO::ForbiddenStrings[] = { R"(..)", R"(../)", R"(..\)" };
|
||||||
|
|
||||||
|
FILE* IO::openScriptIOFileHandle;
|
||||||
|
|
||||||
std::filesystem::path IO::Path;
|
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()
|
void IO::AddScriptFunctions()
|
||||||
{
|
{
|
||||||
Script::AddFunction("FileWrite", [] // gsc: FileWrite(<filepath>, <string>, <mode>)
|
Script::AddFunction("FileWrite", [] // gsc: FileWrite(<filepath>, <string>, <mode>)
|
||||||
{
|
{
|
||||||
const auto* filepath = Game::Scr_GetString(0);
|
const auto* filepath = Game::Scr_GetString(0);
|
||||||
auto* text = Game::Scr_GetString(1);
|
const auto* text = Game::Scr_GetString(1);
|
||||||
auto* mode = Game::Scr_GetString(2);
|
const auto* mode = Game::Scr_GetString(2);
|
||||||
|
|
||||||
if (!filepath)
|
if (!filepath)
|
||||||
{
|
{
|
||||||
@ -32,14 +103,14 @@ namespace Components::GSC
|
|||||||
{
|
{
|
||||||
if (std::strstr(filepath, ForbiddenStrings[i]) != nullptr)
|
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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode != "append"s && mode != "write"s)
|
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";
|
mode = "write";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +132,7 @@ namespace Components::GSC
|
|||||||
{
|
{
|
||||||
if (std::strstr(filepath, ForbiddenStrings[i]) != nullptr)
|
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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -71,7 +142,7 @@ namespace Components::GSC
|
|||||||
std::string file;
|
std::string file;
|
||||||
if (!Utils::IO::ReadFile(scriptData.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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,7 +163,7 @@ namespace Components::GSC
|
|||||||
{
|
{
|
||||||
if (std::strstr(filepath, ForbiddenStrings[i]) != nullptr)
|
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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -114,7 +185,7 @@ namespace Components::GSC
|
|||||||
{
|
{
|
||||||
if (std::strstr(filepath, ForbiddenStrings[i]) != nullptr)
|
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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -122,12 +193,21 @@ namespace Components::GSC
|
|||||||
const auto scriptData = Path / "scriptdata"s / filepath;
|
const auto scriptData = Path / "scriptdata"s / filepath;
|
||||||
Game::Scr_AddInt(Utils::IO::RemoveFile(scriptData.string()));
|
Game::Scr_AddInt(Utils::IO::RemoveFile(scriptData.string()));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Script::AddFunction("ReadStream", GScr_ReadStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
IO::IO()
|
IO::IO()
|
||||||
{
|
{
|
||||||
|
openScriptIOFileHandle = nullptr;
|
||||||
Path = "userraw"s;
|
Path = "userraw"s;
|
||||||
|
|
||||||
AddScriptFunctions();
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,14 @@ namespace Components::GSC
|
|||||||
private:
|
private:
|
||||||
static const char* ForbiddenStrings[];
|
static const char* ForbiddenStrings[];
|
||||||
|
|
||||||
|
static FILE* openScriptIOFileHandle;
|
||||||
|
|
||||||
static std::filesystem::path Path;
|
static std::filesystem::path Path;
|
||||||
|
|
||||||
|
static void GScr_OpenFile();
|
||||||
|
static void GScr_ReadStream();
|
||||||
|
static void GScr_CloseFile();
|
||||||
|
|
||||||
static void AddScriptFunctions();
|
static void AddScriptFunctions();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user