Merge pull request #12266 from noahpistilli/kd-junk-data

IOS/KD: Disable download and mail when files are invalid
This commit is contained in:
Admiral H. Curtiss 2023-11-03 15:27:44 +01:00 committed by GitHub
commit 7dae4dd3d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 109 additions and 23 deletions

View File

@ -5,6 +5,8 @@
#include "Core/IOS/FS/FileSystem.h" #include "Core/IOS/FS/FileSystem.h"
#include "Core/IOS/Uids.h" #include "Core/IOS/Uids.h"
#include "Common/Assert.h"
namespace IOS::HLE::NWC24::Mail namespace IOS::HLE::NWC24::Mail
{ {
constexpr const char SEND_LIST_PATH[] = "/" WII_WC24CONF_DIR "/mbox" constexpr const char SEND_LIST_PATH[] = "/" WII_WC24CONF_DIR "/mbox"
@ -12,28 +14,47 @@ constexpr const char SEND_LIST_PATH[] = "/" WII_WC24CONF_DIR "/mbox"
WC24SendList::WC24SendList(std::shared_ptr<FS::FileSystem> fs) : m_fs{std::move(fs)} WC24SendList::WC24SendList(std::shared_ptr<FS::FileSystem> fs) : m_fs{std::move(fs)}
{ {
ReadSendList(); if (!ReadSendList())
{
ERROR_LOG_FMT(IOS_WC24, "There is an error in the Send List for WC24 mail. Mail will be "
"unavailable for this IOS session.");
m_is_disabled = true;
// If the Send list is corrupted, delete it.
const FS::ResultCode result = m_fs->Delete(PID_KD, PID_KD, SEND_LIST_PATH);
if (result != FS::ResultCode::Success && result != FS::ResultCode::NotFound)
{
ERROR_LOG_FMT(IOS_WC24, "Failed to delete the Send list.");
}
}
} }
void WC24SendList::ReadSendList() bool WC24SendList::ReadSendList()
{ {
const auto file = m_fs->OpenFile(PID_KD, PID_KD, SEND_LIST_PATH, FS::Mode::Read); const auto file = m_fs->OpenFile(PID_KD, PID_KD, SEND_LIST_PATH, FS::Mode::Read);
if (!file || !file->Read(&m_data, 1)) if (!file || !file->Read(&m_data, 1))
return; {
ERROR_LOG_FMT(IOS_WC24, "Failed to read the Send list");
return false;
}
if (file->GetStatus()->size != SEND_LIST_SIZE) if (file->GetStatus()->size != SEND_LIST_SIZE)
{ {
ERROR_LOG_FMT(IOS_WC24, "The WC24 Send list file is not the correct size."); ERROR_LOG_FMT(IOS_WC24, "The WC24 Send list file is not the correct size.");
return; return false;
} }
const s32 file_error = CheckSendList(); return CheckSendList();
if (!file_error) }
ERROR_LOG_FMT(IOS_WC24, "There is an error in the Send List for WC24 mail");
bool WC24SendList::IsDisabled() const
{
return m_is_disabled;
} }
void WC24SendList::WriteSendList() const void WC24SendList::WriteSendList() const
{ {
ASSERT(!IsDisabled());
constexpr FS::Modes public_modes{FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::ReadWrite}; constexpr FS::Modes public_modes{FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::ReadWrite};
m_fs->CreateFullPath(PID_KD, PID_KD, SEND_LIST_PATH, 0, public_modes); m_fs->CreateFullPath(PID_KD, PID_KD, SEND_LIST_PATH, 0, public_modes);
const auto file = m_fs->CreateAndOpenFile(PID_KD, PID_KD, SEND_LIST_PATH, public_modes); const auto file = m_fs->CreateAndOpenFile(PID_KD, PID_KD, SEND_LIST_PATH, public_modes);
@ -63,6 +84,7 @@ bool WC24SendList::CheckSendList() const
std::string_view WC24SendList::GetMailFlag() const std::string_view WC24SendList::GetMailFlag() const
{ {
ASSERT(!IsDisabled());
return {m_data.header.mail_flag.data(), m_data.header.mail_flag.size()}; return {m_data.header.mail_flag.data(), m_data.header.mail_flag.size()};
} }
} // namespace IOS::HLE::NWC24::Mail } // namespace IOS::HLE::NWC24::Mail

View File

@ -26,9 +26,10 @@ class WC24SendList final
public: public:
explicit WC24SendList(std::shared_ptr<FS::FileSystem> fs); explicit WC24SendList(std::shared_ptr<FS::FileSystem> fs);
void ReadSendList(); bool ReadSendList();
bool CheckSendList() const; bool CheckSendList() const;
void WriteSendList() const; void WriteSendList() const;
bool IsDisabled() const;
std::string_view GetMailFlag() const; std::string_view GetMailFlag() const;
@ -47,6 +48,7 @@ private:
SendList m_data; SendList m_data;
std::shared_ptr<FS::FileSystem> m_fs; std::shared_ptr<FS::FileSystem> m_fs;
bool m_is_disabled = false;
}; };
} // namespace NWC24::Mail } // namespace NWC24::Mail
} // namespace IOS::HLE } // namespace IOS::HLE

View File

@ -3,6 +3,7 @@
#include "Core/IOS/Network/KD/NWC24DL.h" #include "Core/IOS/Network/KD/NWC24DL.h"
#include "Common/Assert.h"
#include "Common/BitUtils.h" #include "Common/BitUtils.h"
#include "Common/CommonPaths.h" #include "Common/CommonPaths.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
@ -17,40 +18,65 @@ constexpr const char DL_LIST_PATH[] = "/" WII_WC24CONF_DIR "/nwc24dl.bin";
NWC24Dl::NWC24Dl(std::shared_ptr<FS::FileSystem> fs) : m_fs{std::move(fs)} NWC24Dl::NWC24Dl(std::shared_ptr<FS::FileSystem> fs) : m_fs{std::move(fs)}
{ {
ReadDlList(); if (!ReadDlList())
{
ERROR_LOG_FMT(IOS_WC24,
"There is an error in the DL list for WC24. WiiConnect24 downloading will be "
"unavailable for this current IOS session.");
m_is_disabled = true;
// If the DL list is corrupted, delete it.
// Dolphin should regenerate the file if it is missing, however this is after IOS is loaded
// meaning we will not have access to it.
const FS::ResultCode result = m_fs->Delete(PID_KD, PID_KD, DL_LIST_PATH);
// The file may not exist due to the fact that the Wii Menu reloads IOS twice, meaning
// the first load may have deleted the file.
if (result != FS::ResultCode::Success && result != FS::ResultCode::NotFound)
{
ERROR_LOG_FMT(IOS_WC24, "Failed to delete the DL list.");
}
}
} }
void NWC24Dl::ReadDlList() bool NWC24Dl::ReadDlList()
{ {
const auto file = m_fs->OpenFile(PID_KD, PID_KD, DL_LIST_PATH, FS::Mode::Read); const auto file = m_fs->OpenFile(PID_KD, PID_KD, DL_LIST_PATH, FS::Mode::Read);
if (!file || !file->Read(&m_data, 1)) if (!file || !file->Read(&m_data, 1))
return; {
ERROR_LOG_FMT(IOS_WC24, "Failed to read the DL list");
const s32 file_error = CheckNwc24DlList(); return false;
if (file_error)
ERROR_LOG_FMT(IOS_WC24, "There is an error in the DL list for WC24: {}", file_error);
} }
s32 NWC24Dl::CheckNwc24DlList() const return CheckNwc24DlList();
}
bool NWC24Dl::CheckNwc24DlList() const
{ {
// 'WcDl' magic // 'WcDl' magic
if (Magic() != DL_LIST_MAGIC) if (Magic() != DL_LIST_MAGIC)
{ {
ERROR_LOG_FMT(IOS_WC24, "DL list magic mismatch"); ERROR_LOG_FMT(IOS_WC24, "DL list magic mismatch");
return -1; return false;
} }
if (Version() != 1) if (Version() != 1)
{ {
ERROR_LOG_FMT(IOS_WC24, "DL list version mismatch"); ERROR_LOG_FMT(IOS_WC24, "DL list version mismatch");
return -1; return false;
} }
return 0; return true;
}
bool NWC24Dl::IsDisabled() const
{
return m_is_disabled;
} }
void NWC24Dl::WriteDlList() const void NWC24Dl::WriteDlList() const
{ {
ASSERT(!IsDisabled());
constexpr FS::Modes public_modes{FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::ReadWrite}; constexpr FS::Modes public_modes{FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::ReadWrite};
m_fs->CreateFullPath(PID_KD, PID_KD, DL_LIST_PATH, 0, public_modes); m_fs->CreateFullPath(PID_KD, PID_KD, DL_LIST_PATH, 0, public_modes);
const auto file = m_fs->CreateAndOpenFile(PID_KD, PID_KD, DL_LIST_PATH, public_modes); const auto file = m_fs->CreateAndOpenFile(PID_KD, PID_KD, DL_LIST_PATH, public_modes);
@ -61,11 +87,13 @@ void NWC24Dl::WriteDlList() const
bool NWC24Dl::DoesEntryExist(u16 entry_index) const bool NWC24Dl::DoesEntryExist(u16 entry_index) const
{ {
ASSERT(!IsDisabled());
return m_data.entries[entry_index].low_title_id != 0; return m_data.entries[entry_index].low_title_id != 0;
} }
std::string NWC24Dl::GetDownloadURL(u16 entry_index, std::optional<u8> subtask_id) const std::string NWC24Dl::GetDownloadURL(u16 entry_index, std::optional<u8> subtask_id) const
{ {
ASSERT(!IsDisabled());
std::string url(m_data.entries[entry_index].dl_url); std::string url(m_data.entries[entry_index].dl_url);
// Determine if we need to append the subtask to the URL. // Determine if we need to append the subtask to the URL.
@ -80,6 +108,7 @@ std::string NWC24Dl::GetDownloadURL(u16 entry_index, std::optional<u8> subtask_i
std::string NWC24Dl::GetVFFContentName(u16 entry_index, std::optional<u8> subtask_id) const std::string NWC24Dl::GetVFFContentName(u16 entry_index, std::optional<u8> subtask_id) const
{ {
ASSERT(!IsDisabled());
std::string content(m_data.entries[entry_index].filename); std::string content(m_data.entries[entry_index].filename);
// Determine if we need to append the subtask to the name. // Determine if we need to append the subtask to the name.
@ -94,6 +123,7 @@ std::string NWC24Dl::GetVFFContentName(u16 entry_index, std::optional<u8> subtas
std::string NWC24Dl::GetVFFPath(u16 entry_index) const std::string NWC24Dl::GetVFFPath(u16 entry_index) const
{ {
ASSERT(!IsDisabled());
const u32 lower_title_id = Common::swap32(m_data.entries[entry_index].low_title_id); const u32 lower_title_id = Common::swap32(m_data.entries[entry_index].low_title_id);
const u32 high_title_id = Common::swap32(m_data.entries[entry_index].high_title_id); const u32 high_title_id = Common::swap32(m_data.entries[entry_index].high_title_id);
@ -102,6 +132,7 @@ std::string NWC24Dl::GetVFFPath(u16 entry_index) const
std::optional<WC24PubkMod> NWC24Dl::GetWC24PubkMod(u16 entry_index) const std::optional<WC24PubkMod> NWC24Dl::GetWC24PubkMod(u16 entry_index) const
{ {
ASSERT(!IsDisabled());
WC24PubkMod pubk_mod; WC24PubkMod pubk_mod;
const u32 lower_title_id = Common::swap32(m_data.entries[entry_index].low_title_id); const u32 lower_title_id = Common::swap32(m_data.entries[entry_index].low_title_id);
const u32 high_title_id = Common::swap32(m_data.entries[entry_index].high_title_id); const u32 high_title_id = Common::swap32(m_data.entries[entry_index].high_title_id);
@ -121,22 +152,26 @@ std::optional<WC24PubkMod> NWC24Dl::GetWC24PubkMod(u16 entry_index) const
bool NWC24Dl::IsEncrypted(u16 entry_index) const bool NWC24Dl::IsEncrypted(u16 entry_index) const
{ {
ASSERT(!IsDisabled());
return !!Common::ExtractBit(Common::swap32(m_data.entries[entry_index].flags), 3); return !!Common::ExtractBit(Common::swap32(m_data.entries[entry_index].flags), 3);
} }
bool NWC24Dl::IsRSASigned(u16 entry_index) const bool NWC24Dl::IsRSASigned(u16 entry_index) const
{ {
ASSERT(!IsDisabled());
return !Common::ExtractBit(Common::swap32(m_data.entries[entry_index].flags), 2); return !Common::ExtractBit(Common::swap32(m_data.entries[entry_index].flags), 2);
} }
bool NWC24Dl::SkipSchedulerDownload(u16 entry_index) const bool NWC24Dl::SkipSchedulerDownload(u16 entry_index) const
{ {
ASSERT(!IsDisabled());
// Some entries can be set to not be downloaded by the scheduler. // Some entries can be set to not be downloaded by the scheduler.
return !!Common::ExtractBit(Common::swap32(m_data.entries[entry_index].flags), 5); return !!Common::ExtractBit(Common::swap32(m_data.entries[entry_index].flags), 5);
} }
bool NWC24Dl::HasSubtask(u16 entry_index) const bool NWC24Dl::HasSubtask(u16 entry_index) const
{ {
ASSERT(!IsDisabled());
switch (m_data.entries[entry_index].subtask_type) switch (m_data.entries[entry_index].subtask_type)
{ {
case 1: case 1:
@ -151,22 +186,26 @@ bool NWC24Dl::HasSubtask(u16 entry_index) const
bool NWC24Dl::IsSubtaskDownloadDisabled(u16 entry_index) const bool NWC24Dl::IsSubtaskDownloadDisabled(u16 entry_index) const
{ {
ASSERT(!IsDisabled());
return !!Common::ExtractBit(Common::swap16(m_data.entries[entry_index].subtask_flags), 9); return !!Common::ExtractBit(Common::swap16(m_data.entries[entry_index].subtask_flags), 9);
} }
bool NWC24Dl::IsValidSubtask(u16 entry_index, u8 subtask_id) const bool NWC24Dl::IsValidSubtask(u16 entry_index, u8 subtask_id) const
{ {
ASSERT(!IsDisabled());
return !!Common::ExtractBit(m_data.entries[entry_index].subtask_bitmask, subtask_id); return !!Common::ExtractBit(m_data.entries[entry_index].subtask_bitmask, subtask_id);
} }
u64 NWC24Dl::GetNextDownloadTime(u16 record_index) const u64 NWC24Dl::GetNextDownloadTime(u16 record_index) const
{ {
ASSERT(!IsDisabled());
// Timestamps are stored as a UNIX timestamp but in minutes. We want seconds. // Timestamps are stored as a UNIX timestamp but in minutes. We want seconds.
return Common::swap32(m_data.records[record_index].next_dl_timestamp) * SECONDS_PER_MINUTE; return Common::swap32(m_data.records[record_index].next_dl_timestamp) * SECONDS_PER_MINUTE;
} }
u64 NWC24Dl::GetRetryTime(u16 entry_index) const u64 NWC24Dl::GetRetryTime(u16 entry_index) const
{ {
ASSERT(!IsDisabled());
const u64 retry_time = Common::swap16(m_data.entries[entry_index].retry_frequency); const u64 retry_time = Common::swap16(m_data.entries[entry_index].retry_frequency);
if (retry_time == 0) if (retry_time == 0)
{ {
@ -177,11 +216,13 @@ u64 NWC24Dl::GetRetryTime(u16 entry_index) const
u64 NWC24Dl::GetDownloadMargin(u16 entry_index) const u64 NWC24Dl::GetDownloadMargin(u16 entry_index) const
{ {
ASSERT(!IsDisabled());
return Common::swap16(m_data.entries[entry_index].dl_margin) * SECONDS_PER_MINUTE; return Common::swap16(m_data.entries[entry_index].dl_margin) * SECONDS_PER_MINUTE;
} }
void NWC24Dl::SetNextDownloadTime(u16 record_index, u64 value, std::optional<u8> subtask_id) void NWC24Dl::SetNextDownloadTime(u16 record_index, u64 value, std::optional<u8> subtask_id)
{ {
ASSERT(!IsDisabled());
if (subtask_id) if (subtask_id)
{ {
m_data.entries[record_index].subtask_timestamps[*subtask_id] = m_data.entries[record_index].subtask_timestamps[*subtask_id] =
@ -194,6 +235,7 @@ void NWC24Dl::SetNextDownloadTime(u16 record_index, u64 value, std::optional<u8>
u64 NWC24Dl::GetLastSubtaskDownloadTime(u16 entry_index, u8 subtask_id) const u64 NWC24Dl::GetLastSubtaskDownloadTime(u16 entry_index, u8 subtask_id) const
{ {
ASSERT(!IsDisabled());
return Common::swap32(m_data.entries[entry_index].subtask_timestamps[subtask_id]) * return Common::swap32(m_data.entries[entry_index].subtask_timestamps[subtask_id]) *
SECONDS_PER_MINUTE + SECONDS_PER_MINUTE +
Common::swap32(m_data.entries[entry_index].server_dl_interval) * SECONDS_PER_MINUTE; Common::swap32(m_data.entries[entry_index].server_dl_interval) * SECONDS_PER_MINUTE;
@ -201,21 +243,25 @@ u64 NWC24Dl::GetLastSubtaskDownloadTime(u16 entry_index, u8 subtask_id) const
u32 NWC24Dl::Magic() const u32 NWC24Dl::Magic() const
{ {
ASSERT(!IsDisabled());
return Common::swap32(m_data.header.magic); return Common::swap32(m_data.header.magic);
} }
void NWC24Dl::SetMagic(u32 magic) void NWC24Dl::SetMagic(u32 magic)
{ {
ASSERT(!IsDisabled());
m_data.header.magic = Common::swap32(magic); m_data.header.magic = Common::swap32(magic);
} }
u32 NWC24Dl::Version() const u32 NWC24Dl::Version() const
{ {
ASSERT(!IsDisabled());
return Common::swap32(m_data.header.version); return Common::swap32(m_data.header.version);
} }
void NWC24Dl::SetVersion(u32 version) void NWC24Dl::SetVersion(u32 version)
{ {
ASSERT(!IsDisabled());
m_data.header.version = Common::swap32(version); m_data.header.version = Common::swap32(version);
} }
} // namespace IOS::HLE::NWC24 } // namespace IOS::HLE::NWC24

View File

@ -22,10 +22,11 @@ class NWC24Dl final
public: public:
explicit NWC24Dl(std::shared_ptr<FS::FileSystem> fs); explicit NWC24Dl(std::shared_ptr<FS::FileSystem> fs);
void ReadDlList(); bool ReadDlList();
void WriteDlList() const; void WriteDlList() const;
s32 CheckNwc24DlList() const; bool CheckNwc24DlList() const;
bool IsDisabled() const;
bool DoesEntryExist(u16 entry_index) const; bool DoesEntryExist(u16 entry_index) const;
bool IsEncrypted(u16 entry_index) const; bool IsEncrypted(u16 entry_index) const;
@ -130,6 +131,7 @@ private:
std::shared_ptr<FS::FileSystem> m_fs; std::shared_ptr<FS::FileSystem> m_fs;
DLList m_data; DLList m_data;
bool m_is_disabled = false;
}; };
} // namespace NWC24 } // namespace NWC24
} // namespace IOS::HLE } // namespace IOS::HLE

View File

@ -167,7 +167,7 @@ NetKDRequestDevice::NetKDRequestDevice(EmulationKernel& ios, const std::string&
} }
}); });
m_handle_mail = !ios.GetIOSC().IsUsingDefaultId(); m_handle_mail = !ios.GetIOSC().IsUsingDefaultId() && !m_send_list.IsDisabled();
m_scheduler_work_queue.Reset("WiiConnect24 Scheduler Worker", m_scheduler_work_queue.Reset("WiiConnect24 Scheduler Worker",
[](std::function<void()> task) { task(); }); [](std::function<void()> task) { task(); });
@ -220,7 +220,7 @@ void NetKDRequestDevice::SchedulerTimer()
mail_time_state = 0; mail_time_state = 0;
} }
if (m_download_span <= download_time_state) if (m_download_span <= download_time_state && !m_dl_list.IsDisabled())
{ {
INFO_LOG_FMT(IOS_WC24, "NET_KD_REQ: Dispatching Download Task from Scheduler"); INFO_LOG_FMT(IOS_WC24, "NET_KD_REQ: Dispatching Download Task from Scheduler");
m_scheduler_work_queue.EmplaceItem([this] { SchedulerWorker(SchedulerEvent::Download); }); m_scheduler_work_queue.EmplaceItem([this] { SchedulerWorker(SchedulerEvent::Download); });
@ -630,6 +630,13 @@ NWC24::ErrorCode NetKDRequestDevice::KDDownload(const u16 entry_index,
IPCReply NetKDRequestDevice::HandleNWC24CheckMailNow(const IOCtlRequest& request) IPCReply NetKDRequestDevice::HandleNWC24CheckMailNow(const IOCtlRequest& request)
{ {
if (!m_handle_mail)
{
LogError(ErrorType::CheckMail, NWC24::WC24_ERR_BROKEN);
WriteReturnValue(NWC24::WC24_ERR_BROKEN, request.buffer_out);
return IPCReply(IPC_SUCCESS);
}
auto& system = GetSystem(); auto& system = GetSystem();
auto& memory = system.GetMemory(); auto& memory = system.GetMemory();
@ -645,7 +652,14 @@ IPCReply NetKDRequestDevice::HandleNWC24CheckMailNow(const IOCtlRequest& request
IPCReply NetKDRequestDevice::HandleNWC24DownloadNowEx(const IOCtlRequest& request) IPCReply NetKDRequestDevice::HandleNWC24DownloadNowEx(const IOCtlRequest& request)
{ {
m_dl_list.ReadDlList(); if (m_dl_list.IsDisabled() || !m_dl_list.ReadDlList())
{
// Signal that the DL List is broken.
LogError(ErrorType::KD_Download, NWC24::WC24_ERR_BROKEN);
WriteReturnValue(NWC24::WC24_ERR_BROKEN, request.buffer_out);
return IPCReply(IPC_SUCCESS);
}
auto& system = GetSystem(); auto& system = GetSystem();
auto& memory = system.GetMemory(); auto& memory = system.GetMemory();
const u32 flags = memory.Read_U32(request.buffer_in); const u32 flags = memory.Read_U32(request.buffer_in);