diff --git a/Source/Core/Common/FileUtil.cpp b/Source/Core/Common/FileUtil.cpp index e761f3ade1..acf154f81a 100644 --- a/Source/Core/Common/FileUtil.cpp +++ b/Source/Core/Common/FileUtil.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -30,7 +31,6 @@ #include #include #include -#include #include #endif @@ -712,6 +712,19 @@ std::string GetBundleDirectory() } #endif +std::string GetAbsolutePath(const std::string& path) +{ +#ifdef _WIN32 + wchar_t absolute_path[_MAX_PATH]; + wchar_t* result = _wfullpath(absolute_path, UTF8ToTStr(path).c_str(), _MAX_PATH); + return result ? TStrToUTF8(result) : ""; +#else + char absolute_path[MAX_PATH + 1]; + char* result = realpath(path.c_str(), absolute_path); + return result ? result : ""; +#endif +} + std::string& GetExeDirectory() { static std::string DolphinPath; diff --git a/Source/Core/Common/FileUtil.h b/Source/Core/Common/FileUtil.h index f4a20f623d..cc0ec5a651 100644 --- a/Source/Core/Common/FileUtil.h +++ b/Source/Core/Common/FileUtil.h @@ -133,6 +133,10 @@ std::string CreateTempDir(); // Get a filename that can hopefully be atomically renamed to the given path. std::string GetTempFilenameForAtomicWrite(const std::string& path); +// Converts the given path into an absolute path. +// An empty string is returned if an error occurs. +std::string GetAbsolutePath(const std::string& path); + // Gets a set user directory path // Don't call prior to setting the base user directory const std::string& GetUserPath(unsigned int dir_index); diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp index 5b57b8eb97..b49c286efa 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp @@ -8,6 +8,8 @@ #include "Common/CommonPaths.h" #include "Common/CommonTypes.h" #include "Common/FileUtil.h" +#include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" #include "Common/NandPaths.h" #include "Common/StringUtil.h" @@ -23,8 +25,6 @@ static std::map> openFiles; // This is used by several of the FileIO and /dev/fs functions std::string HLE_IPC_BuildFilename(std::string path_wii) { - std::string path_full = File::GetUserPath(D_SESSION_WIIROOT_IDX); - // Replaces chars that FAT32 can't support with strings defined in /sys/replace for (auto& replacement : replacements) { @@ -32,9 +32,30 @@ std::string HLE_IPC_BuildFilename(std::string path_wii) path_wii.replace(j, 1, replacement.second); } - path_full += path_wii; + const std::string root_path = File::GetUserPath(D_SESSION_WIIROOT_IDX); + const std::string full_path = root_path + path_wii; - return path_full; + const std::string absolute_root_path = File::GetAbsolutePath(root_path); + const std::string absolute_full_path = File::GetAbsolutePath(full_path); + if (absolute_root_path.empty() || absolute_full_path.empty()) + { + PanicAlert("IOS HLE: Couldn't get an absolute path; the root directory will be returned. " + "This will most likely lead to failures."); + return root_path; + } + + if (path_wii.empty() || path_wii[0] != '/' || + absolute_full_path.compare(0, absolute_root_path.size(), absolute_root_path) != 0) + { + // Prevent the emulated system from accessing files that aren't in the NAND directory. + // (Emulated software that tries to exploit Dolphin might access a path like "/../..".) + WARN_LOG(WII_IPC_FILEIO, + "The emulated software tried to access a file outside of the NAND directory: %s", + absolute_full_path.c_str()); + return root_path; + } + + return full_path; } void HLE_IPC_CreateVirtualFATFilesystem()