mirror of https://github.com/PCSX2/pcsx2.git
CDVD: Improve handling of host: paths in cdvdLoadElf
This commit is contained in:
parent
85888a9a81
commit
4081d07dd8
|
@ -13,6 +13,7 @@
|
||||||
#include "Host.h"
|
#include "Host.h"
|
||||||
#include "R3000A.h"
|
#include "R3000A.h"
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
#include "IopBios.h"
|
||||||
#include "IopHw.h"
|
#include "IopHw.h"
|
||||||
#include "IopDma.h"
|
#include "IopDma.h"
|
||||||
#include "VMManager.h"
|
#include "VMManager.h"
|
||||||
|
@ -416,10 +417,11 @@ static bool cdvdUncheckedLoadDiscElf(ElfObject* elfo, IsoReader& isor, const std
|
||||||
|
|
||||||
bool cdvdLoadElf(ElfObject* elfo, const std::string_view& elfpath, bool isPSXElf, Error* error)
|
bool cdvdLoadElf(ElfObject* elfo, const std::string_view& elfpath, bool isPSXElf, Error* error)
|
||||||
{
|
{
|
||||||
if (elfpath.starts_with("host:"))
|
if (R3000A::ioman::is_host(elfpath))
|
||||||
{
|
{
|
||||||
std::string host_filename(elfpath.substr(5));
|
const std::string_view path(elfpath.substr(elfpath.find(':') + 1));
|
||||||
return elfo->OpenFile(host_filename, isPSXElf, error);
|
const std::string file_path(R3000A::ioman::host_path(path, false));
|
||||||
|
return elfo->OpenFile(file_path, isPSXElf, error);
|
||||||
}
|
}
|
||||||
else if (elfpath.starts_with("cdrom:") || elfpath.starts_with("cdrom0:"))
|
else if (elfpath.starts_with("cdrom:") || elfpath.starts_with("cdrom0:"))
|
||||||
{
|
{
|
||||||
|
|
|
@ -149,51 +149,6 @@ namespace R3000A
|
||||||
0x1000,
|
0x1000,
|
||||||
};
|
};
|
||||||
|
|
||||||
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 (!hostRoot.empty() && native_path.starts_with(hostRoot))
|
|
||||||
new_path = std::move(native_path);
|
|
||||||
else if (!hostRoot.empty()) // relative paths
|
|
||||||
new_path = Path::Combine(hostRoot, native_path);
|
|
||||||
|
|
||||||
// Allow opening the ELF override.
|
|
||||||
if (new_path == VMManager::Internal::GetELFOverride())
|
|
||||||
return new_path;
|
|
||||||
|
|
||||||
// Allow nothing if hostfs isn't enabled.
|
|
||||||
if (!EmuConfig.HostFs)
|
|
||||||
{
|
|
||||||
new_path.clear();
|
|
||||||
return new_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));
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
{
|
|
||||||
// Only allow descendants of the hostfs directory.
|
|
||||||
if (canonicalized_path.length() <= hostRoot.length() || // Length has to be equal or longer,
|
|
||||||
!canonicalized_path.starts_with(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is a workaround for GHS on *NIX platforms
|
// This is a workaround for GHS on *NIX platforms
|
||||||
// Whenever a program splits directories with a backslash (ulaunchelf)
|
// Whenever a program splits directories with a backslash (ulaunchelf)
|
||||||
// the directory is considered non-existant
|
// the directory is considered non-existant
|
||||||
|
@ -207,7 +162,7 @@ namespace R3000A
|
||||||
static int host_stat(const std::string path, fio_stat_t* host_stats, fio_stat_flags& stat = ioman_stat)
|
static int host_stat(const std::string path, fio_stat_t* host_stats, fio_stat_flags& stat = ioman_stat)
|
||||||
{
|
{
|
||||||
struct stat file_stats;
|
struct stat file_stats;
|
||||||
const std::string file_path(host_path(path, true));
|
const std::string file_path(ioman::host_path(path, true));
|
||||||
|
|
||||||
if (!FileSystem::StatFile(file_path.c_str(), &file_stats))
|
if (!FileSystem::StatFile(file_path.c_str(), &file_stats))
|
||||||
return -IOP_ENOENT;
|
return -IOP_ENOENT;
|
||||||
|
@ -303,7 +258,7 @@ namespace R3000A
|
||||||
static int open(IOManFile** file, const std::string& full_path, s32 flags, u16 mode)
|
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 path(full_path.substr(full_path.find(':') + 1));
|
||||||
const std::string file_path(host_path(path, false));
|
const std::string file_path(ioman::host_path(path, false));
|
||||||
int native_flags = O_BINARY; // necessary in Windows.
|
int native_flags = O_BINARY; // necessary in Windows.
|
||||||
|
|
||||||
switch (flags & IOP_O_RDWR)
|
switch (flags & IOP_O_RDWR)
|
||||||
|
@ -401,7 +356,7 @@ namespace R3000A
|
||||||
static int open(IOManDir** dir, const std::string& full_path)
|
static int open(IOManDir** dir, const std::string& full_path)
|
||||||
{
|
{
|
||||||
std::string relativePath = full_path.substr(full_path.find(':') + 1);
|
std::string relativePath = full_path.substr(full_path.find(':') + 1);
|
||||||
std::string path = host_path(relativePath, true);
|
std::string path = ioman::host_path(relativePath, true);
|
||||||
|
|
||||||
if (!FileSystem::DirectoryExists(path.c_str()))
|
if (!FileSystem::DirectoryExists(path.c_str()))
|
||||||
return -IOP_ENOENT; // Should return ENOTDIR if path is a file?
|
return -IOP_ENOENT; // Should return ENOTDIR if path is a file?
|
||||||
|
@ -425,13 +380,13 @@ namespace R3000A
|
||||||
{
|
{
|
||||||
fxio_dirent_t* hostcontent = (fxio_dirent_t*)buf;
|
fxio_dirent_t* hostcontent = (fxio_dirent_t*)buf;
|
||||||
StringUtil::Strlcpy(hostcontent->name, dir->FileName, sizeof(hostcontent->name));
|
StringUtil::Strlcpy(hostcontent->name, dir->FileName, sizeof(hostcontent->name));
|
||||||
host_stat(host_path(Path::Combine(basedir, dir->FileName), true), &hostcontent->stat);
|
host_stat(ioman::host_path(Path::Combine(basedir, dir->FileName), true), &hostcontent->stat);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fio_dirent_t* hostcontent = (fio_dirent_t*)buf;
|
fio_dirent_t* hostcontent = (fio_dirent_t*)buf;
|
||||||
StringUtil::Strlcpy(hostcontent->name, dir->FileName, sizeof(hostcontent->name));
|
StringUtil::Strlcpy(hostcontent->name, dir->FileName, sizeof(hostcontent->name));
|
||||||
host_stat(host_path(Path::Combine(basedir, dir->FileName), true), &hostcontent->stat);
|
host_stat(ioman::host_path(Path::Combine(basedir, dir->FileName), true), &hostcontent->stat);
|
||||||
}
|
}
|
||||||
|
|
||||||
dir = std::next(dir);
|
dir = std::next(dir);
|
||||||
|
@ -559,7 +514,7 @@ namespace R3000A
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_host(const std::string path)
|
bool is_host(const std::string_view path)
|
||||||
{
|
{
|
||||||
auto not_number_pos = path.find_first_not_of("0123456789", 4);
|
auto not_number_pos = path.find_first_not_of("0123456789", 4);
|
||||||
if (not_number_pos == std::string::npos)
|
if (not_number_pos == std::string::npos)
|
||||||
|
@ -568,6 +523,51 @@ namespace R3000A
|
||||||
return (path.compare(0, 4, "host") == 0 && path[not_number_pos] == ':');
|
return (path.compare(0, 4, "host") == 0 && path[not_number_pos] == ':');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string host_path(const std::string_view 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 (!hostRoot.empty() && native_path.starts_with(hostRoot))
|
||||||
|
new_path = std::move(native_path);
|
||||||
|
else if (!hostRoot.empty()) // relative paths
|
||||||
|
new_path = Path::Combine(hostRoot, native_path);
|
||||||
|
|
||||||
|
// Allow opening the ELF override.
|
||||||
|
if (new_path == VMManager::Internal::GetELFOverride())
|
||||||
|
return new_path;
|
||||||
|
|
||||||
|
// Allow nothing if hostfs isn't enabled.
|
||||||
|
if (!EmuConfig.HostFs)
|
||||||
|
{
|
||||||
|
new_path.clear();
|
||||||
|
return new_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));
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
// Only allow descendants of the hostfs directory.
|
||||||
|
if (canonicalized_path.length() <= hostRoot.length() || // Length has to be equal or longer,
|
||||||
|
!canonicalized_path.starts_with(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;
|
||||||
|
}
|
||||||
|
|
||||||
int open_HLE()
|
int open_HLE()
|
||||||
{
|
{
|
||||||
IOManFile* file = NULL;
|
IOManFile* file = NULL;
|
||||||
|
|
|
@ -71,6 +71,8 @@ namespace R3000A
|
||||||
namespace ioman
|
namespace ioman
|
||||||
{
|
{
|
||||||
void reset();
|
void reset();
|
||||||
|
bool is_host(const std::string_view path);
|
||||||
|
std::string host_path(const std::string_view path, bool allow_open_host_root);
|
||||||
}
|
}
|
||||||
} // namespace R3000A
|
} // namespace R3000A
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue