Merge pull request #4447 from JosJuice/hthh-hle-issues
Fix exploitable HLE problems reported by hthh
This commit is contained in:
commit
9bfea4a0f2
|
@ -5,6 +5,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
@ -30,7 +31,6 @@
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -712,6 +712,19 @@ std::string GetBundleDirectory()
|
||||||
}
|
}
|
||||||
#endif
|
#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()
|
std::string& GetExeDirectory()
|
||||||
{
|
{
|
||||||
static std::string DolphinPath;
|
static std::string DolphinPath;
|
||||||
|
|
|
@ -133,6 +133,10 @@ std::string CreateTempDir();
|
||||||
// Get a filename that can hopefully be atomically renamed to the given path.
|
// Get a filename that can hopefully be atomically renamed to the given path.
|
||||||
std::string GetTempFilenameForAtomicWrite(const std::string& 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
|
// Gets a set user directory path
|
||||||
// Don't call prior to setting the base user directory
|
// Don't call prior to setting the base user directory
|
||||||
const std::string& GetUserPath(unsigned int dir_index);
|
const std::string& GetUserPath(unsigned int dir_index);
|
||||||
|
|
|
@ -87,8 +87,14 @@ std::string GetStringVA(u32 strReg)
|
||||||
result += '%';
|
result += '%';
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
while (string[i] < 'A' || string[i] > 'z' || string[i] == 'l' || string[i] == '-')
|
|
||||||
|
while (i < string.size() &&
|
||||||
|
(string[i] < 'A' || string[i] > 'z' || string[i] == 'l' || string[i] == '-'))
|
||||||
|
{
|
||||||
ArgumentBuffer += string[i++];
|
ArgumentBuffer += string[i++];
|
||||||
|
}
|
||||||
|
if (i >= string.size())
|
||||||
|
break;
|
||||||
|
|
||||||
ArgumentBuffer += string[i];
|
ArgumentBuffer += string[i];
|
||||||
|
|
||||||
|
@ -137,6 +143,11 @@ std::string GetStringVA(u32 strReg)
|
||||||
result += StringFromFormat("%x", (u32)Parameter);
|
result += StringFromFormat("%x", (u32)Parameter);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'n':
|
||||||
|
PowerPC::HostWrite_U32(static_cast<u32>(result.size()), static_cast<u32>(Parameter));
|
||||||
|
// %n doesn't output anything, so the result variable is untouched
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
result += StringFromFormat(ArgumentBuffer.c_str(), Parameter);
|
result += StringFromFormat(ArgumentBuffer.c_str(), Parameter);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
#include "Common/CommonPaths.h"
|
#include "Common/CommonPaths.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/FileUtil.h"
|
#include "Common/FileUtil.h"
|
||||||
|
#include "Common/Logging/Log.h"
|
||||||
|
#include "Common/MsgHandler.h"
|
||||||
#include "Common/NandPaths.h"
|
#include "Common/NandPaths.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
|
|
||||||
|
@ -23,8 +25,6 @@ static std::map<std::string, std::weak_ptr<File::IOFile>> openFiles;
|
||||||
// This is used by several of the FileIO and /dev/fs functions
|
// This is used by several of the FileIO and /dev/fs functions
|
||||||
std::string HLE_IPC_BuildFilename(std::string path_wii)
|
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
|
// Replaces chars that FAT32 can't support with strings defined in /sys/replace
|
||||||
for (auto& replacement : replacements)
|
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_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()
|
void HLE_IPC_CreateVirtualFATFilesystem()
|
||||||
|
|
|
@ -2,7 +2,9 @@
|
||||||
// Licensed under GPLv2+
|
// Licensed under GPLv2+
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
|
#include <cstddef>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -14,6 +16,7 @@
|
||||||
|
|
||||||
#include "Common/CommonPaths.h"
|
#include "Common/CommonPaths.h"
|
||||||
#include "Common/FileUtil.h"
|
#include "Common/FileUtil.h"
|
||||||
|
#include "Common/Logging/Log.h"
|
||||||
#include "Common/NandPaths.h"
|
#include "Common/NandPaths.h"
|
||||||
#include "Common/Network.h"
|
#include "Common/Network.h"
|
||||||
#include "Common/SettingsHandler.h"
|
#include "Common/SettingsHandler.h"
|
||||||
|
@ -848,9 +851,16 @@ IPCCommandResult CWII_IPC_HLE_Device_net_ip_top::IOCtl(u32 _CommandAddress)
|
||||||
sa_len = sizeof(sa);
|
sa_len = sizeof(sa);
|
||||||
int ret = getsockname(fd, &sa, &sa_len);
|
int ret = getsockname(fd, &sa, &sa_len);
|
||||||
|
|
||||||
Memory::Write_U8(BufferOutSize, BufferOut);
|
if (BufferOutSize < 2 + sizeof(sa.sa_data))
|
||||||
Memory::Write_U8(sa.sa_family & 0xFF, BufferOut + 1);
|
WARN_LOG(WII_IPC_NET, "IOCTL_SO_GETSOCKNAME output buffer is too small. Truncating");
|
||||||
Memory::CopyToEmu(BufferOut + 2, &sa.sa_data, BufferOutSize - 2);
|
|
||||||
|
if (BufferOutSize > 0)
|
||||||
|
Memory::Write_U8(BufferOutSize, BufferOut);
|
||||||
|
if (BufferOutSize > 1)
|
||||||
|
Memory::Write_U8(sa.sa_family & 0xFF, BufferOut + 1);
|
||||||
|
if (BufferOutSize > 2)
|
||||||
|
Memory::CopyToEmu(BufferOut + 2, &sa.sa_data,
|
||||||
|
std::min<size_t>(sizeof(sa.sa_data), BufferOutSize - 2));
|
||||||
ReturnValue = ret;
|
ReturnValue = ret;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -864,9 +874,16 @@ IPCCommandResult CWII_IPC_HLE_Device_net_ip_top::IOCtl(u32 _CommandAddress)
|
||||||
|
|
||||||
int ret = getpeername(fd, &sa, &sa_len);
|
int ret = getpeername(fd, &sa, &sa_len);
|
||||||
|
|
||||||
Memory::Write_U8(BufferOutSize, BufferOut);
|
if (BufferOutSize < 2 + sizeof(sa.sa_data))
|
||||||
Memory::Write_U8(AF_INET, BufferOut + 1);
|
WARN_LOG(WII_IPC_NET, "IOCTL_SO_GETPEERNAME output buffer is too small. Truncating");
|
||||||
Memory::CopyToEmu(BufferOut + 2, &sa.sa_data, BufferOutSize - 2);
|
|
||||||
|
if (BufferOutSize > 0)
|
||||||
|
Memory::Write_U8(BufferOutSize, BufferOut);
|
||||||
|
if (BufferOutSize > 1)
|
||||||
|
Memory::Write_U8(AF_INET, BufferOut + 1);
|
||||||
|
if (BufferOutSize > 2)
|
||||||
|
Memory::CopyToEmu(BufferOut + 2, &sa.sa_data,
|
||||||
|
std::min<size_t>(sizeof(sa.sa_data), BufferOutSize - 2));
|
||||||
|
|
||||||
INFO_LOG(WII_IPC_NET, "IOCTL_SO_GETPEERNAME(%x)", fd);
|
INFO_LOG(WII_IPC_NET, "IOCTL_SO_GETPEERNAME(%x)", fd);
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ void CWII_IPC_HLE_Device_sdio_slot0::DoState(PointerWrap& p)
|
||||||
p.Do(m_Status);
|
p.Do(m_Status);
|
||||||
p.Do(m_BlockLength);
|
p.Do(m_BlockLength);
|
||||||
p.Do(m_BusWidth);
|
p.Do(m_BusWidth);
|
||||||
p.Do(m_Registers);
|
p.Do(m_registers);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWII_IPC_HLE_Device_sdio_slot0::EventNotify()
|
void CWII_IPC_HLE_Device_sdio_slot0::EventNotify()
|
||||||
|
@ -87,7 +87,7 @@ IPCCommandResult CWII_IPC_HLE_Device_sdio_slot0::Open(u32 _CommandAddress, u32 _
|
||||||
OpenInternal();
|
OpenInternal();
|
||||||
|
|
||||||
Memory::Write_U32(GetDeviceID(), _CommandAddress + 0x4);
|
Memory::Write_U32(GetDeviceID(), _CommandAddress + 0x4);
|
||||||
memset(m_Registers, 0, sizeof(m_Registers));
|
m_registers.fill(0);
|
||||||
m_Active = true;
|
m_Active = true;
|
||||||
return GetDefaultReply();
|
return GetDefaultReply();
|
||||||
}
|
}
|
||||||
|
@ -130,7 +130,7 @@ IPCCommandResult CWII_IPC_HLE_Device_sdio_slot0::IOCtl(u32 _CommandAddress)
|
||||||
|
|
||||||
INFO_LOG(WII_IPC_SD, "IOCTL_WRITEHCR 0x%08x - 0x%08x", reg, val);
|
INFO_LOG(WII_IPC_SD, "IOCTL_WRITEHCR 0x%08x - 0x%08x", reg, val);
|
||||||
|
|
||||||
if (reg >= 0x200)
|
if (reg >= m_registers.size())
|
||||||
{
|
{
|
||||||
WARN_LOG(WII_IPC_SD, "IOCTL_WRITEHCR out of range");
|
WARN_LOG(WII_IPC_SD, "IOCTL_WRITEHCR out of range");
|
||||||
break;
|
break;
|
||||||
|
@ -139,17 +139,17 @@ IPCCommandResult CWII_IPC_HLE_Device_sdio_slot0::IOCtl(u32 _CommandAddress)
|
||||||
if ((reg == HCR_CLOCKCONTROL) && (val & 1))
|
if ((reg == HCR_CLOCKCONTROL) && (val & 1))
|
||||||
{
|
{
|
||||||
// Clock is set to oscillate, enable bit 1 to say it's stable
|
// Clock is set to oscillate, enable bit 1 to say it's stable
|
||||||
m_Registers[reg] = val | 2;
|
m_registers[reg] = val | 2;
|
||||||
}
|
}
|
||||||
else if ((reg == HCR_SOFTWARERESET) && val)
|
else if ((reg == HCR_SOFTWARERESET) && val)
|
||||||
{
|
{
|
||||||
// When a reset is specified, the register gets cleared
|
// When a reset is specified, the register gets cleared
|
||||||
m_Registers[reg] = 0;
|
m_registers[reg] = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Default to just storing the new value
|
// Default to just storing the new value
|
||||||
m_Registers[reg] = val;
|
m_registers[reg] = val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -158,13 +158,13 @@ IPCCommandResult CWII_IPC_HLE_Device_sdio_slot0::IOCtl(u32 _CommandAddress)
|
||||||
{
|
{
|
||||||
u32 reg = Memory::Read_U32(BufferIn);
|
u32 reg = Memory::Read_U32(BufferIn);
|
||||||
|
|
||||||
if (reg >= 0x200)
|
if (reg >= m_registers.size())
|
||||||
{
|
{
|
||||||
WARN_LOG(WII_IPC_SD, "IOCTL_READHCR out of range");
|
WARN_LOG(WII_IPC_SD, "IOCTL_READHCR out of range");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 val = m_Registers[reg];
|
u32 val = m_registers[reg];
|
||||||
INFO_LOG(WII_IPC_SD, "IOCTL_READHCR 0x%08x - 0x%08x", reg, val);
|
INFO_LOG(WII_IPC_SD, "IOCTL_READHCR 0x%08x - 0x%08x", reg, val);
|
||||||
|
|
||||||
// Just reading the register
|
// Just reading the register
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "Core/IPC_HLE/WII_IPC_HLE_Device.h"
|
#include "Core/IPC_HLE/WII_IPC_HLE_Device.h"
|
||||||
|
|
||||||
|
@ -119,7 +120,7 @@ private:
|
||||||
u32 m_BlockLength;
|
u32 m_BlockLength;
|
||||||
u32 m_BusWidth;
|
u32 m_BusWidth;
|
||||||
|
|
||||||
u32 m_Registers[0x200 / 4];
|
std::array<u32, 0x200 / sizeof(u32)> m_registers;
|
||||||
|
|
||||||
File::IOFile m_Card;
|
File::IOFile m_Card;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue