From ad2044993dfd30ae1d4d24653fded6d47c1b5b1f Mon Sep 17 00:00:00 2001 From: Sketch <75850871+SketchMaster2001@users.noreply.github.com> Date: Thu, 2 Nov 2023 14:13:17 -0400 Subject: [PATCH] IOS/KD: Disable download and mail when files are invalid --- .../Core/IOS/Network/KD/Mail/WC24Send.cpp | 36 ++++++++-- .../Core/Core/IOS/Network/KD/Mail/WC24Send.h | 4 +- Source/Core/Core/IOS/Network/KD/NWC24DL.cpp | 66 ++++++++++++++++--- Source/Core/Core/IOS/Network/KD/NWC24DL.h | 6 +- .../Core/Core/IOS/Network/KD/NetKDRequest.cpp | 20 +++++- 5 files changed, 109 insertions(+), 23 deletions(-) diff --git a/Source/Core/Core/IOS/Network/KD/Mail/WC24Send.cpp b/Source/Core/Core/IOS/Network/KD/Mail/WC24Send.cpp index f889266ec6..faf4e6a14f 100644 --- a/Source/Core/Core/IOS/Network/KD/Mail/WC24Send.cpp +++ b/Source/Core/Core/IOS/Network/KD/Mail/WC24Send.cpp @@ -5,6 +5,8 @@ #include "Core/IOS/FS/FileSystem.h" #include "Core/IOS/Uids.h" +#include "Common/Assert.h" + namespace IOS::HLE::NWC24::Mail { 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) : 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); 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) { ERROR_LOG_FMT(IOS_WC24, "The WC24 Send list file is not the correct size."); - return; + return false; } - const s32 file_error = CheckSendList(); - if (!file_error) - ERROR_LOG_FMT(IOS_WC24, "There is an error in the Send List for WC24 mail"); + return CheckSendList(); +} + +bool WC24SendList::IsDisabled() const +{ + return m_is_disabled; } void WC24SendList::WriteSendList() const { + ASSERT(!IsDisabled()); 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); 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 { + ASSERT(!IsDisabled()); return {m_data.header.mail_flag.data(), m_data.header.mail_flag.size()}; } } // namespace IOS::HLE::NWC24::Mail diff --git a/Source/Core/Core/IOS/Network/KD/Mail/WC24Send.h b/Source/Core/Core/IOS/Network/KD/Mail/WC24Send.h index 9f4e0399b1..220492cd31 100644 --- a/Source/Core/Core/IOS/Network/KD/Mail/WC24Send.h +++ b/Source/Core/Core/IOS/Network/KD/Mail/WC24Send.h @@ -26,9 +26,10 @@ class WC24SendList final public: explicit WC24SendList(std::shared_ptr fs); - void ReadSendList(); + bool ReadSendList(); bool CheckSendList() const; void WriteSendList() const; + bool IsDisabled() const; std::string_view GetMailFlag() const; @@ -47,6 +48,7 @@ private: SendList m_data; std::shared_ptr m_fs; + bool m_is_disabled = false; }; } // namespace NWC24::Mail } // namespace IOS::HLE diff --git a/Source/Core/Core/IOS/Network/KD/NWC24DL.cpp b/Source/Core/Core/IOS/Network/KD/NWC24DL.cpp index 58776828e6..5f1fb41021 100644 --- a/Source/Core/Core/IOS/Network/KD/NWC24DL.cpp +++ b/Source/Core/Core/IOS/Network/KD/NWC24DL.cpp @@ -3,6 +3,7 @@ #include "Core/IOS/Network/KD/NWC24DL.h" +#include "Common/Assert.h" #include "Common/BitUtils.h" #include "Common/CommonPaths.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) : 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); if (!file || !file->Read(&m_data, 1)) - return; + { + ERROR_LOG_FMT(IOS_WC24, "Failed to read the DL list"); + return false; + } - const s32 file_error = CheckNwc24DlList(); - if (file_error) - ERROR_LOG_FMT(IOS_WC24, "There is an error in the DL list for WC24: {}", file_error); + return CheckNwc24DlList(); } -s32 NWC24Dl::CheckNwc24DlList() const +bool NWC24Dl::CheckNwc24DlList() const { // 'WcDl' magic if (Magic() != DL_LIST_MAGIC) { ERROR_LOG_FMT(IOS_WC24, "DL list magic mismatch"); - return -1; + return false; } if (Version() != 1) { 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 { + ASSERT(!IsDisabled()); 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); 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 { + ASSERT(!IsDisabled()); return m_data.entries[entry_index].low_title_id != 0; } std::string NWC24Dl::GetDownloadURL(u16 entry_index, std::optional subtask_id) const { + ASSERT(!IsDisabled()); std::string url(m_data.entries[entry_index].dl_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 subtask_i std::string NWC24Dl::GetVFFContentName(u16 entry_index, std::optional subtask_id) const { + ASSERT(!IsDisabled()); std::string content(m_data.entries[entry_index].filename); // Determine if we need to append the subtask to the name. @@ -94,6 +123,7 @@ std::string NWC24Dl::GetVFFContentName(u16 entry_index, std::optional subtas 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 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 NWC24Dl::GetWC24PubkMod(u16 entry_index) const { + ASSERT(!IsDisabled()); WC24PubkMod pubk_mod; 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); @@ -121,22 +152,26 @@ std::optional NWC24Dl::GetWC24PubkMod(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); } bool NWC24Dl::IsRSASigned(u16 entry_index) const { + ASSERT(!IsDisabled()); return !Common::ExtractBit(Common::swap32(m_data.entries[entry_index].flags), 2); } bool NWC24Dl::SkipSchedulerDownload(u16 entry_index) const { + ASSERT(!IsDisabled()); // Some entries can be set to not be downloaded by the scheduler. return !!Common::ExtractBit(Common::swap32(m_data.entries[entry_index].flags), 5); } bool NWC24Dl::HasSubtask(u16 entry_index) const { + ASSERT(!IsDisabled()); switch (m_data.entries[entry_index].subtask_type) { case 1: @@ -151,22 +186,26 @@ bool NWC24Dl::HasSubtask(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); } bool NWC24Dl::IsValidSubtask(u16 entry_index, u8 subtask_id) const { + ASSERT(!IsDisabled()); return !!Common::ExtractBit(m_data.entries[entry_index].subtask_bitmask, subtask_id); } u64 NWC24Dl::GetNextDownloadTime(u16 record_index) const { + ASSERT(!IsDisabled()); // 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; } u64 NWC24Dl::GetRetryTime(u16 entry_index) const { + ASSERT(!IsDisabled()); const u64 retry_time = Common::swap16(m_data.entries[entry_index].retry_frequency); if (retry_time == 0) { @@ -177,11 +216,13 @@ u64 NWC24Dl::GetRetryTime(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; } void NWC24Dl::SetNextDownloadTime(u16 record_index, u64 value, std::optional subtask_id) { + ASSERT(!IsDisabled()); if (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 u64 NWC24Dl::GetLastSubtaskDownloadTime(u16 entry_index, u8 subtask_id) const { + ASSERT(!IsDisabled()); return Common::swap32(m_data.entries[entry_index].subtask_timestamps[subtask_id]) * 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 { + ASSERT(!IsDisabled()); return Common::swap32(m_data.header.magic); } void NWC24Dl::SetMagic(u32 magic) { + ASSERT(!IsDisabled()); m_data.header.magic = Common::swap32(magic); } u32 NWC24Dl::Version() const { + ASSERT(!IsDisabled()); return Common::swap32(m_data.header.version); } void NWC24Dl::SetVersion(u32 version) { + ASSERT(!IsDisabled()); m_data.header.version = Common::swap32(version); } } // namespace IOS::HLE::NWC24 diff --git a/Source/Core/Core/IOS/Network/KD/NWC24DL.h b/Source/Core/Core/IOS/Network/KD/NWC24DL.h index 6f5a05adae..4b875e57ac 100644 --- a/Source/Core/Core/IOS/Network/KD/NWC24DL.h +++ b/Source/Core/Core/IOS/Network/KD/NWC24DL.h @@ -22,10 +22,11 @@ class NWC24Dl final public: explicit NWC24Dl(std::shared_ptr fs); - void ReadDlList(); + bool ReadDlList(); void WriteDlList() const; - s32 CheckNwc24DlList() const; + bool CheckNwc24DlList() const; + bool IsDisabled() const; bool DoesEntryExist(u16 entry_index) const; bool IsEncrypted(u16 entry_index) const; @@ -130,6 +131,7 @@ private: std::shared_ptr m_fs; DLList m_data; + bool m_is_disabled = false; }; } // namespace NWC24 } // namespace IOS::HLE diff --git a/Source/Core/Core/IOS/Network/KD/NetKDRequest.cpp b/Source/Core/Core/IOS/Network/KD/NetKDRequest.cpp index 7e8ab1d53b..7436942b85 100644 --- a/Source/Core/Core/IOS/Network/KD/NetKDRequest.cpp +++ b/Source/Core/Core/IOS/Network/KD/NetKDRequest.cpp @@ -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", [](std::function task) { task(); }); @@ -220,7 +220,7 @@ void NetKDRequestDevice::SchedulerTimer() 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"); 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) { + 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& memory = system.GetMemory(); @@ -645,7 +652,14 @@ IPCReply NetKDRequestDevice::HandleNWC24CheckMailNow(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& memory = system.GetMemory(); const u32 flags = memory.Read_U32(request.buffer_in);