From 8e8daa64bab8f65f39ac8f667b8293d801f4e664 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 20 Jun 2019 18:23:40 -0700 Subject: [PATCH 1/6] sm: completely rewrite module --- stratosphere/sm/source/sm_dmnt_service.cpp | 24 +- stratosphere/sm/source/sm_dmnt_service.hpp | 42 +- stratosphere/sm/source/sm_main.cpp | 22 +- stratosphere/sm/source/sm_manager_service.cpp | 30 +- stratosphere/sm/source/sm_manager_service.hpp | 48 +- stratosphere/sm/source/sm_registration.cpp | 632 --------------- stratosphere/sm/source/sm_registration.hpp | 92 --- stratosphere/sm/source/sm_service_manager.cpp | 723 ++++++++++++++++++ stratosphere/sm/source/sm_service_manager.hpp | 51 ++ stratosphere/sm/source/sm_types.hpp | 66 +- stratosphere/sm/source/sm_user_service.cpp | 107 +-- stratosphere/sm/source/sm_user_service.hpp | 82 +- 12 files changed, 996 insertions(+), 923 deletions(-) delete mode 100644 stratosphere/sm/source/sm_registration.cpp delete mode 100644 stratosphere/sm/source/sm_registration.hpp create mode 100644 stratosphere/sm/source/sm_service_manager.cpp create mode 100644 stratosphere/sm/source/sm_service_manager.hpp diff --git a/stratosphere/sm/source/sm_dmnt_service.cpp b/stratosphere/sm/source/sm_dmnt_service.cpp index bca340122..5cffbb0d4 100644 --- a/stratosphere/sm/source/sm_dmnt_service.cpp +++ b/stratosphere/sm/source/sm_dmnt_service.cpp @@ -16,18 +16,22 @@ #include #include + #include "sm_dmnt_service.hpp" -#include "sm_registration.hpp" +#include "sm_service_manager.hpp" -Result DmntService::AtmosphereGetRecord(Out record, SmServiceName service) { - return Registration::GetServiceRecord(smEncodeName(service.name), record.GetPointer()); -} +namespace sts { namespace sm { -void DmntService::AtmosphereListRecords(OutBuffer records, Out out_count, u64 offset) { - Registration::ListServiceRecords(offset, records.num_elements, records.buffer, out_count.GetPointer()); -} + Result DmntService::AtmosphereGetRecord(Out record, ServiceName service) { + return sm::GetServiceRecord(record.GetPointer(), service); + } -void DmntService::AtmosphereGetRecordSize(Out record_size) { - record_size.SetValue(sizeof(SmServiceRecord)); -} + void DmntService::AtmosphereListRecords(OutBuffer records, Out out_count, u64 offset) { + R_ASSERT(sm::ListServiceRecords(records.buffer, out_count.GetPointer(), offset, records.num_elements)); + } + void DmntService::AtmosphereGetRecordSize(Out record_size) { + record_size.SetValue(sizeof(ServiceRecord)); + } + +}} diff --git a/stratosphere/sm/source/sm_dmnt_service.hpp b/stratosphere/sm/source/sm_dmnt_service.hpp index dfb84c890..1a3b9ca47 100644 --- a/stratosphere/sm/source/sm_dmnt_service.hpp +++ b/stratosphere/sm/source/sm_dmnt_service.hpp @@ -19,22 +19,28 @@ #include #include "sm_types.hpp" -enum DmntServiceCmd { - Dmnt_Cmd_AtmosphereGetRecord = 65000, - Dmnt_Cmd_AtmosphereListRecords = 65001, - Dmnt_Cmd_AtmosphereGetRecordSize = 65002, -}; +namespace sts { namespace sm { -class DmntService final : public IServiceObject { - private: - /* Actual commands. */ - virtual Result AtmosphereGetRecord(Out record, SmServiceName service); - virtual void AtmosphereListRecords(OutBuffer records, Out out_count, u64 offset); - virtual void AtmosphereGetRecordSize(Out record_size); - public: - DEFINE_SERVICE_DISPATCH_TABLE { - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - }; -}; + /* Command IDs. */ + enum DmntServiceCmd { + Dmnt_Cmd_AtmosphereGetRecord = 65000, + Dmnt_Cmd_AtmosphereListRecords = 65001, + Dmnt_Cmd_AtmosphereGetRecordSize = 65002, + }; + + /* Service definition. */ + class DmntService final : public IServiceObject { + private: + /* Actual commands. */ + virtual Result AtmosphereGetRecord(Out record, ServiceName service); + virtual void AtmosphereListRecords(OutBuffer records, Out out_count, u64 offset); + virtual void AtmosphereGetRecordSize(Out record_size); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + }; + }; + +}} diff --git a/stratosphere/sm/source/sm_main.cpp b/stratosphere/sm/source/sm_main.cpp index 0c5e1aa1f..645978cbb 100644 --- a/stratosphere/sm/source/sm_main.cpp +++ b/stratosphere/sm/source/sm_main.cpp @@ -22,10 +22,10 @@ #include #include -#include "sm_manager_service.hpp" +#include "sm_service_manager.hpp" #include "sm_user_service.hpp" +#include "sm_manager_service.hpp" #include "sm_dmnt_service.hpp" -#include "sm_registration.hpp" extern "C" { extern u32 __start__; @@ -75,31 +75,28 @@ void __appExit(void) { /* Nothing to clean up, because we're sm. */ } - - - int main(int argc, char **argv) { - consoleDebugInit(debugDevice_SVC); + /* Initialize service manager. */ + sts::sm::InitializeRegistrationLists(); /* TODO: What's a good timeout value to use here? */ static auto s_server_manager = WaitableManager(1); /* Create sm:, (and thus allow things to register to it). */ - s_server_manager.AddWaitable(new ManagedPortServer("sm:", 0x40)); + s_server_manager.AddWaitable(new ManagedPortServer("sm:", 0x40)); /* Create sm:m manually. */ Handle smm_h; - R_ASSERT(Registration::RegisterServiceForSelf(smEncodeName("sm:m"), 1, false, &smm_h)); - - s_server_manager.AddWaitable(new ExistingPortServer(smm_h, 1)); + R_ASSERT(sts::sm::RegisterServiceForSelf(&smm_h, sts::sm::ServiceName::Encode("sm:m"), 1)); + s_server_manager.AddWaitable(new ExistingPortServer(smm_h, 1)); /*===== ATMOSPHERE EXTENSION =====*/ /* Create sm:dmnt manually. */ Handle smdmnt_h; - R_ASSERT(Registration::RegisterServiceForSelf(smEncodeName("sm:dmnt"), 1, false, &smdmnt_h)); + R_ASSERT(sts::sm::RegisterServiceForSelf(&smdmnt_h, sts::sm::ServiceName::Encode("sm:dmnt"), 1)); + s_server_manager.AddWaitable(new ExistingPortServer(smm_h, 1));; - s_server_manager.AddWaitable(new ExistingPortServer(smm_h, 1));; /*================================*/ /* Loop forever, servicing our services. */ @@ -108,4 +105,3 @@ int main(int argc, char **argv) /* Cleanup. */ return 0; } - diff --git a/stratosphere/sm/source/sm_manager_service.cpp b/stratosphere/sm/source/sm_manager_service.cpp index 9b559663d..e132706dd 100644 --- a/stratosphere/sm/source/sm_manager_service.cpp +++ b/stratosphere/sm/source/sm_manager_service.cpp @@ -16,22 +16,26 @@ #include #include + #include "sm_manager_service.hpp" -#include "sm_registration.hpp" +#include "sm_service_manager.hpp" -Result ManagerService::RegisterProcess(u64 pid, InBuffer acid_sac, InBuffer aci0_sac) { - return Registration::RegisterProcess(pid, acid_sac.buffer, acid_sac.num_elements, aci0_sac.buffer, aci0_sac.num_elements); -} +namespace sts { namespace sm { -Result ManagerService::UnregisterProcess(u64 pid) { - return Registration::UnregisterProcess(pid); -} + Result ManagerService::RegisterProcess(u64 pid, InBuffer acid_sac, InBuffer aci0_sac) { + return sm::RegisterProcess(pid, acid_sac.buffer, acid_sac.num_elements, aci0_sac.buffer, aci0_sac.num_elements); + } -void ManagerService::AtmosphereEndInitDefers() { - Registration::EndInitDefers(); -} + Result ManagerService::UnregisterProcess(u64 pid) { + return sm::UnregisterProcess(pid); + } -void ManagerService::AtmosphereHasMitm(Out out, SmServiceName service) { - out.SetValue(Registration::HasMitm(smEncodeName(service.name))); -} + void ManagerService::AtmosphereEndInitDefers() { + R_ASSERT(sm::EndInitialDefers()); + } + void ManagerService::AtmosphereHasMitm(Out out, ServiceName service) { + R_ASSERT(sm::HasMitm(out.GetPointer(), service)); + } + +}} diff --git a/stratosphere/sm/source/sm_manager_service.hpp b/stratosphere/sm/source/sm_manager_service.hpp index 8960eecdf..c8d7f5763 100644 --- a/stratosphere/sm/source/sm_manager_service.hpp +++ b/stratosphere/sm/source/sm_manager_service.hpp @@ -19,27 +19,33 @@ #include #include "sm_types.hpp" -enum ManagerServiceCmd { - Manager_Cmd_RegisterProcess = 0, - Manager_Cmd_UnregisterProcess = 1, +namespace sts { namespace sm { - Manager_Cmd_AtmosphereEndInitDefers = 65000, - Manager_Cmd_AtmosphereHasMitm = 65001, -}; + /* Command IDs. */ + enum ManagerServiceCmd { + Manager_Cmd_RegisterProcess = 0, + Manager_Cmd_UnregisterProcess = 1, -class ManagerService final : public IServiceObject { - private: - /* Actual commands. */ - virtual Result RegisterProcess(u64 pid, InBuffer acid_sac, InBuffer aci0_sac); - virtual Result UnregisterProcess(u64 pid); - virtual void AtmosphereEndInitDefers(); - virtual void AtmosphereHasMitm(Out out, SmServiceName service); - public: - DEFINE_SERVICE_DISPATCH_TABLE { - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), + Manager_Cmd_AtmosphereEndInitDefers = 65000, + Manager_Cmd_AtmosphereHasMitm = 65001, + }; - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - }; -}; + /* Service definition. */ + class ManagerService final : public IServiceObject { + private: + /* Actual commands. */ + virtual Result RegisterProcess(u64 pid, InBuffer acid_sac, InBuffer aci0_sac); + virtual Result UnregisterProcess(u64 pid); + virtual void AtmosphereEndInitDefers(); + virtual void AtmosphereHasMitm(Out out, ServiceName service); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + }; + }; + +}} diff --git a/stratosphere/sm/source/sm_registration.cpp b/stratosphere/sm/source/sm_registration.cpp deleted file mode 100644 index bfdba8820..000000000 --- a/stratosphere/sm/source/sm_registration.cpp +++ /dev/null @@ -1,632 +0,0 @@ -/* - * Copyright (c) 2018-2019 Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include "sm_registration.hpp" -#include "meta_tools.hpp" - -static std::array g_process_list = {0}; -static std::array g_service_list = {0}; - -static u64 g_initial_process_id_low = 0; -static u64 g_initial_process_id_high = 0; -static bool g_determined_initial_process_ids = false; -static bool g_end_init_defers = false; - -u64 GetServiceNameLength(u64 service) { - u64 service_name_len = 0; - while (service & 0xFF) { - service_name_len++; - service >>= 8; - } - return service_name_len; -} - -/* Atmosphere extension utilities. */ -void Registration::EndInitDefers() { - g_end_init_defers = true; -} - -constexpr u64 EncodeNameConstant(const char *name) { - u64 service = 0; - for (unsigned int i = 0; i < sizeof(service); i++) { - if (name[i] == '\x00') { - break; - } - service |= ((u64)name[i]) << (8 * i); - } - return service; -} - -bool Registration::ShouldInitDefer(u64 service) { - /* Only enable if compile-time generated. */ -#ifndef SM_ENABLE_INIT_DEFERS - return false; -#endif - - if (g_end_init_defers) { - return false; - } - - /* This is a mechanism by which certain services will always be deferred until sm:m receives a special command. */ - /* This can be extended with more services as needed at a later date. */ - constexpr u64 FSP_SRV = EncodeNameConstant("fsp-srv"); - return service == FSP_SRV; -} - -/* Utilities. */ -Registration::Process *Registration::GetProcessForPid(u64 pid) { - auto process_it = std::find_if(g_process_list.begin(), g_process_list.end(), member_equals_fn(&Process::pid, pid)); - if (process_it == g_process_list.end()) { - return nullptr; - } - return &*process_it; -} - -Registration::Process *Registration::GetFreeProcess() { - return GetProcessForPid(0); -} - -Registration::Service *Registration::GetService(u64 service_name) { - auto service_it = std::find_if(g_service_list.begin(), g_service_list.end(), member_equals_fn(&Service::service_name, service_name)); - if (service_it == g_service_list.end()) { - return nullptr; - } - return &*service_it; -} - -Registration::Service *Registration::GetFreeService() { - return GetService(0); -} - -bool Registration::IsValidForSac(u8 *sac, size_t sac_size, u64 service, bool is_host) { - u8 cur_ctrl; - u64 cur_service; - u64 service_for_compare; - bool cur_is_host; - size_t remaining = sac_size; - while (remaining) { - cur_ctrl = *sac++; - remaining--; - size_t cur_size = (cur_ctrl & 7) + 1; - if (cur_size > remaining) { - break; - } - cur_is_host = (cur_ctrl & 0x80) != 0; - cur_service = 0; - for (unsigned int i = 0; i < cur_size; i++) { - cur_service |= ((u64)sac[i]) << (8 * i); - } - /* Check if the last byte is a wildcard ('*') */ - service_for_compare = service; - if (sac[cur_size - 1] == '*') { - u64 mask = U64_MAX; - for (unsigned int i = 0; i < 8 - (cur_size - 1); i++) { - mask >>= 8; - } - /* Mask cur_service, service with 0xFF.. up until the wildcard. */ - cur_service &= mask; - service_for_compare &= mask; - } - if (cur_service == service_for_compare && (is_host == cur_is_host)) { - return true; - } - sac += cur_size; - remaining -= cur_size; - } - return false; -} - - -bool Registration::ValidateSacAgainstRestriction(u8 *r_sac, size_t r_sac_size, u8 *sac, size_t sac_size) { - u8 cur_ctrl; - u64 cur_service; - bool cur_is_host; - size_t remaining = sac_size; - while (remaining) { - cur_ctrl = *sac++; - remaining--; - size_t cur_size = (cur_ctrl & 7) + 1; - if (cur_size > remaining) { - break; - } - cur_is_host = (cur_ctrl & 0x80) != 0; - cur_service = 0; - for (unsigned int i = 0; i < cur_size; i++) { - cur_service |= ((u64)sac[i]) << (8 * i); - } - if (!IsValidForSac(r_sac, r_sac_size, cur_service, cur_is_host)) { - return false; - } - sac += cur_size; - remaining -= cur_size; - } - return true; -} - -void Registration::CacheInitialProcessIdLimits() { - if (g_determined_initial_process_ids) { - return; - } - if ((GetRuntimeFirmwareVersion() >= FirmwareVersion_500)) { - svcGetSystemInfo(&g_initial_process_id_low, 2, 0, 0); - svcGetSystemInfo(&g_initial_process_id_high, 2, 0, 1); - } else { - g_initial_process_id_low = 0; - g_initial_process_id_high = REGISTRATION_INITIAL_PID_MAX; - } - g_determined_initial_process_ids = true; -} - -bool Registration::IsInitialProcess(u64 pid) { - CacheInitialProcessIdLimits(); - return g_initial_process_id_low <= pid && pid <= g_initial_process_id_high; -} - -u64 Registration::GetInitialProcessId() { - CacheInitialProcessIdLimits(); - if (IsInitialProcess(1)) { - return 1; - } - return g_initial_process_id_low; -} - -/* Process management. */ -Result Registration::RegisterProcess(u64 pid, u8 *acid_sac, size_t acid_sac_size, u8 *aci0_sac, size_t aci0_sac_size) { - if (aci0_sac_size > REGISTRATION_MAX_SAC_SIZE) { - return ResultSmTooLargeAccessControl; - } - - Registration::Process *proc = GetFreeProcess(); - if (proc == NULL) { - return ResultSmInsufficientProcesses; - } - - if (aci0_sac_size && !ValidateSacAgainstRestriction(acid_sac, acid_sac_size, aci0_sac, aci0_sac_size)) { - return ResultSmNotAllowed; - } - - proc->pid = pid; - proc->sac_size = aci0_sac_size; - std::copy(aci0_sac, aci0_sac + aci0_sac_size, proc->sac); - return ResultSuccess; -} - -Result Registration::UnregisterProcess(u64 pid) { - Registration::Process *proc = GetProcessForPid(pid); - if (proc == NULL) { - return ResultSmInvalidClient; - } - - proc->pid = 0; - return ResultSuccess; -} - -/* Service management. */ -bool Registration::HasService(u64 service) { - return std::any_of(g_service_list.begin(), g_service_list.end(), member_equals_fn(&Service::service_name, service)); -} - -bool Registration::HasMitm(u64 service) { - Registration::Service *target_service = GetService(service); - return target_service != NULL && target_service->mitm_pid != 0; -} - -Result Registration::GetMitmServiceHandleImpl(Registration::Service *target_service, u64 pid, Handle *out) { - /* Send command to query if we should mitm. */ - IpcCommand c; - ipcInitialize(&c); - struct { - u64 magic; - u64 cmd_id; - u64 pid; - } *info = ((decltype(info))ipcPrepareHeader(&c, sizeof(*info))); - info->magic = SFCI_MAGIC; - info->cmd_id = 65000; - info->pid = pid; - R_TRY(ipcDispatch(target_service->mitm_query_h)); - - /* Parse response to see if we should mitm. */ - bool should_mitm; - { - IpcParsedCommand r; - ipcParse(&r); - struct { - u64 magic; - u64 result; - bool should_mitm; - } *resp = ((decltype(resp))r.Raw); - - R_TRY(resp->result); - should_mitm = resp->should_mitm; - } - - /* If we shouldn't mitm, give normal session. */ - if (!should_mitm) { - return svcConnectToPort(out, target_service->port_h); - } - - /* Create both handles. If the second fails, close the first to prevent leak. */ - R_TRY(svcConnectToPort(&target_service->mitm_fwd_sess_h, target_service->port_h)); - R_TRY_CLEANUP(svcConnectToPort(out, target_service->mitm_port_h), { - svcCloseHandle(target_service->mitm_fwd_sess_h); - target_service->mitm_fwd_sess_h = 0; - }); - - target_service->mitm_waiting_ack_pid = pid; - target_service->mitm_waiting_ack = true; - - return ResultSuccess; -} - -Result Registration::GetServiceHandleImpl(Registration::Service *target_service, u64 pid, Handle *out) { - /* Clear handle output. */ - *out = 0; - - /* If not mitm'd or mitm service is requesting, get normal session. */ - if (target_service->mitm_pid == 0 || target_service->mitm_pid == pid) { - return svcConnectToPort(out, target_service->port_h); - } - - /* We're mitm'd. */ - if (R_FAILED(GetMitmServiceHandleImpl(target_service, pid, out))) { - /* If the Mitm service is dead, just give a normal session. */ - return svcConnectToPort(out, target_service->port_h); - } - - return ResultSuccess; -} - -Result Registration::GetServiceHandle(u64 pid, u64 service, Handle *out) { - Registration::Service *target_service = GetService(service); - if (target_service == NULL || ShouldInitDefer(service) || target_service->mitm_waiting_ack) { - /* Note: This defers the result until later. */ - return ResultServiceFrameworkRequestDeferredByUser; - } - - R_TRY_CATCH(GetServiceHandleImpl(target_service, pid, out)) { - /* Convert Kernel result to SM result. */ - R_CATCH(ResultKernelOutOfSessions) { - return ResultSmInsufficientSessions; - } - } R_END_TRY_CATCH; - - return ResultSuccess; -} - -Result Registration::GetServiceForPid(u64 pid, u64 service, Handle *out) { - if (!service) { - return ResultSmInvalidServiceName; - } - - u64 service_name_len = GetServiceNameLength(service); - - /* If the service has bytes after a null terminator, that's no good. */ - if (service_name_len != 8 && (service >> (8 * service_name_len))) { - return ResultSmInvalidServiceName; - } - - /* In 8.0.0, Nintendo removed the service apm:p -- however, all homebrew attempts to get */ - /* a handle to this when calling appletInitialize(). Because hbl has access to all services, */ - /* This would return true, and homebrew would *wait forever* trying to get a handle to a service */ - /* that will never register. Thus, in the interest of not breaking every single piece of homebrew */ - /* we will provide a little first class help. */ - if (GetRuntimeFirmwareVersion() >= FirmwareVersion_800 && service == EncodeNameConstant("apm:p")) { - return ResultSmNotAllowed; - } - - if (!IsInitialProcess(pid)) { - Registration::Process *proc = GetProcessForPid(pid); - if (proc == NULL) { - return ResultSmInvalidClient; - } - - if (!IsValidForSac(proc->sac, proc->sac_size, service, false)) { - return ResultSmNotAllowed; - } - } - - return GetServiceHandle(pid, service, out); -} - -Result Registration::RegisterServiceForPid(u64 pid, u64 service, u64 max_sessions, bool is_light, Handle *out) { - if (!service) { - return ResultSmInvalidServiceName; - } - - u64 service_name_len = GetServiceNameLength(service); - - /* If the service has bytes after a null terminator, that's no good. */ - if (service_name_len != 8 && (service >> (8 * service_name_len))) { - return ResultSmInvalidServiceName; - } - - if (!IsInitialProcess(pid)) { - Registration::Process *proc = GetProcessForPid(pid); - if (proc == NULL) { - return ResultSmInvalidClient; - } - - if (!IsValidForSac(proc->sac, proc->sac_size, service, true)) { - return ResultSmNotAllowed; - } - } - - if (HasService(service)) { - return ResultSmAlreadyRegistered; - } - -#ifdef SM_MINIMUM_SESSION_LIMIT - if (max_sessions < SM_MINIMUM_SESSION_LIMIT) { - max_sessions = SM_MINIMUM_SESSION_LIMIT; - } -#endif - - Registration::Service *free_service = GetFreeService(); - if (free_service == NULL) { - return ResultSmInsufficientServices; - } - - *out = 0; - *free_service = (const Registration::Service){0}; - R_TRY(svcCreatePort(out, &free_service->port_h, max_sessions, is_light, (char *)&free_service->service_name)); - - free_service->service_name = service; - free_service->owner_pid = pid; - free_service->max_sessions = max_sessions; - free_service->is_light = is_light; - - return ResultSuccess; -} - -Result Registration::RegisterServiceForSelf(u64 service, u64 max_sessions, bool is_light, Handle *out) { - u64 pid; - R_TRY(svcGetProcessId(&pid, CUR_PROCESS_HANDLE)); - - u64 service_name_len = GetServiceNameLength(service); - - /* If the service has bytes after a null terminator, that's no good. */ - if (service_name_len != 8 && (service >> (8 * service_name_len))) { - return ResultSmInvalidServiceName; - } - - if (HasService(service)) { - return ResultSmAlreadyRegistered; - } - -#ifdef SM_MINIMUM_SESSION_LIMIT - if (max_sessions < SM_MINIMUM_SESSION_LIMIT) { - max_sessions = SM_MINIMUM_SESSION_LIMIT; - } -#endif - - Registration::Service *free_service = GetFreeService(); - if (free_service == NULL) { - return ResultSmInsufficientServices; - } - - *out = 0; - *free_service = (const Registration::Service){0}; - R_TRY(svcCreatePort(out, &free_service->port_h, max_sessions, is_light, (char *)&free_service->service_name)); - - free_service->service_name = service; - free_service->owner_pid = pid; - free_service->max_sessions = max_sessions; - free_service->is_light = is_light; - - return ResultSuccess; -} - -Result Registration::UnregisterServiceForPid(u64 pid, u64 service) { - if (!service) { - return ResultSmInvalidServiceName; - } - - u64 service_name_len = GetServiceNameLength(service); - - /* If the service has bytes after a null terminator, that's no good. */ - if (service_name_len != 8 && (service >> (8 * service_name_len))) { - return ResultSmInvalidServiceName; - } - - Registration::Service *target_service = GetService(service); - if (target_service == NULL) { - return ResultSmNotRegistered; - } - - if (!IsInitialProcess(pid) && target_service->owner_pid != pid) { - return ResultSmNotAllowed; - } - - svcCloseHandle(target_service->port_h); - svcCloseHandle(target_service->mitm_port_h); - svcCloseHandle(target_service->mitm_query_h); - *target_service = (const Registration::Service){0}; - return ResultSuccess; -} - - -Result Registration::InstallMitmForPid(u64 pid, u64 service, Handle *out, Handle *query_out) { - if (!service) { - return ResultSmInvalidServiceName; - } - - u64 service_name_len = GetServiceNameLength(service); - - /* If the service has bytes after a null terminator, that's no good. */ - if (service_name_len != 8 && (service >> (8 * service_name_len))) { - return ResultSmInvalidServiceName; - } - - /* Verify we're allowed to mitm the service. */ - if (!IsInitialProcess(pid)) { - Registration::Process *proc = GetProcessForPid(pid); - if (proc == NULL) { - return ResultSmInvalidClient; - } - - if (!IsValidForSac(proc->sac, proc->sac_size, service, true)) { - return ResultSmNotAllowed; - } - } - - /* Verify the service exists. */ - Registration::Service *target_service = GetService(service); - if (target_service == NULL) { - return ResultServiceFrameworkRequestDeferredByUser; - } - - /* Verify the service isn't already being mitm'd. */ - if (target_service->mitm_pid != 0) { - return ResultSmAlreadyRegistered; - } - - *out = 0; - u64 x = 0; - R_TRY(svcCreatePort(out, &target_service->mitm_port_h, target_service->max_sessions, target_service->is_light, (char *)&x)); - R_TRY(svcCreateSession(query_out, &target_service->mitm_query_h, 0, 0)); - - target_service->mitm_pid = pid; - - return ResultSuccess; -} - -Result Registration::UninstallMitmForPid(u64 pid, u64 service) { - if (!service) { - return ResultSmInvalidServiceName; - } - - u64 service_name_len = GetServiceNameLength(service); - - /* If the service has bytes after a null terminator, that's no good. */ - if (service_name_len != 8 && (service >> (8 * service_name_len))) { - return ResultSmInvalidServiceName; - } - - Registration::Service *target_service = GetService(service); - if (target_service == NULL) { - return ResultSmNotRegistered; - } - - if (!IsInitialProcess(pid) && target_service->mitm_pid != pid) { - return ResultSmNotAllowed; - } - - svcCloseHandle(target_service->mitm_port_h); - svcCloseHandle(target_service->mitm_query_h); - target_service->mitm_pid = 0; - return ResultSuccess; -} - -Result Registration::AcknowledgeMitmSessionForPid(u64 pid, u64 service, Handle *out, u64 *out_pid) { - if (!service) { - return ResultSmInvalidServiceName; - } - - u64 service_name_len = GetServiceNameLength(service); - - /* If the service has bytes after a null terminator, that's no good. */ - if (service_name_len != 8 && (service >> (8 * service_name_len))) { - return ResultSmInvalidServiceName; - } - - Registration::Service *target_service = GetService(service); - if (target_service == NULL) { - return ResultSmNotRegistered; - } - - if ((!IsInitialProcess(pid) && target_service->mitm_pid != pid) || !target_service->mitm_waiting_ack) { - return ResultSmNotAllowed; - } - - *out = target_service->mitm_fwd_sess_h; - *out_pid = target_service->mitm_waiting_ack_pid; - target_service->mitm_fwd_sess_h = 0; - target_service->mitm_waiting_ack_pid = 0; - target_service->mitm_waiting_ack = false; - return ResultSuccess; -} - -Result Registration::AssociatePidTidForMitm(u64 pid, u64 tid) { - for (auto &service : g_service_list) { - if (service.mitm_pid) { - IpcCommand c; - ipcInitialize(&c); - struct { - u64 magic; - u64 cmd_id; - u64 pid; - u64 tid; - } *info = ((decltype(info))ipcPrepareHeader(&c, sizeof(*info))); - info->magic = SFCI_MAGIC; - info->cmd_id = 65001; - info->pid = pid; - info->tid = tid; - ipcDispatch(service.mitm_query_h); - } - } - return ResultSuccess; -} - -void Registration::ConvertServiceToRecord(Registration::Service *service, SmServiceRecord *record) { - record->service_name = service->service_name; - record->owner_pid = service->owner_pid; - record->max_sessions = service->max_sessions; - record->mitm_pid = service->mitm_pid; - record->mitm_waiting_ack_pid = service->mitm_waiting_ack_pid; - record->is_light = service->is_light; - record->mitm_waiting_ack = service->mitm_waiting_ack; -} - -Result Registration::GetServiceRecord(u64 service, SmServiceRecord *out) { - if (!service) { - return ResultSmInvalidServiceName; - } - - u64 service_name_len = GetServiceNameLength(service); - - /* If the service has bytes after a null terminator, that's no good. */ - if (service_name_len != 8 && (service >> (8 * service_name_len))) { - return ResultSmInvalidServiceName; - } - - Registration::Service *target_service = GetService(service); - if (target_service == NULL) { - return ResultSmNotRegistered; - } - - ConvertServiceToRecord(target_service, out); - return ResultSuccess; -} - -void Registration::ListServiceRecords(u64 offset, u64 max_out, SmServiceRecord *out, u64 *out_count) { - u64 count = 0; - - for (auto it = g_service_list.begin(); it != g_service_list.end() && count < max_out; it++) { - if (it->service_name != 0) { - if (offset > 0) { - offset--; - } else { - ConvertServiceToRecord(it, out++); - count++; - } - } - } - - *out_count = count; -} diff --git a/stratosphere/sm/source/sm_registration.hpp b/stratosphere/sm/source/sm_registration.hpp deleted file mode 100644 index bb4f6e3c6..000000000 --- a/stratosphere/sm/source/sm_registration.hpp +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2018-2019 Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once -#include - -#include "sm_types.hpp" - -#define REGISTRATION_LIST_MAX_PROCESS (0x40) -#define REGISTRATION_LIST_MAX_SERVICE (0x100) -#define REGISTRATION_MAX_SAC_SIZE (0x200) -#define REGISTRATION_INITIAL_PID_MAX 0x50 - -class Registration { - public: - struct Process { - u64 pid; - u64 sac_size; - u8 sac[REGISTRATION_MAX_SAC_SIZE]; - }; - - struct Service { - u64 service_name; - u64 owner_pid; - Handle port_h; - - /* Debug. */ - u64 max_sessions; - bool is_light; - - /* Extension. */ - u64 mitm_pid; - Handle mitm_port_h; - Handle mitm_query_h; - - bool mitm_waiting_ack; - u64 mitm_waiting_ack_pid; - Handle mitm_fwd_sess_h; - }; - - /* Utilities. */ - static void EndInitDefers(); - static bool ShouldInitDefer(u64 service); - - static Registration::Process *GetProcessForPid(u64 pid); - static Registration::Process *GetFreeProcess(); - static Registration::Service *GetService(u64 service); - static Registration::Service *GetFreeService(); - static bool IsValidForSac(u8 *sac, size_t sac_size, u64 service, bool is_host); - static bool ValidateSacAgainstRestriction(u8 *r_sac, size_t r_sac_size, u8 *sac, size_t sac_size); - static void CacheInitialProcessIdLimits(); - static bool IsInitialProcess(u64 pid); - static u64 GetInitialProcessId(); - - /* Process management. */ - static Result RegisterProcess(u64 pid, u8 *acid_sac, size_t acid_sac_size, u8 *aci0_sac, size_t aci0_sac_size); - static Result UnregisterProcess(u64 pid); - - /* Service management. */ - static bool HasService(u64 service); - static bool HasMitm(u64 service); - static Result GetMitmServiceHandleImpl(Registration::Service *service, u64 pid, Handle *out); - static Result GetServiceHandleImpl(Registration::Service *service, u64 pid, Handle *out); - static Result GetServiceHandle(u64 pid, u64 service, Handle *out); - static Result GetServiceForPid(u64 pid, u64 service, Handle *out); - static Result RegisterServiceForPid(u64 pid, u64 service, u64 max_sessions, bool is_light, Handle *out); - static Result RegisterServiceForSelf(u64 service, u64 max_sessions, bool is_light, Handle *out); - static Result UnregisterServiceForPid(u64 pid, u64 service); - - /* Extension. */ - static Result InstallMitmForPid(u64 pid, u64 service, Handle *out, Handle *query_out); - static Result UninstallMitmForPid(u64 pid, u64 service); - static Result AcknowledgeMitmSessionForPid(u64 pid, u64 service, Handle *out, u64 *out_pid); - static Result AssociatePidTidForMitm(u64 pid, u64 tid); - - static void ConvertServiceToRecord(Registration::Service *service, SmServiceRecord *record); - static Result GetServiceRecord(u64 service, SmServiceRecord *out); - static void ListServiceRecords(u64 offset, u64 max_out, SmServiceRecord *out, u64 *out_count); -}; diff --git a/stratosphere/sm/source/sm_service_manager.cpp b/stratosphere/sm/source/sm_service_manager.cpp new file mode 100644 index 000000000..8b633664b --- /dev/null +++ b/stratosphere/sm/source/sm_service_manager.cpp @@ -0,0 +1,723 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "sm_service_manager.hpp" + +namespace sts { namespace sm { + + /* Anonymous namespace for implementation details. */ + namespace { + /* Constexpr definitions. */ + static constexpr size_t ProcessCountMax = 0x40; + static constexpr size_t ServiceCountMax = 0x100; + static constexpr size_t AccessControlSizeMax = 0x200; + + /* Types. */ + struct ProcessInfo { + u64 pid; + size_t access_control_size; + u8 access_control[AccessControlSizeMax]; + }; + + struct ServiceInfo { + ServiceName name; + u64 owner_pid; + Handle port_h; + + /* Debug. */ + u64 max_sessions; + bool is_light; + + /* Mitm Extension. */ + u64 mitm_pid; + Handle mitm_port_h; + Handle mitm_query_h; + + /* Acknowledgement members. */ + bool mitm_waiting_ack; + u64 mitm_waiting_ack_pid; + Handle mitm_fwd_sess_h; + }; + + class AccessControlEntry { + private: + const u8 *entry; + size_t size; + public: + AccessControlEntry(const void *e, size_t sz) : entry(reinterpret_cast(e)), size(sz) { + /* ... */ + } + + AccessControlEntry GetNextEntry() const { + return AccessControlEntry(this->entry + this->GetSize(), this->size - this->GetSize()); + } + + size_t GetSize() const { + return this->GetServiceNameSize() + 1; + } + + size_t GetServiceNameSize() const { + return (this->entry[0] & 7) + 1; + } + + ServiceName GetServiceName() const { + return ServiceName::Encode(reinterpret_cast(this->entry + 1), this->GetServiceNameSize()); + } + + bool IsHost() const { + return (this->entry[0] & 0x80) != 0; + } + + bool IsWildcard() const { + return this->entry[this->GetServiceNameSize()] == '*'; + } + + bool IsValid() const { + /* Validate that we can access data. */ + if (this->entry == nullptr || this->size == 0) { + return false; + } + + /* Validate that the size is correct. */ + return this->GetSize() <= this->size; + } + }; + + class InitialProcessIdLimits { + public: + static constexpr u64 InitialProcessIdMin = 0x00; + static constexpr u64 InitialProcessIdMax = 0x50; + private: + u64 min; + u64 max; + public: + InitialProcessIdLimits() { + if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500) { + /* On 5.0.0+, we can get precise limits from the kernel. */ + R_ASSERT(svcGetSystemInfo(&this->min, 2, 0, 0)); + R_ASSERT(svcGetSystemInfo(&this->max, 2, 0, 1)); + } else { + /* On < 5.0.0, we just use hardcoded extents. */ + this->min = InitialProcessIdMin; + this->max = InitialProcessIdMax; + } + + /* Ensure range is sane. */ + if (this->min > this->max) { + std::abort(); + } + } + + bool IsInitialProcess(u64 pid) const { + if (pid == InvalidProcessId) { + std::abort(); + } + return this->min <= pid && pid <= this->max; + } + }; + + /* Static members. */ + ProcessInfo g_process_list[ProcessCountMax]; + ServiceInfo g_service_list[ServiceCountMax]; + InitialProcessIdLimits g_initial_process_id_limits; + bool g_ended_initial_defers; + + /* Helper functions for interacting with processes/services. */ + ProcessInfo *GetProcessInfo(u64 pid) { + for (size_t i = 0; i < ProcessCountMax; i++) { + if (g_process_list[i].pid == pid) { + return &g_process_list[i]; + } + } + return nullptr; + } + + ProcessInfo *GetFreeProcessInfo() { + return GetProcessInfo(InvalidProcessId); + } + + void FreeProcessInfo(ProcessInfo *process_info) { + std::memset(process_info, 0, sizeof(*process_info)); + process_info->pid = InvalidProcessId; + } + + bool HasProcessInfo(u64 pid) { + return GetProcessInfo(pid) != nullptr; + } + + ServiceInfo *GetServiceInfo(ServiceName service_name) { + for (size_t i = 0; i < ServiceCountMax; i++) { + if (g_service_list[i].name == service_name) { + return &g_service_list[i]; + } + } + return nullptr; + } + + ServiceInfo *GetFreeServiceInfo() { + return GetServiceInfo(InvalidServiceName); + } + + void GetServiceInfoRecord(ServiceRecord *out_record, const ServiceInfo *service_info) { + out_record->service = service_info->name; + out_record->owner_pid = service_info->owner_pid; + out_record->max_sessions = service_info->max_sessions; + out_record->mitm_pid = service_info->mitm_pid; + out_record->mitm_waiting_ack_pid = service_info->mitm_waiting_ack_pid; + out_record->is_light = service_info->is_light; + out_record->mitm_waiting_ack = service_info->mitm_waiting_ack; + } + + void FreeServiceInfo(ServiceInfo *service_info) { + if (service_info->port_h != INVALID_HANDLE) { + svcCloseHandle(service_info->port_h); + } + if (service_info->mitm_port_h != INVALID_HANDLE) { + svcCloseHandle(service_info->mitm_port_h); + } + if (service_info->mitm_query_h != INVALID_HANDLE) { + svcCloseHandle(service_info->mitm_query_h); + } + std::memset(service_info, 0, sizeof(*service_info)); + service_info->owner_pid = InvalidProcessId; + service_info->mitm_pid = InvalidProcessId; + service_info->mitm_waiting_ack_pid = InvalidProcessId; + } + + bool HasServiceInfo(ServiceName service) { + return GetServiceInfo(service) != nullptr; + } + + Result ValidateAccessControl(AccessControlEntry access_control, ServiceName service, bool is_host, bool is_wildcard) { + /* Iterate over all entries in the access control, checking to see if we have a match. */ + while (access_control.IsValid()) { + if (access_control.IsHost() == is_host) { + if (access_control.IsWildcard() == is_wildcard) { + /* Check for exact match. */ + if (access_control.GetServiceName() == service) { + return ResultSuccess; + } + } else if (access_control.IsWildcard()) { + /* Also allow fuzzy match for wildcard. */ + ServiceName ac_service = access_control.GetServiceName(); + if (std::memcmp(&ac_service, &service, access_control.GetServiceNameSize() - 1) == 0) { + return ResultSuccess; + } + } + } + access_control = access_control.GetNextEntry(); + } + + return ResultSmNotAllowed; + } + + Result ValidateAccessControl(AccessControlEntry restriction, AccessControlEntry access) { + /* Ensure that every entry in the access control is allowed by the restriction control. */ + while (access.IsValid()) { + R_TRY(ValidateAccessControl(restriction, access.GetServiceName(), access.IsHost(), access.IsWildcard())); + access = access.GetNextEntry(); + } + + return ResultSuccess; + } + + Result ValidateServiceName(ServiceName service) { + /* Service names must be non-empty. */ + if (service.name[0] == 0) { + return ResultSmInvalidServiceName; + } + + /* Get name length. */ + size_t name_len = 1; + while (name_len < sizeof(service)) { + if (service.name[name_len] == 0) { + break; + } + name_len++; + } + + /* Names must be all-zero after they end. */ + while (name_len < sizeof(service)) { + if (service.name[name_len++] != 0) { + return ResultSmInvalidServiceName; + } + } + + return ResultSuccess; + } + + bool IsInitialProcess(u64 pid) { + return g_initial_process_id_limits.IsInitialProcess(pid); + } + + bool IsValidProcessId(u64 pid) { + return pid != InvalidProcessId; + } + + bool ShouldDeferForInit(ServiceName service) { + /* Once end has been called, we're done. */ + if (g_ended_initial_defers) { + return false; + } + + /* This is a mechanism by which certain services will always be deferred until sm:m receives a special command. */ + /* This can be extended with more services as needed at a later date. */ + return service == ServiceName::Encode("fsp-srv"); + } + + Result GetMitmServiceHandleImpl(Handle *out, ServiceInfo *service_info, u64 pid) { + /* Send command to query if we should mitm. */ + { + IpcCommand c; + ipcInitialize(&c); + struct { + u64 magic; + u64 cmd_id; + u64 pid; + } *info = ((decltype(info))ipcPrepareHeader(&c, sizeof(*info))); + info->magic = SFCI_MAGIC; + info->cmd_id = 65000; + info->pid = pid; + R_TRY(ipcDispatch(service_info->mitm_query_h)); + } + + /* Parse response to see if we should mitm. */ + bool should_mitm; + { + IpcParsedCommand r; + ipcParse(&r); + struct { + u64 magic; + u64 result; + bool should_mitm; + } *resp = ((decltype(resp))r.Raw); + + R_TRY(resp->result); + should_mitm = resp->should_mitm; + } + + /* If we shouldn't mitm, give normal session. */ + if (!should_mitm) { + return svcConnectToPort(out, service_info->port_h); + } + + /* Create both handles. If the second fails, close the first to prevent leak. */ + R_TRY(svcConnectToPort(&service_info->mitm_fwd_sess_h, service_info->port_h)); + R_TRY_CLEANUP(svcConnectToPort(out, service_info->mitm_port_h), { + svcCloseHandle(service_info->mitm_fwd_sess_h); + service_info->mitm_fwd_sess_h = 0; + }); + + service_info->mitm_waiting_ack_pid = pid; + service_info->mitm_waiting_ack = true; + + return ResultSuccess; + } + + Result GetServiceHandleImpl(Handle *out, ServiceInfo *service_info, u64 pid) { + /* Clear handle output. */ + *out = 0; + + /* If not mitm'd or mitm service is requesting, get normal session. */ + if (!IsValidProcessId(service_info->mitm_pid) || service_info->mitm_pid == pid) { + return svcConnectToPort(out, service_info->port_h); + } + + /* We're mitm'd. */ + if (R_FAILED(GetMitmServiceHandleImpl(out, service_info, pid))) { + /* If the Mitm service is dead, just give a normal session. */ + return svcConnectToPort(out, service_info->port_h); + } + + return ResultSuccess; + } + + Result RegisterServiceImpl(Handle *out, u64 pid, ServiceName service, size_t max_sessions, bool is_light) { + /* Validate service name. */ + R_TRY(ValidateServiceName(service)); + + /* Don't try to register something already registered. */ + if (HasServiceInfo(service)) { + return ResultSmAlreadyRegistered; + } + + /* Adjust session limit, if compile flags tell us to. */ +#ifdef SM_MINIMUM_SESSION_LIMIT + if (max_sessions < SM_MINIMUM_SESSION_LIMIT) { + max_sessions = SM_MINIMUM_SESSION_LIMIT; + } +#endif + + /* Get free service. */ + ServiceInfo *free_service = GetFreeServiceInfo(); + if (free_service == nullptr) { + return ResultSmInsufficientServices; + } + + /* Create the new service. */ + *out = 0; + R_TRY(svcCreatePort(out, &free_service->port_h, max_sessions, is_light, free_service->name.name)); + + /* Save info. */ + free_service->name = service; + free_service->owner_pid = pid; + free_service->max_sessions = max_sessions; + free_service->is_light = is_light; + + return ResultSuccess; + } + } + + /* Initialization. */ + void InitializeRegistrationLists() { + /* Free all services. */ + for (size_t i = 0; i < ServiceCountMax; i++) { + FreeServiceInfo(&g_service_list[i]); + } + /* Free all processes. */ + for (size_t i = 0; i < ProcessCountMax; i++) { + FreeProcessInfo(&g_process_list[i]); + } + } + + /* Process management. */ + Result RegisterProcess(u64 pid, const void *acid_sac, size_t acid_sac_size, const void *aci0_sac, size_t aci0_sac_size) { + /* Check that access control will fit in the ServiceInfo. */ + if (aci0_sac_size > AccessControlSizeMax) { + return ResultSmTooLargeAccessControl; + } + + /* Get free process. */ + ProcessInfo *proc = GetFreeProcessInfo(); + if (proc == nullptr) { + return ResultSmInsufficientProcesses; + } + + /* Validate restrictions. */ + if (!aci0_sac_size) { + return ResultSmNotAllowed; + } + R_TRY(ValidateAccessControl(AccessControlEntry(acid_sac, acid_sac_size), AccessControlEntry(aci0_sac, aci0_sac_size))); + + /* Save info. */ + proc->pid = pid; + proc->access_control_size = aci0_sac_size; + std::memcpy(proc->access_control, aci0_sac, proc->access_control_size); + return ResultSuccess; + } + + Result UnregisterProcess(u64 pid) { + /* Find the process. */ + ProcessInfo *proc = GetProcessInfo(pid); + if (proc == nullptr) { + return ResultSmInvalidClient; + } + + FreeProcessInfo(proc); + return ResultSuccess; + } + + /* Service management. */ + Result HasService(bool *out, ServiceName service) { + *out = HasServiceInfo(service); + return ResultSuccess; + } + + Result GetServiceHandle(Handle *out, u64 pid, ServiceName service) { + /* Validate service name. */ + R_TRY(ValidateServiceName(service)); + + /* In 8.0.0, Nintendo removed the service apm:p -- however, all homebrew attempts to get */ + /* a handle to this when calling appletInitialize(). Because hbl has access to all services, */ + /* This would return true, and homebrew would *wait forever* trying to get a handle to a service */ + /* that will never register. Thus, in the interest of not breaking every single piece of homebrew */ + /* we will provide a little first class help. */ + if (GetRuntimeFirmwareVersion() >= FirmwareVersion_800 && service == ServiceName::Encode("apm:p")) { + return ResultSmNotAllowed; + } + + /* Check that the process is registered and allowed to register the service. */ + if (!IsInitialProcess(pid)) { + ProcessInfo *proc = GetProcessInfo(pid); + if (proc == nullptr) { + return ResultSmInvalidClient; + } + + R_TRY(ValidateAccessControl(AccessControlEntry(proc->access_control, proc->access_control_size), service, false, false)); + } + + /* Get service info. Check to see if we need to defer this until later. */ + ServiceInfo *service_info = GetServiceInfo(service); + if (service_info == nullptr || ShouldDeferForInit(service) || service_info->mitm_waiting_ack) { + return ResultServiceFrameworkRequestDeferredByUser; + } + + /* Get a handle from the service info. */ + R_TRY_CATCH(GetServiceHandleImpl(out, service_info, pid)) { + /* Convert Kernel result to SM result. */ + R_CATCH(ResultKernelOutOfSessions) { + return ResultSmInsufficientSessions; + } + } R_END_TRY_CATCH; + + return ResultSuccess; + } + + Result RegisterService(Handle *out, u64 pid, ServiceName service, size_t max_sessions, bool is_light) { + /* Validate service name. */ + R_TRY(ValidateServiceName(service)); + + /* Check that the process is registered and allowed to register the service. */ + if (!IsInitialProcess(pid)) { + ProcessInfo *proc = GetProcessInfo(pid); + if (proc == nullptr) { + return ResultSmInvalidClient; + } + + R_TRY(ValidateAccessControl(AccessControlEntry(proc->access_control, proc->access_control_size), service, true, false)); + } + + if (HasServiceInfo(service)) { + return ResultSmAlreadyRegistered; + } + + return RegisterServiceImpl(out, pid, service, max_sessions, is_light); + } + + Result RegisterServiceForSelf(Handle *out, ServiceName service, size_t max_sessions) { + u64 self_pid; + R_TRY(svcGetProcessId(&self_pid, CUR_PROCESS_HANDLE)); + + return RegisterServiceImpl(out, self_pid, service, max_sessions, false); + } + + Result UnregisterService(u64 pid, ServiceName service) { + /* Validate service name. */ + R_TRY(ValidateServiceName(service)); + + /* Check that the process is registered. */ + if (!IsInitialProcess(pid)) { + if (!HasProcessInfo(pid)) { + return ResultSmInvalidClient; + } + } + + /* Ensure that the service is actually registered. */ + ServiceInfo *service_info = GetServiceInfo(service); + if (service_info == nullptr) { + return ResultSmNotRegistered; + } + + /* Check if we have permission to do this. */ + if (service_info->owner_pid != pid) { + return ResultSmNotAllowed; + } + + /* Unregister the service. */ + FreeServiceInfo(service_info); + return ResultSuccess; + } + + /* Mitm extensions. */ + Result HasMitm(bool *out, ServiceName service) { + /* Validate service name. */ + R_TRY(ValidateServiceName(service)); + + const ServiceInfo *service_info = GetServiceInfo(service); + *out = service_info != nullptr && IsValidProcessId(service_info->mitm_pid); + return ResultSuccess; + } + + Result InstallMitm(Handle *out, Handle *out_query, u64 pid, ServiceName service) { + /* Validate service name. */ + R_TRY(ValidateServiceName(service)); + + /* Check that the process is registered and allowed to register the service. */ + if (!IsInitialProcess(pid)) { + ProcessInfo *proc = GetProcessInfo(pid); + if (proc == nullptr) { + return ResultSmInvalidClient; + } + + R_TRY(ValidateAccessControl(AccessControlEntry(proc->access_control, proc->access_control_size), service, true, false)); + } + + /* Validate that the service exists. */ + ServiceInfo *service_info = GetServiceInfo(service); + if (service_info == nullptr) { + /* If it doesn't exist, defer until it does. */ + return ResultServiceFrameworkRequestDeferredByUser; + } + + /* Validate that the service isn't already being mitm'd. */ + if (IsValidProcessId(service_info->mitm_pid)) { + return ResultSmAlreadyRegistered; + } + + /* Always clear output. */ + *out = 0; + *out_query = 0; + + /* Create mitm handles. */ + Handle hnd = 0; + Handle qry_hnd = 0; + u64 x = 0; + R_TRY(svcCreatePort(&hnd, &service_info->mitm_port_h, service_info->max_sessions, service_info->is_light, reinterpret_cast(&x))); + R_TRY_CLEANUP(svcCreateSession(&qry_hnd, &service_info->mitm_query_h, 0, 0), { + svcCloseHandle(hnd); + svcCloseHandle(service_info->mitm_port_h); + service_info->mitm_port_h = 0; + }); + service_info->mitm_pid = pid; + + /* Set output. */ + *out = hnd; + *out_query = qry_hnd; + + return ResultSuccess; + } + + Result UninstallMitm(u64 pid, ServiceName service) { + /* Validate service name. */ + R_TRY(ValidateServiceName(service)); + + /* Check that the process is registered. */ + if (!IsInitialProcess(pid)) { + ProcessInfo *proc = GetProcessInfo(pid); + if (proc == nullptr) { + return ResultSmInvalidClient; + } + } + + /* Validate that the service exists. */ + ServiceInfo *service_info = GetServiceInfo(service); + if (service_info == nullptr) { + return ResultSmNotRegistered; + } + + /* Validate that the client pid is the mitm process. */ + if (service_info->mitm_pid != pid) { + return ResultSmNotAllowed; + } + + /* Free Mitm session info. */ + svcCloseHandle(service_info->mitm_port_h); + svcCloseHandle(service_info->mitm_query_h); + service_info->mitm_pid = InvalidProcessId; + return ResultSuccess; + } + + Result AcknowledgeMitmSession(u64 *out_pid, Handle *out_hnd, u64 pid, ServiceName service) { + /* Validate service name. */ + R_TRY(ValidateServiceName(service)); + + /* Check that the process is registered. */ + if (!IsInitialProcess(pid)) { + ProcessInfo *proc = GetProcessInfo(pid); + if (proc == nullptr) { + return ResultSmInvalidClient; + } + } + + /* Validate that the service exists. */ + ServiceInfo *service_info = GetServiceInfo(service); + if (service_info == nullptr) { + return ResultSmNotRegistered; + } + + /* Validate that the client pid is the mitm process, and that an acknowledgement is waiting. */ + if (service_info->mitm_pid != pid || !service_info->mitm_waiting_ack) { + return ResultSmNotAllowed; + } + + /* Copy to output. */ + *out_pid = service_info->mitm_waiting_ack_pid; + *out_hnd = service_info->mitm_fwd_sess_h; + + /* Clear pending acknowledgement. */ + service_info->mitm_fwd_sess_h = 0; + service_info->mitm_waiting_ack_pid = 0; + service_info->mitm_waiting_ack = false; + return ResultSuccess; + } + + Result AssociatePidTidForMitm(u64 pid, u64 tid) { + for (size_t i = 0; i < ServiceCountMax; i++) { + const ServiceInfo *service_info = &g_service_list[i]; + if (IsValidProcessId(service_info->mitm_pid)) { + /* Send association command to all mitm processes. */ + IpcCommand c; + ipcInitialize(&c); + struct { + u64 magic; + u64 cmd_id; + u64 pid; + u64 tid; + } *info = ((decltype(info))ipcPrepareHeader(&c, sizeof(*info))); + info->magic = SFCI_MAGIC; + info->cmd_id = 65001; + info->pid = pid; + info->tid = tid; + ipcDispatch(service_info->mitm_query_h); + } + } + return ResultSuccess; + } + + /* Dmnt record extensions. */ + Result GetServiceRecord(ServiceRecord *out, ServiceName service) { + /* Validate service name. */ + R_TRY(ValidateServiceName(service)); + + /* Validate that the service exists. */ + const ServiceInfo *service_info = GetServiceInfo(service); + if (service_info == nullptr) { + return ResultSmNotRegistered; + } + + GetServiceInfoRecord(out, service_info); + return ResultSuccess; + } + + Result ListServiceRecords(ServiceRecord *out, u64 *out_count, u64 offset, u64 max_count) { + u64 count = 0; + + for (size_t i = 0; i < ServiceCountMax && count < max_count; i++) { + const ServiceInfo *service_info = &g_service_list[i]; + if (service_info->name != InvalidServiceName) { + if (offset == 0) { + GetServiceInfoRecord(out++, service_info); + count++; + } else { + offset--; + } + } + } + + *out_count = 0; + return ResultSuccess; + } + + /* Deferral extension (works around FS bug). */ + Result EndInitialDefers() { + g_ended_initial_defers = true; + return ResultSuccess; + } + +}} diff --git a/stratosphere/sm/source/sm_service_manager.hpp b/stratosphere/sm/source/sm_service_manager.hpp new file mode 100644 index 000000000..b4ac5e0b8 --- /dev/null +++ b/stratosphere/sm/source/sm_service_manager.hpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include "sm_types.hpp" + +namespace sts { namespace sm { + + /* Initialization. */ + void InitializeRegistrationLists(); + + /* Process management. */ + Result RegisterProcess(u64 pid, const void *acid_sac, size_t acid_sac_size, const void *aci0_sac, size_t aci0_sac_size); + Result UnregisterProcess(u64 pid); + + /* Service management. */ + Result HasService(bool *out, ServiceName service); + Result GetServiceHandle(Handle *out, u64 pid, ServiceName service); + Result RegisterService(Handle *out, u64 pid, ServiceName service, size_t max_sessions, bool is_light); + Result RegisterServiceForSelf(Handle *out, ServiceName service, size_t max_sessions); + Result UnregisterService(u64 pid, ServiceName service); + + /* Mitm extensions. */ + Result HasMitm(bool *out, ServiceName service); + Result InstallMitm(Handle *out, Handle *out_query, u64 pid, ServiceName service); + Result UninstallMitm(u64 pid, ServiceName service); + Result AcknowledgeMitmSession(u64 *out_pid, Handle *out_hnd, u64 pid, ServiceName service); + Result AssociatePidTidForMitm(u64 pid, u64 tid); + + /* Dmnt record extensions. */ + Result GetServiceRecord(ServiceRecord *out, ServiceName service); + Result ListServiceRecords(ServiceRecord *out, u64 *out_count, u64 offset, u64 max_count); + + /* Deferral extension (works around FS bug). */ + Result EndInitialDefers(); + +}} diff --git a/stratosphere/sm/source/sm_types.hpp b/stratosphere/sm/source/sm_types.hpp index 28ff3beb4..9896e21a9 100644 --- a/stratosphere/sm/source/sm_types.hpp +++ b/stratosphere/sm/source/sm_types.hpp @@ -15,21 +15,57 @@ */ #pragma once -struct SmServiceName { - char name[sizeof(u64)]; -}; +#include -static_assert(__alignof__(SmServiceName) == 1, "SmServiceName definition!"); +namespace sts { namespace sm { -/* For Debug Monitor extensions. */ -struct SmServiceRecord { - u64 service_name; - u64 owner_pid; - u64 max_sessions; - u64 mitm_pid; - u64 mitm_waiting_ack_pid; - bool is_light; - bool mitm_waiting_ack; -}; + struct ServiceName { + static constexpr size_t MaxLength = 8; -static_assert(sizeof(SmServiceRecord) == 0x30, "SmServiceRecord definition!"); \ No newline at end of file + char name[MaxLength]; + + static constexpr ServiceName Encode(const char *name, size_t name_size) { + ServiceName out{}; + + for (size_t i = 0; i < MaxLength; i++) { + if (i < name_size) { + out.name[i] = name[i]; + } else { + out.name[i] = 0; + } + } + + return out; + } + + static constexpr ServiceName Encode(const char *name) { + return Encode(name, std::strlen(name)); + } + }; + static constexpr ServiceName InvalidServiceName = ServiceName::Encode(""); + static_assert(alignof(ServiceName) == 1, "ServiceName definition!"); + + inline bool operator==(const ServiceName &lhs, const ServiceName &rhs) { + return std::memcmp(&lhs, &rhs, sizeof(ServiceName)) == 0; + } + + inline bool operator!=(const ServiceName &lhs, const ServiceName &rhs) { + return !(lhs == rhs); + } + + /* For Debug Monitor extensions. */ + struct ServiceRecord { + ServiceName service; + u64 owner_pid; + u64 max_sessions; + u64 mitm_pid; + u64 mitm_waiting_ack_pid; + bool is_light; + bool mitm_waiting_ack; + }; + static_assert(sizeof(ServiceRecord) == 0x30, "ServiceRecord definition!"); + + /* For process validation. */ + static constexpr u64 InvalidProcessId = static_cast(-1ull); + +}} diff --git a/stratosphere/sm/source/sm_user_service.cpp b/stratosphere/sm/source/sm_user_service.cpp index 785ab9517..1fcb0f017 100644 --- a/stratosphere/sm/source/sm_user_service.cpp +++ b/stratosphere/sm/source/sm_user_service.cpp @@ -16,93 +16,58 @@ #include #include + #include "sm_user_service.hpp" -#include "sm_registration.hpp" +#include "sm_service_manager.hpp" -Result UserService::Initialize(PidDescriptor pid) { - this->pid = pid.pid; - this->has_initialized = true; - return ResultSuccess; -} +namespace sts { namespace sm { -Result UserService::GetService(Out out_h, SmServiceName service) { - Handle session_h = 0; - - if (!this->has_initialized) { - return ResultSmInvalidClient; + Result UserService::Initialize(PidDescriptor pid) { + this->pid = pid.pid; + this->has_initialized = true; + return ResultSuccess; } - R_TRY(Registration::GetServiceForPid(this->pid, smEncodeName(service.name), &session_h)); - - out_h.SetValue(session_h); - return ResultSuccess; -} - -Result UserService::RegisterService(Out out_h, SmServiceName service, u32 max_sessions, bool is_light) { - Handle service_h = 0; - - if (!this->has_initialized) { - return ResultSmInvalidClient; + Result UserService::EnsureInitialized() { + if (!this->has_initialized) { + return ResultSmInvalidClient; + } + return ResultSuccess; } - R_TRY(Registration::RegisterServiceForPid(this->pid, smEncodeName(service.name), max_sessions, (is_light & 1) != 0, &service_h)); - - out_h.SetValue(service_h); - return ResultSuccess; -} - -Result UserService::UnregisterService(SmServiceName service) { - if (!this->has_initialized) { - return ResultSmInvalidClient; + Result UserService::GetService(Out out_h, ServiceName service) { + R_TRY(this->EnsureInitialized()); + return sm::GetServiceHandle(out_h.GetHandlePointer(), this->pid, service); } - return Registration::UnregisterServiceForPid(this->pid, smEncodeName(service.name)); -} - -Result UserService::AtmosphereInstallMitm(Out srv_h, Out qry_h, SmServiceName service) { - Handle service_h = 0; - Handle query_h = 0; - - if (!this->has_initialized) { - return ResultSmInvalidClient; + Result UserService::RegisterService(Out out_h, ServiceName service, u32 max_sessions, bool is_light) { + R_TRY(this->EnsureInitialized()); + return sm::RegisterService(out_h.GetHandlePointer(), this->pid, service, max_sessions, is_light); } - R_TRY(Registration::InstallMitmForPid(this->pid, smEncodeName(service.name), &service_h, &query_h)); - - srv_h.SetValue(service_h); - qry_h.SetValue(query_h); - return ResultSuccess; -} - -Result UserService::AtmosphereUninstallMitm(SmServiceName service) { - if (!this->has_initialized) { - return ResultSmInvalidClient; + Result UserService::UnregisterService(ServiceName service) { + R_TRY(this->EnsureInitialized()); + return sm::UnregisterService(this->pid, service); } - return Registration::UninstallMitmForPid(this->pid, smEncodeName(service.name)); -} - -Result UserService::AtmosphereAcknowledgeMitmSession(Out client_pid, Out fwd_h, SmServiceName service) { - Handle out_fwd_h = 0; - - if (!this->has_initialized) { - return ResultSmInvalidClient; + Result UserService::AtmosphereInstallMitm(Out srv_h, Out qry_h, ServiceName service) { + R_TRY(this->EnsureInitialized()); + return sm::InstallMitm(srv_h.GetHandlePointer(), qry_h.GetHandlePointer(), this->pid, service); } - R_TRY(Registration::AcknowledgeMitmSessionForPid(this->pid, smEncodeName(service.name), &out_fwd_h, client_pid.GetPointer())); - - fwd_h.SetValue(out_fwd_h); - return ResultSuccess; -} - -Result UserService::AtmosphereAssociatePidTidForMitm(u64 pid, u64 tid) { - if (!this->has_initialized) { - return ResultSmInvalidClient; + Result UserService::AtmosphereUninstallMitm(ServiceName service) { + R_TRY(this->EnsureInitialized()); + return sm::UninstallMitm(this->pid, service); } - if (Registration::IsInitialProcess(pid)) { - return ResultSmNotAllowed; + Result UserService::AtmosphereAcknowledgeMitmSession(Out client_pid, Out fwd_h, ServiceName service) { + R_TRY(this->EnsureInitialized()); + return sm::AcknowledgeMitmSession(client_pid.GetPointer(), fwd_h.GetHandlePointer(), this->pid, service); } - return Registration::AssociatePidTidForMitm(pid, tid); -} + Result UserService::AtmosphereAssociatePidTidForMitm(u64 pid, u64 tid) { + R_TRY(this->EnsureInitialized()); + return sm::AssociatePidTidForMitm(pid, tid); + } + +}} diff --git a/stratosphere/sm/source/sm_user_service.hpp b/stratosphere/sm/source/sm_user_service.hpp index 3d1f50b4a..a939e7561 100644 --- a/stratosphere/sm/source/sm_user_service.hpp +++ b/stratosphere/sm/source/sm_user_service.hpp @@ -19,46 +19,52 @@ #include #include "sm_types.hpp" -enum UserServiceCmd { - User_Cmd_Initialize = 0, - User_Cmd_GetService = 1, - User_Cmd_RegisterService = 2, - User_Cmd_UnregisterService = 3, +namespace sts { namespace sm { - User_Cmd_AtmosphereInstallMitm = 65000, - User_Cmd_AtmosphereUninstallMitm = 65001, - User_Cmd_AtmosphereAssociatePidTidForMitm = 65002, - User_Cmd_AtmosphereAcknowledgeMitmSession = 65003, -}; + /* Command IDs. */ + enum UserServiceCmd { + User_Cmd_Initialize = 0, + User_Cmd_GetService = 1, + User_Cmd_RegisterService = 2, + User_Cmd_UnregisterService = 3, -class UserService final : public IServiceObject { - private: - u64 pid = U64_MAX; - bool has_initialized = false; + User_Cmd_AtmosphereInstallMitm = 65000, + User_Cmd_AtmosphereUninstallMitm = 65001, + User_Cmd_AtmosphereAssociatePidTidForMitm = 65002, + User_Cmd_AtmosphereAcknowledgeMitmSession = 65003, + }; - /* Actual commands. */ - virtual Result Initialize(PidDescriptor pid); - virtual Result GetService(Out out_h, SmServiceName service); - virtual Result RegisterService(Out out_h, SmServiceName service, u32 max_sessions, bool is_light); - virtual Result UnregisterService(SmServiceName service); + /* Service definition. */ + class UserService final : public IServiceObject { + private: + u64 pid = InvalidProcessId; + bool has_initialized = false; + private: + Result EnsureInitialized(); + public: + /* Official commands. */ + virtual Result Initialize(PidDescriptor pid); + virtual Result GetService(Out out_h, ServiceName service); + virtual Result RegisterService(Out out_h, ServiceName service, u32 max_sessions, bool is_light); + virtual Result UnregisterService(ServiceName service); - /* Atmosphere commands. */ - virtual Result AtmosphereInstallMitm(Out srv_h, Out qry_h, SmServiceName service); - virtual Result AtmosphereUninstallMitm(SmServiceName service); - virtual Result AtmosphereAssociatePidTidForMitm(u64 pid, u64 tid); - virtual Result AtmosphereAcknowledgeMitmSession(Out client_pid, Out fwd_h, SmServiceName service); - public: - DEFINE_SERVICE_DISPATCH_TABLE { - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), + /* Atmosphere commands. */ + virtual Result AtmosphereInstallMitm(Out srv_h, Out qry_h, ServiceName service); + virtual Result AtmosphereUninstallMitm(ServiceName service); + virtual Result AtmosphereAssociatePidTidForMitm(u64 pid, u64 tid); + virtual Result AtmosphereAcknowledgeMitmSession(Out client_pid, Out fwd_h, ServiceName service); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), -#ifdef SM_ENABLE_MITM - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), -#endif - }; -}; + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + }; + }; + +}} From 4be88c7180e7422585b20a7b2b1279652fd483b3 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 20 Jun 2019 18:24:33 -0700 Subject: [PATCH 2/6] sm: adjust Makefile --- stratosphere/sm/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stratosphere/sm/Makefile b/stratosphere/sm/Makefile index 10829cfd0..2de980b83 100644 --- a/stratosphere/sm/Makefile +++ b/stratosphere/sm/Makefile @@ -41,7 +41,7 @@ ARCH := -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE CFLAGS := -g -Wall -O2 -ffunction-sections \ $(ARCH) $(DEFINES) -CFLAGS += $(INCLUDE) -D__SWITCH__ -DSM_ENABLE_MITM -DSM_ENABLE_INIT_DEFERS -DSM_MINIMUM_SESSION_LIMIT=8 +CFLAGS += $(INCLUDE) -D__SWITCH__ -DSM_MINIMUM_SESSION_LIMIT=8 CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++17 From e86e1588e31402dc12a1c1c82ab8893aab381047 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 20 Jun 2019 18:32:00 -0700 Subject: [PATCH 3/6] Simplify namespacing --- stratosphere/sm/source/sm_dmnt_service.cpp | 4 ++-- stratosphere/sm/source/sm_dmnt_service.hpp | 4 ++-- stratosphere/sm/source/sm_manager_service.cpp | 4 ++-- stratosphere/sm/source/sm_manager_service.hpp | 4 ++-- stratosphere/sm/source/sm_service_manager.cpp | 4 ++-- stratosphere/sm/source/sm_service_manager.hpp | 4 ++-- stratosphere/sm/source/sm_types.hpp | 4 ++-- stratosphere/sm/source/sm_user_service.cpp | 4 ++-- stratosphere/sm/source/sm_user_service.hpp | 4 ++-- 9 files changed, 18 insertions(+), 18 deletions(-) diff --git a/stratosphere/sm/source/sm_dmnt_service.cpp b/stratosphere/sm/source/sm_dmnt_service.cpp index 5cffbb0d4..6245c4dc7 100644 --- a/stratosphere/sm/source/sm_dmnt_service.cpp +++ b/stratosphere/sm/source/sm_dmnt_service.cpp @@ -20,7 +20,7 @@ #include "sm_dmnt_service.hpp" #include "sm_service_manager.hpp" -namespace sts { namespace sm { +namespace sts::sm { Result DmntService::AtmosphereGetRecord(Out record, ServiceName service) { return sm::GetServiceRecord(record.GetPointer(), service); @@ -34,4 +34,4 @@ namespace sts { namespace sm { record_size.SetValue(sizeof(ServiceRecord)); } -}} +} diff --git a/stratosphere/sm/source/sm_dmnt_service.hpp b/stratosphere/sm/source/sm_dmnt_service.hpp index 1a3b9ca47..419e4462d 100644 --- a/stratosphere/sm/source/sm_dmnt_service.hpp +++ b/stratosphere/sm/source/sm_dmnt_service.hpp @@ -19,7 +19,7 @@ #include #include "sm_types.hpp" -namespace sts { namespace sm { +namespace sts::sm { /* Command IDs. */ enum DmntServiceCmd { @@ -43,4 +43,4 @@ namespace sts { namespace sm { }; }; -}} +} diff --git a/stratosphere/sm/source/sm_manager_service.cpp b/stratosphere/sm/source/sm_manager_service.cpp index e132706dd..55bcb2f32 100644 --- a/stratosphere/sm/source/sm_manager_service.cpp +++ b/stratosphere/sm/source/sm_manager_service.cpp @@ -20,7 +20,7 @@ #include "sm_manager_service.hpp" #include "sm_service_manager.hpp" -namespace sts { namespace sm { +namespace sts::sm { Result ManagerService::RegisterProcess(u64 pid, InBuffer acid_sac, InBuffer aci0_sac) { return sm::RegisterProcess(pid, acid_sac.buffer, acid_sac.num_elements, aci0_sac.buffer, aci0_sac.num_elements); @@ -38,4 +38,4 @@ namespace sts { namespace sm { R_ASSERT(sm::HasMitm(out.GetPointer(), service)); } -}} +} diff --git a/stratosphere/sm/source/sm_manager_service.hpp b/stratosphere/sm/source/sm_manager_service.hpp index c8d7f5763..49e344182 100644 --- a/stratosphere/sm/source/sm_manager_service.hpp +++ b/stratosphere/sm/source/sm_manager_service.hpp @@ -19,7 +19,7 @@ #include #include "sm_types.hpp" -namespace sts { namespace sm { +namespace sts::sm { /* Command IDs. */ enum ManagerServiceCmd { @@ -48,4 +48,4 @@ namespace sts { namespace sm { }; }; -}} +} diff --git a/stratosphere/sm/source/sm_service_manager.cpp b/stratosphere/sm/source/sm_service_manager.cpp index 8b633664b..d53c46955 100644 --- a/stratosphere/sm/source/sm_service_manager.cpp +++ b/stratosphere/sm/source/sm_service_manager.cpp @@ -19,7 +19,7 @@ #include "sm_service_manager.hpp" -namespace sts { namespace sm { +namespace sts::sm { /* Anonymous namespace for implementation details. */ namespace { @@ -720,4 +720,4 @@ namespace sts { namespace sm { return ResultSuccess; } -}} +} diff --git a/stratosphere/sm/source/sm_service_manager.hpp b/stratosphere/sm/source/sm_service_manager.hpp index b4ac5e0b8..2eb729ab9 100644 --- a/stratosphere/sm/source/sm_service_manager.hpp +++ b/stratosphere/sm/source/sm_service_manager.hpp @@ -18,7 +18,7 @@ #include #include "sm_types.hpp" -namespace sts { namespace sm { +namespace sts::sm { /* Initialization. */ void InitializeRegistrationLists(); @@ -48,4 +48,4 @@ namespace sts { namespace sm { /* Deferral extension (works around FS bug). */ Result EndInitialDefers(); -}} +} diff --git a/stratosphere/sm/source/sm_types.hpp b/stratosphere/sm/source/sm_types.hpp index 9896e21a9..57b792d8a 100644 --- a/stratosphere/sm/source/sm_types.hpp +++ b/stratosphere/sm/source/sm_types.hpp @@ -17,7 +17,7 @@ #pragma once #include -namespace sts { namespace sm { +namespace sts::sm { struct ServiceName { static constexpr size_t MaxLength = 8; @@ -68,4 +68,4 @@ namespace sts { namespace sm { /* For process validation. */ static constexpr u64 InvalidProcessId = static_cast(-1ull); -}} +} diff --git a/stratosphere/sm/source/sm_user_service.cpp b/stratosphere/sm/source/sm_user_service.cpp index 1fcb0f017..49b4f4ce9 100644 --- a/stratosphere/sm/source/sm_user_service.cpp +++ b/stratosphere/sm/source/sm_user_service.cpp @@ -20,7 +20,7 @@ #include "sm_user_service.hpp" #include "sm_service_manager.hpp" -namespace sts { namespace sm { +namespace sts::sm { Result UserService::Initialize(PidDescriptor pid) { this->pid = pid.pid; @@ -70,4 +70,4 @@ namespace sts { namespace sm { return sm::AssociatePidTidForMitm(pid, tid); } -}} +} diff --git a/stratosphere/sm/source/sm_user_service.hpp b/stratosphere/sm/source/sm_user_service.hpp index a939e7561..a1a461856 100644 --- a/stratosphere/sm/source/sm_user_service.hpp +++ b/stratosphere/sm/source/sm_user_service.hpp @@ -19,7 +19,7 @@ #include #include "sm_types.hpp" -namespace sts { namespace sm { +namespace sts::sm { /* Command IDs. */ enum UserServiceCmd { @@ -67,4 +67,4 @@ namespace sts { namespace sm { }; }; -}} +} From 2357bc70a72e071366eee9be6905c7dbf2fbcf58 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 20 Jun 2019 23:34:59 -0700 Subject: [PATCH 4/6] Implementation cleanup --- stratosphere/sm/source/sm_dmnt_service.hpp | 20 +-- stratosphere/sm/source/sm_main.cpp | 5 +- stratosphere/sm/source/sm_manager_service.hpp | 26 +-- stratosphere/sm/source/sm_service_manager.cpp | 160 ++++++++++-------- stratosphere/sm/source/sm_service_manager.hpp | 3 - stratosphere/sm/source/sm_user_service.hpp | 42 ++--- 6 files changed, 136 insertions(+), 120 deletions(-) diff --git a/stratosphere/sm/source/sm_dmnt_service.hpp b/stratosphere/sm/source/sm_dmnt_service.hpp index 419e4462d..70a3585cd 100644 --- a/stratosphere/sm/source/sm_dmnt_service.hpp +++ b/stratosphere/sm/source/sm_dmnt_service.hpp @@ -21,15 +21,15 @@ namespace sts::sm { - /* Command IDs. */ - enum DmntServiceCmd { - Dmnt_Cmd_AtmosphereGetRecord = 65000, - Dmnt_Cmd_AtmosphereListRecords = 65001, - Dmnt_Cmd_AtmosphereGetRecordSize = 65002, - }; - /* Service definition. */ class DmntService final : public IServiceObject { + protected: + /* Command IDs. */ + enum class CommandId { + AtmosphereGetRecord = 65000, + AtmosphereListRecords = 65001, + AtmosphereGetRecordSize = 65002, + }; private: /* Actual commands. */ virtual Result AtmosphereGetRecord(Out record, ServiceName service); @@ -37,9 +37,9 @@ namespace sts::sm { virtual void AtmosphereGetRecordSize(Out record_size); public: DEFINE_SERVICE_DISPATCH_TABLE { - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), }; }; diff --git a/stratosphere/sm/source/sm_main.cpp b/stratosphere/sm/source/sm_main.cpp index 645978cbb..3dac7bf64 100644 --- a/stratosphere/sm/source/sm_main.cpp +++ b/stratosphere/sm/source/sm_main.cpp @@ -77,10 +77,7 @@ void __appExit(void) { int main(int argc, char **argv) { - /* Initialize service manager. */ - sts::sm::InitializeRegistrationLists(); - - /* TODO: What's a good timeout value to use here? */ + /* Create service waitable manager. */ static auto s_server_manager = WaitableManager(1); /* Create sm:, (and thus allow things to register to it). */ diff --git a/stratosphere/sm/source/sm_manager_service.hpp b/stratosphere/sm/source/sm_manager_service.hpp index 49e344182..c63af81e5 100644 --- a/stratosphere/sm/source/sm_manager_service.hpp +++ b/stratosphere/sm/source/sm_manager_service.hpp @@ -21,17 +21,17 @@ namespace sts::sm { - /* Command IDs. */ - enum ManagerServiceCmd { - Manager_Cmd_RegisterProcess = 0, - Manager_Cmd_UnregisterProcess = 1, - - Manager_Cmd_AtmosphereEndInitDefers = 65000, - Manager_Cmd_AtmosphereHasMitm = 65001, - }; - /* Service definition. */ class ManagerService final : public IServiceObject { + protected: + /* Command IDs. */ + enum class CommandId { + RegisterProcess = 0, + UnregisterProcess = 1, + + AtmosphereEndInitDefers = 65000, + AtmosphereHasMitm = 65001, + }; private: /* Actual commands. */ virtual Result RegisterProcess(u64 pid, InBuffer acid_sac, InBuffer aci0_sac); @@ -40,11 +40,11 @@ namespace sts::sm { virtual void AtmosphereHasMitm(Out out, ServiceName service); public: DEFINE_SERVICE_DISPATCH_TABLE { - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), }; }; diff --git a/stratosphere/sm/source/sm_service_manager.cpp b/stratosphere/sm/source/sm_service_manager.cpp index d53c46955..cf771e951 100644 --- a/stratosphere/sm/source/sm_service_manager.cpp +++ b/stratosphere/sm/source/sm_service_manager.cpp @@ -33,6 +33,16 @@ namespace sts::sm { u64 pid; size_t access_control_size; u8 access_control[AccessControlSizeMax]; + + ProcessInfo() { + this->Free(); + } + + void Free() { + this->pid = InvalidProcessId; + this->access_control_size = 0; + std::memset(this->access_control, 0, sizeof(this->access_control)); + } }; struct ServiceInfo { @@ -53,19 +63,73 @@ namespace sts::sm { bool mitm_waiting_ack; u64 mitm_waiting_ack_pid; Handle mitm_fwd_sess_h; + + ServiceInfo() { + this->Free(); + } + + void Free() { + /* Close any open handles. */ + if (this->port_h != INVALID_HANDLE) { + svcCloseHandle(this->port_h); + } + if (this->mitm_port_h != INVALID_HANDLE) { + svcCloseHandle(this->mitm_port_h); + } + if (this->mitm_query_h != INVALID_HANDLE) { + svcCloseHandle(this->mitm_query_h); + } + + /* Reset all members. */ + this->name = InvalidServiceName; + this->owner_pid = InvalidProcessId; + this->port_h = INVALID_HANDLE; + this->max_sessions = 0; + this->is_light = false; + this->mitm_pid = InvalidProcessId; + this->mitm_port_h = INVALID_HANDLE; + this->mitm_query_h = INVALID_HANDLE; + this->mitm_waiting_ack = false; + this->mitm_waiting_ack_pid = InvalidProcessId; + this->mitm_fwd_sess_h = INVALID_HANDLE; + } + + void FreeMitm() { + /* Close mitm handles. */ + if (this->mitm_port_h != INVALID_HANDLE) { + svcCloseHandle(this->mitm_port_h); + } + if (this->mitm_query_h != INVALID_HANDLE) { + svcCloseHandle(this->mitm_query_h); + } + + /* Reset mitm members. */ + this->mitm_pid = InvalidProcessId; + this->mitm_port_h = INVALID_HANDLE; + this->mitm_query_h = INVALID_HANDLE; + } + + void AcknowledgeMitmSession(u64 *out_pid, Handle *out_hnd) { + /* Copy to output. */ + *out_pid = this->mitm_waiting_ack_pid; + *out_hnd = this->mitm_fwd_sess_h; + this->mitm_waiting_ack = false; + this->mitm_waiting_ack_pid = InvalidProcessId; + this->mitm_fwd_sess_h = INVALID_HANDLE; + } }; class AccessControlEntry { private: const u8 *entry; - size_t size; + size_t capacity; public: - AccessControlEntry(const void *e, size_t sz) : entry(reinterpret_cast(e)), size(sz) { + AccessControlEntry(const void *e, size_t c) : entry(reinterpret_cast(e)), capacity(c) { /* ... */ } AccessControlEntry GetNextEntry() const { - return AccessControlEntry(this->entry + this->GetSize(), this->size - this->GetSize()); + return AccessControlEntry(this->entry + this->GetSize(), this->capacity - this->GetSize()); } size_t GetSize() const { @@ -90,12 +154,12 @@ namespace sts::sm { bool IsValid() const { /* Validate that we can access data. */ - if (this->entry == nullptr || this->size == 0) { + if (this->entry == nullptr || this->capacity == 0) { return false; } /* Validate that the size is correct. */ - return this->GetSize() <= this->size; + return this->GetSize() <= this->capacity; } }; @@ -109,11 +173,15 @@ namespace sts::sm { public: InitialProcessIdLimits() { if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500) { - /* On 5.0.0+, we can get precise limits from the kernel. */ + /* On 5.0.0+, we can get precise limits from svcGetSystemInfo. */ R_ASSERT(svcGetSystemInfo(&this->min, 2, 0, 0)); R_ASSERT(svcGetSystemInfo(&this->max, 2, 0, 1)); + } else if (GetRuntimeFirmwareVersion() >= FirmwareVersion_400) { + /* On 4.0.0-4.1.0, we can get the precise limits from normal svcGetInfo. */ + R_ASSERT(svcGetInfo(&this->min, 19, 0, 0)); + R_ASSERT(svcGetInfo(&this->max, 19, 0, 1)); } else { - /* On < 5.0.0, we just use hardcoded extents. */ + /* On < 4.0.0, we just use hardcoded extents. */ this->min = InitialProcessIdMin; this->max = InitialProcessIdMax; } @@ -152,11 +220,6 @@ namespace sts::sm { return GetProcessInfo(InvalidProcessId); } - void FreeProcessInfo(ProcessInfo *process_info) { - std::memset(process_info, 0, sizeof(*process_info)); - process_info->pid = InvalidProcessId; - } - bool HasProcessInfo(u64 pid) { return GetProcessInfo(pid) != nullptr; } @@ -174,6 +237,10 @@ namespace sts::sm { return GetServiceInfo(InvalidServiceName); } + bool HasServiceInfo(ServiceName service) { + return GetServiceInfo(service) != nullptr; + } + void GetServiceInfoRecord(ServiceRecord *out_record, const ServiceInfo *service_info) { out_record->service = service_info->name; out_record->owner_pid = service_info->owner_pid; @@ -184,26 +251,6 @@ namespace sts::sm { out_record->mitm_waiting_ack = service_info->mitm_waiting_ack; } - void FreeServiceInfo(ServiceInfo *service_info) { - if (service_info->port_h != INVALID_HANDLE) { - svcCloseHandle(service_info->port_h); - } - if (service_info->mitm_port_h != INVALID_HANDLE) { - svcCloseHandle(service_info->mitm_port_h); - } - if (service_info->mitm_query_h != INVALID_HANDLE) { - svcCloseHandle(service_info->mitm_query_h); - } - std::memset(service_info, 0, sizeof(*service_info)); - service_info->owner_pid = InvalidProcessId; - service_info->mitm_pid = InvalidProcessId; - service_info->mitm_waiting_ack_pid = InvalidProcessId; - } - - bool HasServiceInfo(ServiceName service) { - return GetServiceInfo(service) != nullptr; - } - Result ValidateAccessControl(AccessControlEntry access_control, ServiceName service, bool is_host, bool is_wildcard) { /* Iterate over all entries in the access control, checking to see if we have a match. */ while (access_control.IsValid()) { @@ -244,12 +291,11 @@ namespace sts::sm { } /* Get name length. */ - size_t name_len = 1; - while (name_len < sizeof(service)) { + size_t name_len; + for (name_len = 1; name_len < sizeof(service); name_len++) { if (service.name[name_len] == 0) { break; } - name_len++; } /* Names must be all-zero after they end. */ @@ -332,19 +378,15 @@ namespace sts::sm { Result GetServiceHandleImpl(Handle *out, ServiceInfo *service_info, u64 pid) { /* Clear handle output. */ - *out = 0; + *out = INVALID_HANDLE; /* If not mitm'd or mitm service is requesting, get normal session. */ if (!IsValidProcessId(service_info->mitm_pid) || service_info->mitm_pid == pid) { return svcConnectToPort(out, service_info->port_h); } - /* We're mitm'd. */ - if (R_FAILED(GetMitmServiceHandleImpl(out, service_info, pid))) { - /* If the Mitm service is dead, just give a normal session. */ - return svcConnectToPort(out, service_info->port_h); - } - + /* We're mitm'd. Assert, because mitm service host dead is an error state. */ + R_ASSERT(GetMitmServiceHandleImpl(out, service_info, pid)); return ResultSuccess; } @@ -384,18 +426,6 @@ namespace sts::sm { } } - /* Initialization. */ - void InitializeRegistrationLists() { - /* Free all services. */ - for (size_t i = 0; i < ServiceCountMax; i++) { - FreeServiceInfo(&g_service_list[i]); - } - /* Free all processes. */ - for (size_t i = 0; i < ProcessCountMax; i++) { - FreeProcessInfo(&g_process_list[i]); - } - } - /* Process management. */ Result RegisterProcess(u64 pid, const void *acid_sac, size_t acid_sac_size, const void *aci0_sac, size_t aci0_sac_size) { /* Check that access control will fit in the ServiceInfo. */ @@ -429,7 +459,7 @@ namespace sts::sm { return ResultSmInvalidClient; } - FreeProcessInfo(proc); + proc->Free(); return ResultSuccess; } @@ -530,7 +560,7 @@ namespace sts::sm { } /* Unregister the service. */ - FreeServiceInfo(service_info); + service_info->Free(); return ResultSuccess; } @@ -571,8 +601,8 @@ namespace sts::sm { } /* Always clear output. */ - *out = 0; - *out_query = 0; + *out = INVALID_HANDLE; + *out_query = INVALID_HANDLE; /* Create mitm handles. */ Handle hnd = 0; @@ -617,9 +647,7 @@ namespace sts::sm { } /* Free Mitm session info. */ - svcCloseHandle(service_info->mitm_port_h); - svcCloseHandle(service_info->mitm_query_h); - service_info->mitm_pid = InvalidProcessId; + service_info->FreeMitm(); return ResultSuccess; } @@ -646,14 +674,8 @@ namespace sts::sm { return ResultSmNotAllowed; } - /* Copy to output. */ - *out_pid = service_info->mitm_waiting_ack_pid; - *out_hnd = service_info->mitm_fwd_sess_h; - - /* Clear pending acknowledgement. */ - service_info->mitm_fwd_sess_h = 0; - service_info->mitm_waiting_ack_pid = 0; - service_info->mitm_waiting_ack = false; + /* Acknowledge. */ + service_info->AcknowledgeMitmSession(out_pid, out_hnd); return ResultSuccess; } diff --git a/stratosphere/sm/source/sm_service_manager.hpp b/stratosphere/sm/source/sm_service_manager.hpp index 2eb729ab9..9bac407a6 100644 --- a/stratosphere/sm/source/sm_service_manager.hpp +++ b/stratosphere/sm/source/sm_service_manager.hpp @@ -20,9 +20,6 @@ namespace sts::sm { - /* Initialization. */ - void InitializeRegistrationLists(); - /* Process management. */ Result RegisterProcess(u64 pid, const void *acid_sac, size_t acid_sac_size, const void *aci0_sac, size_t aci0_sac_size); Result UnregisterProcess(u64 pid); diff --git a/stratosphere/sm/source/sm_user_service.hpp b/stratosphere/sm/source/sm_user_service.hpp index a1a461856..54c060c68 100644 --- a/stratosphere/sm/source/sm_user_service.hpp +++ b/stratosphere/sm/source/sm_user_service.hpp @@ -21,21 +21,21 @@ namespace sts::sm { - /* Command IDs. */ - enum UserServiceCmd { - User_Cmd_Initialize = 0, - User_Cmd_GetService = 1, - User_Cmd_RegisterService = 2, - User_Cmd_UnregisterService = 3, - - User_Cmd_AtmosphereInstallMitm = 65000, - User_Cmd_AtmosphereUninstallMitm = 65001, - User_Cmd_AtmosphereAssociatePidTidForMitm = 65002, - User_Cmd_AtmosphereAcknowledgeMitmSession = 65003, - }; - /* Service definition. */ class UserService final : public IServiceObject { + protected: + /* Command IDs. */ + enum class CommandId { + Initialize = 0, + GetService = 1, + RegisterService = 2, + UnregisterService = 3, + + AtmosphereInstallMitm = 65000, + AtmosphereUninstallMitm = 65001, + AtmosphereAssociatePidTidForMitm = 65002, + AtmosphereAcknowledgeMitmSession = 65003, + }; private: u64 pid = InvalidProcessId; bool has_initialized = false; @@ -55,15 +55,15 @@ namespace sts::sm { virtual Result AtmosphereAcknowledgeMitmSession(Out client_pid, Out fwd_h, ServiceName service); public: DEFINE_SERVICE_DISPATCH_TABLE { - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), }; }; From d986ffa15387694339b0a537528a762b10b06ea3 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 20 Jun 2019 23:51:15 -0700 Subject: [PATCH 5/6] sm: use AutoHandles --- stratosphere/libstratosphere | 2 +- stratosphere/sm/source/sm_service_manager.cpp | 93 ++++++++----------- 2 files changed, 40 insertions(+), 55 deletions(-) diff --git a/stratosphere/libstratosphere b/stratosphere/libstratosphere index 4ccee4257..0c26276b2 160000 --- a/stratosphere/libstratosphere +++ b/stratosphere/libstratosphere @@ -1 +1 @@ -Subproject commit 4ccee4257763373c8e8dd5453246a592482f9a86 +Subproject commit 0c26276b21e4cf0f7a0665c0280b3888ebfbd1af diff --git a/stratosphere/sm/source/sm_service_manager.cpp b/stratosphere/sm/source/sm_service_manager.cpp index cf771e951..ab26726db 100644 --- a/stratosphere/sm/source/sm_service_manager.cpp +++ b/stratosphere/sm/source/sm_service_manager.cpp @@ -48,7 +48,7 @@ namespace sts::sm { struct ServiceInfo { ServiceName name; u64 owner_pid; - Handle port_h; + AutoHandle port_h; /* Debug. */ u64 max_sessions; @@ -56,13 +56,13 @@ namespace sts::sm { /* Mitm Extension. */ u64 mitm_pid; - Handle mitm_port_h; - Handle mitm_query_h; + AutoHandle mitm_port_h; + AutoHandle mitm_query_h; /* Acknowledgement members. */ bool mitm_waiting_ack; u64 mitm_waiting_ack_pid; - Handle mitm_fwd_sess_h; + AutoHandle mitm_fwd_sess_h; ServiceInfo() { this->Free(); @@ -70,52 +70,36 @@ namespace sts::sm { void Free() { /* Close any open handles. */ - if (this->port_h != INVALID_HANDLE) { - svcCloseHandle(this->port_h); - } - if (this->mitm_port_h != INVALID_HANDLE) { - svcCloseHandle(this->mitm_port_h); - } - if (this->mitm_query_h != INVALID_HANDLE) { - svcCloseHandle(this->mitm_query_h); - } + this->port_h.Clear(); + this->mitm_port_h.Clear(); + this->mitm_query_h.Clear(); + this->mitm_fwd_sess_h.Clear(); - /* Reset all members. */ + /* Reset all other members. */ this->name = InvalidServiceName; this->owner_pid = InvalidProcessId; - this->port_h = INVALID_HANDLE; this->max_sessions = 0; this->is_light = false; this->mitm_pid = InvalidProcessId; - this->mitm_port_h = INVALID_HANDLE; - this->mitm_query_h = INVALID_HANDLE; this->mitm_waiting_ack = false; this->mitm_waiting_ack_pid = InvalidProcessId; - this->mitm_fwd_sess_h = INVALID_HANDLE; } void FreeMitm() { /* Close mitm handles. */ - if (this->mitm_port_h != INVALID_HANDLE) { - svcCloseHandle(this->mitm_port_h); - } - if (this->mitm_query_h != INVALID_HANDLE) { - svcCloseHandle(this->mitm_query_h); - } + this->mitm_port_h.Clear(); + this->mitm_query_h.Clear(); /* Reset mitm members. */ this->mitm_pid = InvalidProcessId; - this->mitm_port_h = INVALID_HANDLE; - this->mitm_query_h = INVALID_HANDLE; } void AcknowledgeMitmSession(u64 *out_pid, Handle *out_hnd) { /* Copy to output. */ *out_pid = this->mitm_waiting_ack_pid; - *out_hnd = this->mitm_fwd_sess_h; + *out_hnd = this->mitm_fwd_sess_h.Move(); this->mitm_waiting_ack = false; this->mitm_waiting_ack_pid = InvalidProcessId; - this->mitm_fwd_sess_h = INVALID_HANDLE; } }; @@ -340,7 +324,7 @@ namespace sts::sm { info->magic = SFCI_MAGIC; info->cmd_id = 65000; info->pid = pid; - R_TRY(ipcDispatch(service_info->mitm_query_h)); + R_TRY(ipcDispatch(service_info->mitm_query_h.Get())); } /* Parse response to see if we should mitm. */ @@ -360,15 +344,17 @@ namespace sts::sm { /* If we shouldn't mitm, give normal session. */ if (!should_mitm) { - return svcConnectToPort(out, service_info->port_h); + return svcConnectToPort(out, service_info->port_h.Get()); } - /* Create both handles. If the second fails, close the first to prevent leak. */ - R_TRY(svcConnectToPort(&service_info->mitm_fwd_sess_h, service_info->port_h)); - R_TRY_CLEANUP(svcConnectToPort(out, service_info->mitm_port_h), { - svcCloseHandle(service_info->mitm_fwd_sess_h); - service_info->mitm_fwd_sess_h = 0; - }); + /* Create both handles. */ + { + AutoHandle fwd_hnd, hnd; + R_TRY(svcConnectToPort(fwd_hnd.GetPointer(), service_info->port_h.Get())); + R_TRY(svcConnectToPort(hnd.GetPointer(), service_info->mitm_port_h.Get())); + service_info->mitm_fwd_sess_h = std::move(fwd_hnd); + *out = hnd.Move(); + } service_info->mitm_waiting_ack_pid = pid; service_info->mitm_waiting_ack = true; @@ -382,7 +368,7 @@ namespace sts::sm { /* If not mitm'd or mitm service is requesting, get normal session. */ if (!IsValidProcessId(service_info->mitm_pid) || service_info->mitm_pid == pid) { - return svcConnectToPort(out, service_info->port_h); + return svcConnectToPort(out, service_info->port_h.Get()); } /* We're mitm'd. Assert, because mitm service host dead is an error state. */ @@ -413,8 +399,8 @@ namespace sts::sm { } /* Create the new service. */ - *out = 0; - R_TRY(svcCreatePort(out, &free_service->port_h, max_sessions, is_light, free_service->name.name)); + *out = INVALID_HANDLE; + R_TRY(svcCreatePort(out, free_service->port_h.GetPointerAndClear(), max_sessions, is_light, free_service->name.name)); /* Save info. */ free_service->name = service; @@ -482,7 +468,7 @@ namespace sts::sm { return ResultSmNotAllowed; } - /* Check that the process is registered and allowed to register the service. */ + /* Check that the process is registered and allowed to get the service. */ if (!IsInitialProcess(pid)) { ProcessInfo *proc = GetProcessInfo(pid); if (proc == nullptr) { @@ -605,20 +591,19 @@ namespace sts::sm { *out_query = INVALID_HANDLE; /* Create mitm handles. */ - Handle hnd = 0; - Handle qry_hnd = 0; - u64 x = 0; - R_TRY(svcCreatePort(&hnd, &service_info->mitm_port_h, service_info->max_sessions, service_info->is_light, reinterpret_cast(&x))); - R_TRY_CLEANUP(svcCreateSession(&qry_hnd, &service_info->mitm_query_h, 0, 0), { - svcCloseHandle(hnd); - svcCloseHandle(service_info->mitm_port_h); - service_info->mitm_port_h = 0; - }); - service_info->mitm_pid = pid; + { + AutoHandle hnd, port_hnd, qry_hnd, mitm_qry_hnd; + u64 x = 0; + R_TRY(svcCreatePort(hnd.GetPointer(), port_hnd.GetPointer(), service_info->max_sessions, service_info->is_light, reinterpret_cast(&x))); + R_TRY(svcCreateSession(qry_hnd.GetPointer(), mitm_qry_hnd.GetPointer(), 0, 0)); - /* Set output. */ - *out = hnd; - *out_query = qry_hnd; + /* Copy to output. */ + service_info->mitm_pid = pid; + service_info->mitm_port_h = std::move(port_hnd); + service_info->mitm_query_h = std::move(mitm_qry_hnd); + *out = hnd.Move(); + *out_query = qry_hnd.Move(); + } return ResultSuccess; } @@ -696,7 +681,7 @@ namespace sts::sm { info->cmd_id = 65001; info->pid = pid; info->tid = tid; - ipcDispatch(service_info->mitm_query_h); + ipcDispatch(service_info->mitm_query_h.Get()); } } return ResultSuccess; From 53d7281e6602fb27731781d53a59137985c53a16 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Fri, 21 Jun 2019 17:37:01 -0700 Subject: [PATCH 6/6] sm: use enums for GetInfo --- stratosphere/sm/source/sm_main.cpp | 16 ++++++++-------- stratosphere/sm/source/sm_service_manager.cpp | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/stratosphere/sm/source/sm_main.cpp b/stratosphere/sm/source/sm_main.cpp index 3dac7bf64..dd8f3aebb 100644 --- a/stratosphere/sm/source/sm_main.cpp +++ b/stratosphere/sm/source/sm_main.cpp @@ -54,15 +54,15 @@ void __libnx_exception_handler(ThreadExceptionDump *ctx) { void __libnx_initheap(void) { - void* addr = nx_inner_heap; - size_t size = nx_inner_heap_size; + void* addr = nx_inner_heap; + size_t size = nx_inner_heap_size; - /* Newlib */ - extern char* fake_heap_start; - extern char* fake_heap_end; + /* Newlib */ + extern char* fake_heap_start; + extern char* fake_heap_end; - fake_heap_start = (char*)addr; - fake_heap_end = (char*)addr + size; + fake_heap_start = (char*)addr; + fake_heap_end = (char*)addr + size; } void __appInit(void) { @@ -100,5 +100,5 @@ int main(int argc, char **argv) s_server_manager.Process(); /* Cleanup. */ - return 0; + return 0; } diff --git a/stratosphere/sm/source/sm_service_manager.cpp b/stratosphere/sm/source/sm_service_manager.cpp index ab26726db..7dee60a35 100644 --- a/stratosphere/sm/source/sm_service_manager.cpp +++ b/stratosphere/sm/source/sm_service_manager.cpp @@ -158,12 +158,12 @@ namespace sts::sm { InitialProcessIdLimits() { if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500) { /* On 5.0.0+, we can get precise limits from svcGetSystemInfo. */ - R_ASSERT(svcGetSystemInfo(&this->min, 2, 0, 0)); - R_ASSERT(svcGetSystemInfo(&this->max, 2, 0, 1)); + R_ASSERT(svcGetSystemInfo(&this->min, SystemInfoType_InitialProcessIdRange, INVALID_HANDLE, InitialProcessIdRangeInfo_Minimum)); + R_ASSERT(svcGetSystemInfo(&this->max, SystemInfoType_InitialProcessIdRange, INVALID_HANDLE, InitialProcessIdRangeInfo_Maximum)); } else if (GetRuntimeFirmwareVersion() >= FirmwareVersion_400) { /* On 4.0.0-4.1.0, we can get the precise limits from normal svcGetInfo. */ - R_ASSERT(svcGetInfo(&this->min, 19, 0, 0)); - R_ASSERT(svcGetInfo(&this->max, 19, 0, 1)); + R_ASSERT(svcGetInfo(&this->min, InfoType_InitialProcessIdRange, INVALID_HANDLE, InitialProcessIdRangeInfo_Minimum)); + R_ASSERT(svcGetInfo(&this->max, InfoType_InitialProcessIdRange, INVALID_HANDLE, InitialProcessIdRangeInfo_Maximum)); } else { /* On < 4.0.0, we just use hardcoded extents. */ this->min = InitialProcessIdMin;