pm/cfg: simplify initial process id range logic

This commit is contained in:
Michael Scire 2021-10-01 17:37:39 -07:00
parent 18825866ac
commit 65fd967550
2 changed files with 30 additions and 56 deletions

View file

@ -19,66 +19,42 @@ namespace ams::cfg {
namespace { namespace {
/* Convenience definitions. */
constexpr os::ProcessId InitialProcessIdMinDeprecated = {0x00};
constexpr os::ProcessId InitialProcessIdMaxDeprecated = {0x50};
/* Privileged process globals. */
constinit os::SdkMutex g_lock; constinit os::SdkMutex g_lock;
constinit bool g_got_privileged_process_status = false; constinit bool g_got_privileged_process_status = false;
constinit os::ProcessId g_min_initial_process_id = os::InvalidProcessId, g_max_initial_process_id = os::InvalidProcessId; constinit os::ProcessId g_min_initial_process_id = os::InvalidProcessId, g_max_initial_process_id = os::InvalidProcessId;
constinit os::ProcessId g_cur_process_id = os::InvalidProcessId; constinit os::ProcessId g_cur_process_id = os::InvalidProcessId;
/* SD card helpers. */ ALWAYS_INLINE void EnsurePrivilegedProcessStatusCached() {
void GetPrivilegedProcessIdRange(os::ProcessId *out_min, os::ProcessId *out_max) { if (AMS_LIKELY(g_got_privileged_process_status)) {
os::ProcessId min = os::InvalidProcessId, max = os::InvalidProcessId; return;
if (hos::GetVersion() >= hos::Version_5_0_0) {
/* On 5.0.0+, we can get precise limits from svcGetSystemInfo. */
R_ABORT_UNLESS(svcGetSystemInfo(reinterpret_cast<u64 *>(&min), SystemInfoType_InitialProcessIdRange, INVALID_HANDLE, InitialProcessIdRangeInfo_Minimum));
R_ABORT_UNLESS(svcGetSystemInfo(reinterpret_cast<u64 *>(&max), SystemInfoType_InitialProcessIdRange, INVALID_HANDLE, InitialProcessIdRangeInfo_Maximum));
} else if (hos::GetVersion() >= hos::Version_4_0_0) {
/* On 4.0.0-4.1.0, we can get the precise limits from normal svcGetInfo. */
R_ABORT_UNLESS(svcGetInfo(reinterpret_cast<u64 *>(&min), InfoType_InitialProcessIdRange, INVALID_HANDLE, InitialProcessIdRangeInfo_Minimum));
R_ABORT_UNLESS(svcGetInfo(reinterpret_cast<u64 *>(&max), InfoType_InitialProcessIdRange, INVALID_HANDLE, InitialProcessIdRangeInfo_Maximum));
} else {
/* On < 4.0.0, we just use hardcoded extents. */
min = InitialProcessIdMinDeprecated;
max = InitialProcessIdMaxDeprecated;
} }
*out_min = min;
*out_max = max;
}
void GetPrivilegedProcessStatus() {
GetPrivilegedProcessIdRange(&g_min_initial_process_id, &g_max_initial_process_id);
g_cur_process_id = os::GetCurrentProcessId();
g_got_privileged_process_status = true;
}
}
/* Privileged Process utilities. */
bool IsInitialProcess() {
std::scoped_lock lk(g_lock); std::scoped_lock lk(g_lock);
/* If we've not detected, do detection. */ if (AMS_LIKELY(!g_got_privileged_process_status)) {
if (!g_got_privileged_process_status) { R_ABORT_UNLESS(svc::GetSystemInfo(std::addressof(g_min_initial_process_id.value), svc::SystemInfoType_InitialProcessIdRange, svc::InvalidHandle, svc::InitialProcessIdRangeInfo_Minimum));
GetPrivilegedProcessStatus(); R_ABORT_UNLESS(svc::GetSystemInfo(std::addressof(g_max_initial_process_id.value), svc::SystemInfoType_InitialProcessIdRange, svc::InvalidHandle, svc::InitialProcessIdRangeInfo_Maximum));
g_cur_process_id = os::GetCurrentProcessId();
g_got_privileged_process_status = true;
}
} }
/* Determine if we're privileged, and return. */ }
bool IsInitialProcess() {
/* Cache initial process range and extents. */
EnsurePrivilegedProcessStatusCached();
/* Determine if we're Initial. */
return g_min_initial_process_id <= g_cur_process_id && g_cur_process_id <= g_max_initial_process_id; return g_min_initial_process_id <= g_cur_process_id && g_cur_process_id <= g_max_initial_process_id;
} }
void GetInitialProcessRange(os::ProcessId *out_min, os::ProcessId *out_max) { void GetInitialProcessRange(os::ProcessId *out_min, os::ProcessId *out_max) {
std::scoped_lock lk(g_lock); /* Cache initial process range and extents. */
EnsurePrivilegedProcessStatusCached();
/* If we've not detected, do detection. */
if (!g_got_privileged_process_status) {
GetPrivilegedProcessStatus();
}
/* Set output. */
*out_min = g_min_initial_process_id; *out_min = g_min_initial_process_id;
*out_max = g_max_initial_process_id; *out_max = g_max_initial_process_id;
} }

View file

@ -71,21 +71,15 @@ namespace {
/* This uses debugging SVCs to retrieve a process's program id. */ /* This uses debugging SVCs to retrieve a process's program id. */
ncm::ProgramId GetProcessProgramId(os::ProcessId process_id) { ncm::ProgramId GetProcessProgramId(os::ProcessId process_id) {
/* Check if we should return our program id. */
/* Doing this here works around a bug fixed in 6.0.0. */
/* Not doing so will cause svcDebugActiveProcess to deadlock on lower firmwares if called for it's own process. */
if (process_id == os::GetCurrentProcessId()) {
return os::GetCurrentProgramId();
}
/* Get a debug handle. */ /* Get a debug handle. */
os::ManagedHandle debug_handle; svc::Handle debug_handle;
R_ABORT_UNLESS(svcDebugActiveProcess(debug_handle.GetPointer(), static_cast<u64>(process_id))); R_ABORT_UNLESS(svc::DebugActiveProcess(std::addressof(debug_handle), process_id.value));
ON_SCOPE_EXIT { R_ABORT_UNLESS(svc::CloseHandle(debug_handle)); };
/* Loop until we get the event that tells us about the process. */ /* Loop until we get the event that tells us about the process. */
svc::DebugEventInfo d; svc::DebugEventInfo d;
while (true) { while (true) {
R_ABORT_UNLESS(svcGetDebugEvent(reinterpret_cast<u8 *>(&d), debug_handle.Get())); R_ABORT_UNLESS(svc::GetDebugEvent(std::addressof(d), debug_handle));
if (d.type == svc::DebugEvent_CreateProcess) { if (d.type == svc::DebugEvent_CreateProcess) {
return ncm::ProgramId{d.info.create_process.program_id}; return ncm::ProgramId{d.info.create_process.program_id};
} }
@ -95,11 +89,11 @@ namespace {
/* This works around a bug fixed by FS in 4.0.0. */ /* This works around a bug fixed by FS in 4.0.0. */
/* Not doing so will cause KIPs with higher process IDs than 7 to be unable to use filesystem services. */ /* Not doing so will cause KIPs with higher process IDs than 7 to be unable to use filesystem services. */
/* It also registers privileged processes with SM, so that their program ids can be known. */ /* It also registers privileged processes with SM, so that their program ids can be known. */
void RegisterPrivilegedProcess(os::ProcessId process_id) { void RegisterPrivilegedProcess(os::ProcessId process_id, ncm::ProgramId program_id) {
fsprUnregisterProgram(static_cast<u64>(process_id)); fsprUnregisterProgram(process_id.value);
fsprRegisterProgram(static_cast<u64>(process_id), static_cast<u64>(process_id), NcmStorageId_BuiltInSystem, PrivilegedFileAccessHeader, sizeof(PrivilegedFileAccessHeader), PrivilegedFileAccessControl, sizeof(PrivilegedFileAccessControl)); fsprRegisterProgram(process_id.value, process_id.value, NcmStorageId_BuiltInSystem, PrivilegedFileAccessHeader, sizeof(PrivilegedFileAccessHeader), PrivilegedFileAccessControl, sizeof(PrivilegedFileAccessControl));
sm::manager::UnregisterProcess(process_id); sm::manager::UnregisterProcess(process_id);
sm::manager::RegisterProcess(process_id, GetProcessProgramId(process_id), cfg::OverrideStatus{}, PrivilegedServiceAccessControl, sizeof(PrivilegedServiceAccessControl), PrivilegedServiceAccessControl, sizeof(PrivilegedServiceAccessControl)); sm::manager::RegisterProcess(process_id, program_id, cfg::OverrideStatus{}, PrivilegedServiceAccessControl, sizeof(PrivilegedServiceAccessControl), PrivilegedServiceAccessControl, sizeof(PrivilegedServiceAccessControl));
} }
void RegisterPrivilegedProcesses() { void RegisterPrivilegedProcesses() {
@ -107,13 +101,17 @@ namespace {
os::ProcessId min_priv_process_id = os::InvalidProcessId, max_priv_process_id = os::InvalidProcessId; os::ProcessId min_priv_process_id = os::InvalidProcessId, max_priv_process_id = os::InvalidProcessId;
cfg::GetInitialProcessRange(&min_priv_process_id, &max_priv_process_id); cfg::GetInitialProcessRange(&min_priv_process_id, &max_priv_process_id);
/* Get current process id/program id. */
const auto cur_process_id = os::GetCurrentProcessId();
const auto cur_program_id = os::GetCurrentProgramId();
/* Get list of processes, register all privileged ones. */ /* Get list of processes, register all privileged ones. */
s32 num_pids; s32 num_pids;
os::ProcessId pids[ProcessCountMax]; os::ProcessId pids[ProcessCountMax];
R_ABORT_UNLESS(svc::GetProcessList(&num_pids, reinterpret_cast<u64 *>(pids), ProcessCountMax)); R_ABORT_UNLESS(svc::GetProcessList(&num_pids, reinterpret_cast<u64 *>(pids), ProcessCountMax));
for (s32 i = 0; i < num_pids; i++) { for (s32 i = 0; i < num_pids; i++) {
if (min_priv_process_id <= pids[i] && pids[i] <= max_priv_process_id) { if (min_priv_process_id <= pids[i] && pids[i] <= max_priv_process_id) {
RegisterPrivilegedProcess(pids[i]); RegisterPrivilegedProcess(pids[i], pids[i] == cur_process_id ? cur_program_id : GetProcessProgramId(pids[i]));
} }
} }
} }