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.
This commit is contained in:
Léo Lam 2017-04-23 12:38:16 +02:00
parent 8a559f2e58
commit dae950ff90
8 changed files with 86 additions and 18 deletions

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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)))

View File

@ -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;

View File

@ -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

View File

@ -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,

View File

@ -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();