IopBios: Fix opening host: or host:. as a directory

This commit is contained in:
Connor McLaughlin 2022-08-26 01:50:06 +10:00 committed by refractionpcsx2
parent edc82d77a5
commit cb2a21ef19
1 changed files with 26 additions and 17 deletions

View File

@ -69,7 +69,7 @@ static std::string hostRoot;
void Hle_SetElfPath(const char* elfFileName)
{
DevCon.WriteLn("HLE Host: Will load ELF: %s\n", elfFileName);
hostRoot = Path::ToNativePath(Path::GetDirectory(elfFileName)) + FS_OSPATH_SEPARATOR_STR;
hostRoot = Path::ToNativePath(Path::GetDirectory(elfFileName));
Console.WriteLn("HLE Host: Set 'host:' root path to: %s\n", hostRoot.c_str());
}
@ -98,26 +98,35 @@ namespace R3000A
#define FIO_SO_IFREG 0x0010
#define FIO_SO_IFDIR 0x0020
static std::string host_path(const std::string& path)
static std::string host_path(const std::string& path, bool allow_open_host_root)
{
// We are NOT allowing to use the root of the host unit.
// For now it just supports relative folders from the location of the elf
std::string native_path(Path::Canonicalize(path));
std::string new_path;
if (StringUtil::StartsWith(native_path, hostRoot))
if (!hostRoot.empty() && StringUtil::StartsWith(native_path, hostRoot))
new_path = std::move(native_path);
else // relative paths
else if (!hostRoot.empty()) // relative paths
new_path = Path::Combine(hostRoot, native_path);
// Double-check that it falls within the directory of the elf.
// Not a real sandbox, but emulators shouldn't be treated as such. Don't run untrusted code!
std::string canonicalized_path(Path::Canonicalize(new_path));
if (!StringUtil::StartsWith(canonicalized_path, hostRoot))
// Are we opening the root of host? (i.e. `host:.` or `host:`)
// We want to allow this as a directory open, but not as a file open.
if (!allow_open_host_root || canonicalized_path != hostRoot)
{
Console.Error(fmt::format(
"IopHLE: Denying access to path outside of ELF directory. Requested path: '{}', Resolved path: '{}', ELF directory: '{}'",
path, new_path, hostRoot));
new_path.clear();
// Only allow descendants of the hostfs directory.
if (canonicalized_path.length() <= hostRoot.length() || // Length has to be equal or longer,
!StringUtil::StartsWith(canonicalized_path, hostRoot) || // and start with the host root,
canonicalized_path[hostRoot.length()] != FS_OSPATH_SEPARATOR_CHARACTER) // and we can't access a sibling.
{
Console.Error(fmt::format(
"IopHLE: Denying access to path outside of ELF directory. Requested path: '{}', Resolved path: '{}', ELF directory: '{}'",
path, new_path, hostRoot));
new_path.clear();
}
}
return new_path;
@ -136,7 +145,7 @@ namespace R3000A
static int host_stat(const std::string path, fio_stat_t* host_stats)
{
struct stat file_stats;
const std::string file_path(host_path(path));
const std::string file_path(host_path(path, true));
if (!FileSystem::StatFile(file_path.c_str(), &file_stats))
return -IOP_ENOENT;
@ -227,7 +236,7 @@ namespace R3000A
static int open(IOManFile** file, const std::string& full_path, s32 flags, u16 mode)
{
const std::string path(full_path.substr(full_path.find(':') + 1));
const std::string file_path(host_path(path));
const std::string file_path(host_path(path, false));
int native_flags = O_BINARY; // necessary in Windows.
switch (flags & IOP_O_RDWR)
@ -325,7 +334,7 @@ namespace R3000A
static int open(IOManDir** dir, const std::string& full_path)
{
std::string relativePath = full_path.substr(full_path.find(':') + 1);
std::string path = host_path(relativePath);
std::string path = host_path(relativePath, true);
FileSystem::FindResultsArray results;
if (!FileSystem::FindFiles(path.c_str(), "*", FILESYSTEM_FIND_FILES | FILESYSTEM_FIND_FOLDERS | FILESYSTEM_FIND_RELATIVE_PATHS | FILESYSTEM_FIND_HIDDEN_FILES, &results))
@ -345,7 +354,7 @@ namespace R3000A
return 0;
StringUtil::Strlcpy(hostcontent->name, dir->FileName, sizeof(hostcontent->name));
host_stat(host_path(Path::Combine(basedir, dir->FileName)), &hostcontent->stat);
host_stat(host_path(Path::Combine(basedir, dir->FileName), true), &hostcontent->stat);
static_cast<void>(std::next(dir)); /* This is for avoid warning of non used return value */
return 1;
@ -609,7 +618,7 @@ namespace R3000A
if (is_host(path))
{
const std::string full_path = host_path(path.substr(path.find(':') + 1));
const std::string full_path = host_path(path.substr(path.find(':') + 1), true);
char buf[sizeof(fio_stat_t)];
v0 = host_stat(full_path, (fio_stat_t*)&buf);
@ -646,7 +655,7 @@ namespace R3000A
if (is_host(full_path))
{
const std::string path = full_path.substr(full_path.find(':') + 1);
const std::string file_path(host_path(path));
const std::string file_path(host_path(path, false));
const bool succeeded = FileSystem::DeleteFilePath(file_path.c_str());
if (!succeeded)
Console.Warning("IOPHLE remove_HLE failed for '%s'", file_path.c_str());
@ -663,7 +672,7 @@ namespace R3000A
if (is_host(full_path))
{
const std::string path = full_path.substr(full_path.find(':') + 1);
const std::string folder_path(host_path(path));
const std::string folder_path(host_path(path, false)); // NOTE: Don't allow creating the ELF directory.
const bool succeeded = FileSystem::CreateDirectoryPath(folder_path.c_str(), false);
if (!succeeded)
Console.Warning("IOPHLE mkdir_HLE failed for '%s'", folder_path.c_str());
@ -704,7 +713,7 @@ namespace R3000A
if (is_host(full_path))
{
const std::string path = full_path.substr(full_path.find(':') + 1);
const std::string folder_path(host_path(path));
const std::string folder_path(host_path(path, false)); // NOTE: Don't allow removing the elf directory itself.
const bool succeeded = FileSystem::DeleteDirectory(folder_path.c_str());
if (!succeeded)
Console.Warning("IOPHLE rmdir_HLE failed for '%s'", folder_path.c_str());