From dae950ff90e16d6b618874af2b8b455e58bb95c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 23 Apr 2017 12:38:16 +0200 Subject: [PATCH] IOS: Implement UID/GID changes for the PPC This will be required for permission checks in the future. Note that this is only for the PPC as we do not have actual processes. Keeping track of other modules' UIDs/GIDs is virtually useless anyway. UID/GID changes are implemented in the following functions: * ES_Launch * ES_DIVerify ES_SetUid is not implemented yet because it'd need further changes. --- Source/Core/Core/IOS/ES/ES.cpp | 37 +++++++++++++++++++++--- Source/Core/Core/IOS/ES/Formats.cpp | 25 ++++++++++------ Source/Core/Core/IOS/ES/Formats.h | 4 +-- Source/Core/Core/IOS/ES/NandUtils.cpp | 2 +- Source/Core/Core/IOS/IPC.cpp | 27 +++++++++++++++++ Source/Core/Core/IOS/IPC.h | 5 ++++ Source/Core/Core/State.cpp | 2 +- Source/Core/DiscIO/NANDContentLoader.cpp | 2 +- 8 files changed, 86 insertions(+), 18 deletions(-) diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp index a8d72b96a8..ef3864bcf8 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -158,6 +158,21 @@ IPCCommandResult ES::GetTitleID(const IOCtlVRequest& request) return GetDefaultReply(IPC_SUCCESS); } +static bool UpdateUIDAndGID(const IOS::ES::TMDReader& tmd) +{ + IOS::ES::UIDSys uid_sys{Common::FromWhichRoot::FROM_SESSION_ROOT}; + const u64 title_id = tmd.GetTitleId(); + const u32 uid = uid_sys.GetOrInsertUIDForTitle(title_id); + if (!uid) + { + ERROR_LOG(IOS_ES, "Failed to get UID for title %016" PRIx64, title_id); + return false; + } + SetUIDForPPC(uid); + SetGIDForPPC(tmd.GetGroupId()); + return true; +} + IPCCommandResult ES::SetUID(const IOCtlVRequest& request) { if (!request.HasNumberOfValidVectors(1, 0)) @@ -226,6 +241,16 @@ bool ES::LaunchPPCTitle(u64 title_id, bool skip_reload) s_title_context.Update(content_loader); INFO_LOG(IOS_ES, "LaunchPPCTitle: Title context changed: %016" PRIx64, s_title_context.tmd.GetTitleId()); + + // Note: the UID/GID is also updated for IOS titles, but since we have no guarantee IOS titles + // are installed, we can only do this for PPC titles. + if (!UpdateUIDAndGID(s_title_context.tmd)) + { + s_title_context.Clear(); + INFO_LOG(IOS_ES, "LaunchPPCTitle: Title context changed: (none)"); + return false; + } + return BootstrapPPC(content_loader); } @@ -533,6 +558,9 @@ s32 ES::DIVerify(const IOS::ES::TMDReader& tmd, const IOS::ES::TicketReader& tic if (tmd.GetTitleId() != ticket.GetTitleId()) return ES_EINVAL; + s_title_context.Update(tmd, ticket); + INFO_LOG(IOS_ES, "ES_DIVerify: Title context changed: %016" PRIx64, tmd.GetTitleId()); + std::string tmd_path = Common::GetTMDFileName(tmd.GetTitleId(), Common::FROM_SESSION_ROOT); File::CreateFullPath(tmd_path); @@ -545,14 +573,15 @@ s32 ES::DIVerify(const IOS::ES::TMDReader& tmd, const IOS::ES::TicketReader& tic if (!tmd_file.WriteBytes(tmd_bytes.data(), tmd_bytes.size())) ERROR_LOG(IOS_ES, "DIVerify failed to write disc TMD to NAND."); } - IOS::ES::UIDSys uid_sys{Common::FromWhichRoot::FROM_SESSION_ROOT}; - uid_sys.AddTitle(tmd.GetTitleId()); // DI_VERIFY writes to title.tmd, which is read and cached inside the NAND Content Manager. // clear the cache to avoid content access mismatches. DiscIO::CNANDContentManager::Access().ClearCache(); - s_title_context.Update(tmd, ticket); - INFO_LOG(IOS_ES, "ES_DIVerify: Title context changed: %016" PRIx64, tmd.GetTitleId()); + if (!UpdateUIDAndGID(s_title_context.tmd)) + { + return ES_SHORT_READ; + } + return IPC_SUCCESS; } } // namespace Device diff --git a/Source/Core/Core/IOS/ES/Formats.cpp b/Source/Core/Core/IOS/ES/Formats.cpp index e4da96e2d0..d57bffb460 100644 --- a/Source/Core/Core/IOS/ES/Formats.cpp +++ b/Source/Core/Core/IOS/ES/Formats.cpp @@ -446,11 +446,11 @@ UIDSys::UIDSys(Common::FromWhichRoot root) if (m_entries.empty()) { - AddTitle(TITLEID_SYSMENU); + GetOrInsertUIDForTitle(TITLEID_SYSMENU); } } -u32 UIDSys::GetUIDFromTitle(u64 title_id) +u32 UIDSys::GetUIDFromTitle(u64 title_id) const { const auto it = std::find_if(m_entries.begin(), m_entries.end(), [title_id](const auto& entry) { return entry.second == title_id; }); @@ -464,26 +464,33 @@ u32 UIDSys::GetNextUID() const return m_entries.rbegin()->first + 1; } -void UIDSys::AddTitle(u64 title_id) +u32 UIDSys::GetOrInsertUIDForTitle(const u64 title_id) { - if (GetUIDFromTitle(title_id)) + const u32 current_uid = GetUIDFromTitle(title_id); + if (current_uid) { INFO_LOG(IOS_ES, "Title %016" PRIx64 " already exists in uid.sys", title_id); - return; + return current_uid; } - u32 uid = GetNextUID(); + const u32 uid = GetNextUID(); m_entries.insert({uid, title_id}); // Byte swap before writing. - title_id = Common::swap64(title_id); - uid = Common::swap32(uid); + const u64 swapped_title_id = Common::swap64(title_id); + const u32 swapped_uid = Common::swap32(uid); File::CreateFullPath(m_file_path); File::IOFile file(m_file_path, "ab"); - if (!file.WriteBytes(&title_id, sizeof(title_id)) || !file.WriteBytes(&uid, sizeof(uid))) + if (!file.WriteBytes(&swapped_title_id, sizeof(title_id)) || + !file.WriteBytes(&swapped_uid, sizeof(uid))) + { ERROR_LOG(IOS_ES, "Failed to write to /sys/uid.sys"); + return 0; + } + + return uid; } } // namespace ES } // namespace IOS diff --git a/Source/Core/Core/IOS/ES/Formats.h b/Source/Core/Core/IOS/ES/Formats.h index d073544ad1..691babdc9b 100644 --- a/Source/Core/Core/IOS/ES/Formats.h +++ b/Source/Core/Core/IOS/ES/Formats.h @@ -219,8 +219,8 @@ class UIDSys final public: explicit UIDSys(Common::FromWhichRoot root); - u32 GetUIDFromTitle(u64 title_id); - void AddTitle(u64 title_id); + u32 GetUIDFromTitle(u64 title_id) const; + u32 GetOrInsertUIDForTitle(u64 title_id); u32 GetNextUID() const; private: diff --git a/Source/Core/Core/IOS/ES/NandUtils.cpp b/Source/Core/Core/IOS/ES/NandUtils.cpp index 7d60f5c5e6..fd586010e5 100644 --- a/Source/Core/Core/IOS/ES/NandUtils.cpp +++ b/Source/Core/Core/IOS/ES/NandUtils.cpp @@ -194,7 +194,7 @@ bool InitImport(u64 title_id) } UIDSys uid_sys{Common::FROM_CONFIGURED_ROOT}; - uid_sys.AddTitle(title_id); + uid_sys.GetOrInsertUIDForTitle(title_id); // IOS moves the title content directory to /import if the TMD exists during an import. if (File::Exists(Common::GetTMDFileName(title_id, Common::FROM_SESSION_ROOT))) diff --git a/Source/Core/Core/IOS/IPC.cpp b/Source/Core/Core/IOS/IPC.cpp index bfbcf7c4b6..00d20877f9 100644 --- a/Source/Core/Core/IOS/IPC.cpp +++ b/Source/Core/Core/IOS/IPC.cpp @@ -91,6 +91,9 @@ static u64 s_last_reply_time; static u64 s_active_title_id; +static u32 s_ppc_uid; +static u16 s_ppc_gid; + static constexpr u64 ENQUEUE_REQUEST_FLAG = 0x100000000ULL; static constexpr u64 ENQUEUE_ACKNOWLEDGEMENT_FLAG = 0x200000000ULL; @@ -702,6 +705,28 @@ bool Reload(const u64 ios_title_id) return true; } +// Since we don't have actual processes, we keep track of only the PPC's UID/GID. +// These functions roughly correspond to syscalls 0x2b, 0x2c, 0x2d, 0x2e (though only for the PPC). +void SetUIDForPPC(u32 uid) +{ + s_ppc_uid = uid; +} + +u32 GetUIDForPPC() +{ + return s_ppc_uid; +} + +void SetGIDForPPC(u16 gid) +{ + s_ppc_gid = gid; +} + +u16 GetGIDForPPC() +{ + return s_ppc_gid; +} + // This corresponds to syscall 0x41, which loads a binary from the NAND and bootstraps the PPC. // Unlike 0x42, IOS will set up some constants in memory before booting the PPC. bool BootstrapPPC(const DiscIO::CNANDContentLoader& content_loader) @@ -783,6 +808,8 @@ void DoState(PointerWrap& p) p.Do(s_reply_queue); p.Do(s_last_reply_time); p.Do(s_active_title_id); + p.Do(s_ppc_uid); + p.Do(s_ppc_gid); if (s_active_title_id == MIOS_TITLE_ID) return; diff --git a/Source/Core/Core/IOS/IPC.h b/Source/Core/Core/IOS/IPC.h index e35608de0c..0d9e93ad70 100644 --- a/Source/Core/Core/IOS/IPC.h +++ b/Source/Core/Core/IOS/IPC.h @@ -59,6 +59,11 @@ void Shutdown(); bool Reload(u64 ios_title_id); u32 GetVersion(); +void SetUIDForPPC(u32 uid); +u32 GetUIDForPPC(); +void SetGIDForPPC(u16 gid); +u16 GetGIDForPPC(); + bool BootstrapPPC(const DiscIO::CNANDContentLoader& content_loader); // Do State diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index 28d41b5961..1d1f92cd2f 100644 --- a/Source/Core/Core/State.cpp +++ b/Source/Core/Core/State.cpp @@ -71,7 +71,7 @@ static Common::Event g_compressAndDumpStateSyncEvent; static std::thread g_save_thread; // Don't forget to increase this after doing changes on the savestate system -static const u32 STATE_VERSION = 79; // Last changed in PR 4981 +static const u32 STATE_VERSION = 80; // Last changed in PR 5309 // Maps savestate versions to Dolphin versions. // Versions after 42 don't need to be added to this list, diff --git a/Source/Core/DiscIO/NANDContentLoader.cpp b/Source/Core/DiscIO/NANDContentLoader.cpp index 58594d6fc5..79242d1307 100644 --- a/Source/Core/DiscIO/NANDContentLoader.cpp +++ b/Source/Core/DiscIO/NANDContentLoader.cpp @@ -336,7 +336,7 @@ u64 CNANDContentManager::Install_WiiWAD(const std::string& filename) } IOS::ES::UIDSys uid_sys{Common::FromWhichRoot::FROM_CONFIGURED_ROOT}; - uid_sys.AddTitle(title_id); + uid_sys.GetOrInsertUIDForTitle(title_id); ClearCache();