From 9b480e475753ebb686ad6e8e0925ddc72dd31467 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 9 May 2023 15:07:40 -0700 Subject: [PATCH] pm: add api for ams.mitm to steal application memory --- .../pm/impl/pm_shell_interface.hpp | 49 ++++++----- .../include/stratosphere/pm/pm_shell_api.hpp | 2 + .../source/pm/pm_ams.os.horizon.c | 6 ++ .../source/pm/pm_ams.os.horizon.h | 2 + .../source/pm/pm_shell_api.cpp | 5 ++ .../pm/source/impl/pm_process_manager.cpp | 4 + .../pm/source/impl/pm_process_manager.hpp | 1 + .../pm/source/impl/pm_resource_manager.cpp | 88 +++++++++++++------ .../pm/source/impl/pm_resource_manager.hpp | 2 + stratosphere/pm/source/pm_shell_service.cpp | 4 + stratosphere/pm/source/pm_shell_service.hpp | 3 + 11 files changed, 114 insertions(+), 52 deletions(-) diff --git a/libraries/libstratosphere/include/stratosphere/pm/impl/pm_shell_interface.hpp b/libraries/libstratosphere/include/stratosphere/pm/impl/pm_shell_interface.hpp index 1da93af4c..ff19597b6 100644 --- a/libraries/libstratosphere/include/stratosphere/pm/impl/pm_shell_interface.hpp +++ b/libraries/libstratosphere/include/stratosphere/pm/impl/pm_shell_interface.hpp @@ -19,31 +19,34 @@ #include #include -#define AMS_PM_I_SHELL_INTERFACE_INTERFACE_INFO(C, H) \ - AMS_SF_METHOD_INFO(C, H, 0, Result, LaunchProgram, (sf::Out out_process_id, const ncm::ProgramLocation &loc, u32 flags), (out_process_id, loc, flags)) \ - AMS_SF_METHOD_INFO(C, H, 1, Result, TerminateProcess, (os::ProcessId process_id), (process_id)) \ - AMS_SF_METHOD_INFO(C, H, 2, Result, TerminateProgram, (ncm::ProgramId program_id), (program_id)) \ - AMS_SF_METHOD_INFO(C, H, 3, void, GetProcessEventHandle, (sf::OutCopyHandle out), (out)) \ - AMS_SF_METHOD_INFO(C, H, 4, void, GetProcessEventInfo, (sf::Out out), (out)) \ - AMS_SF_METHOD_INFO(C, H, 5, void, NotifyBootFinished, (), ()) \ - AMS_SF_METHOD_INFO(C, H, 6, Result, GetApplicationProcessIdForShell, (sf::Out out), (out)) \ - AMS_SF_METHOD_INFO(C, H, 7, Result, BoostSystemMemoryResourceLimit, (u64 boost_size), (boost_size)) \ - AMS_SF_METHOD_INFO(C, H, 8, Result, BoostApplicationThreadResourceLimit, (), ()) \ - AMS_SF_METHOD_INFO(C, H, 9, void, GetBootFinishedEventHandle, (sf::OutCopyHandle out), (out), hos::Version_8_0_0) \ - AMS_SF_METHOD_INFO(C, H, 10, Result, BoostSystemThreadResourceLimit, (), ()) +#define AMS_PM_I_SHELL_INTERFACE_INTERFACE_INFO(C, H) \ + AMS_SF_METHOD_INFO(C, H, 0, Result, LaunchProgram, (sf::Out out_process_id, const ncm::ProgramLocation &loc, u32 flags), (out_process_id, loc, flags)) \ + AMS_SF_METHOD_INFO(C, H, 1, Result, TerminateProcess, (os::ProcessId process_id), (process_id)) \ + AMS_SF_METHOD_INFO(C, H, 2, Result, TerminateProgram, (ncm::ProgramId program_id), (program_id)) \ + AMS_SF_METHOD_INFO(C, H, 3, void, GetProcessEventHandle, (sf::OutCopyHandle out), (out)) \ + AMS_SF_METHOD_INFO(C, H, 4, void, GetProcessEventInfo, (sf::Out out), (out)) \ + AMS_SF_METHOD_INFO(C, H, 5, void, NotifyBootFinished, (), ()) \ + AMS_SF_METHOD_INFO(C, H, 6, Result, GetApplicationProcessIdForShell, (sf::Out out), (out)) \ + AMS_SF_METHOD_INFO(C, H, 7, Result, BoostSystemMemoryResourceLimit, (u64 boost_size), (boost_size)) \ + AMS_SF_METHOD_INFO(C, H, 8, Result, BoostApplicationThreadResourceLimit, (), ()) \ + AMS_SF_METHOD_INFO(C, H, 9, void, GetBootFinishedEventHandle, (sf::OutCopyHandle out), (out), hos::Version_8_0_0) \ + AMS_SF_METHOD_INFO(C, H, 10, Result, BoostSystemThreadResourceLimit, (), ()) \ + AMS_SF_METHOD_INFO(C, H, 65000, Result, AtmosphereBoostSystemMemoryResourceLimitForMitm, (u64 boost_size), (boost_size)) AMS_SF_DEFINE_INTERFACE(ams::pm::impl, IShellInterface, AMS_PM_I_SHELL_INTERFACE_INTERFACE_INFO, 0x387D60C0) -#define AMS_PM_I_DEPRECATED_SHELL_INTERFACE_INTERFACE_INFO(C, H) \ - AMS_SF_METHOD_INFO(C, H, 0, Result, LaunchProgram, (sf::Out out_process_id, const ncm::ProgramLocation &loc, u32 flags), (out_process_id, loc, flags)) \ - AMS_SF_METHOD_INFO(C, H, 1, Result, TerminateProcess, (os::ProcessId process_id), (process_id)) \ - AMS_SF_METHOD_INFO(C, H, 2, Result, TerminateProgram, (ncm::ProgramId program_id), (program_id)) \ - AMS_SF_METHOD_INFO(C, H, 3, void, GetProcessEventHandle, (sf::OutCopyHandle out), (out)) \ - AMS_SF_METHOD_INFO(C, H, 4, void, GetProcessEventInfo, (sf::Out out), (out)) \ - AMS_SF_METHOD_INFO(C, H, 5, Result, CleanupProcess, (os::ProcessId process_id), (process_id)) \ - AMS_SF_METHOD_INFO(C, H, 6, Result, ClearExceptionOccurred, (os::ProcessId process_id), (process_id)) \ - AMS_SF_METHOD_INFO(C, H, 7, void, NotifyBootFinished, (), ()) \ - AMS_SF_METHOD_INFO(C, H, 8, Result, GetApplicationProcessIdForShell, (sf::Out out), (out)) \ - AMS_SF_METHOD_INFO(C, H, 9, Result, BoostSystemMemoryResourceLimit, (u64 boost_size), (boost_size), hos::Version_4_0_0) +#define AMS_PM_I_DEPRECATED_SHELL_INTERFACE_INTERFACE_INFO(C, H) \ + AMS_SF_METHOD_INFO(C, H, 0, Result, LaunchProgram, (sf::Out out_process_id, const ncm::ProgramLocation &loc, u32 flags), (out_process_id, loc, flags)) \ + AMS_SF_METHOD_INFO(C, H, 1, Result, TerminateProcess, (os::ProcessId process_id), (process_id)) \ + AMS_SF_METHOD_INFO(C, H, 2, Result, TerminateProgram, (ncm::ProgramId program_id), (program_id)) \ + AMS_SF_METHOD_INFO(C, H, 3, void, GetProcessEventHandle, (sf::OutCopyHandle out), (out)) \ + AMS_SF_METHOD_INFO(C, H, 4, void, GetProcessEventInfo, (sf::Out out), (out)) \ + AMS_SF_METHOD_INFO(C, H, 5, Result, CleanupProcess, (os::ProcessId process_id), (process_id)) \ + AMS_SF_METHOD_INFO(C, H, 6, Result, ClearExceptionOccurred, (os::ProcessId process_id), (process_id)) \ + AMS_SF_METHOD_INFO(C, H, 7, void, NotifyBootFinished, (), ()) \ + AMS_SF_METHOD_INFO(C, H, 8, Result, GetApplicationProcessIdForShell, (sf::Out out), (out)) \ + AMS_SF_METHOD_INFO(C, H, 9, Result, BoostSystemMemoryResourceLimit, (u64 boost_size), (boost_size), hos::Version_4_0_0) \ + AMS_SF_METHOD_INFO(C, H, 10, Result, BoostSystemThreadResourceLimit, (), ()) \ + AMS_SF_METHOD_INFO(C, H, 65000, Result, AtmosphereBoostSystemMemoryResourceLimitForMitm, (u64 boost_size), (boost_size)) AMS_SF_DEFINE_INTERFACE(ams::pm::impl, IDeprecatedShellInterface, AMS_PM_I_DEPRECATED_SHELL_INTERFACE_INTERFACE_INFO, 0x387D60C0) diff --git a/libraries/libstratosphere/include/stratosphere/pm/pm_shell_api.hpp b/libraries/libstratosphere/include/stratosphere/pm/pm_shell_api.hpp index b4cd348c4..ce3f393ab 100644 --- a/libraries/libstratosphere/include/stratosphere/pm/pm_shell_api.hpp +++ b/libraries/libstratosphere/include/stratosphere/pm/pm_shell_api.hpp @@ -32,4 +32,6 @@ namespace ams::pm::shell { Result BoostApplicationThreadResourceLimit(); Result BoostSystemThreadResourceLimit(); + Result AtmosphereBoostSystemMemoryResourceLimitForMitm(u64 size); + } diff --git a/libraries/libstratosphere/source/pm/pm_ams.os.horizon.c b/libraries/libstratosphere/source/pm/pm_ams.os.horizon.c index b7b3d249a..d67f5c704 100644 --- a/libraries/libstratosphere/source/pm/pm_ams.os.horizon.c +++ b/libraries/libstratosphere/source/pm/pm_ams.os.horizon.c @@ -90,3 +90,9 @@ Result pmdmntAtmosphereGetCurrentLimitInfo(u64 *out_cur, u64 *out_lim, u32 group return rc; } + +Result pmshellAtmosphereBoostSystemMemoryResourceLimitForMitm(u64 size) { + return serviceDispatchIn(pmshellGetServiceSession(), 65000, size); +} + + diff --git a/libraries/libstratosphere/source/pm/pm_ams.os.horizon.h b/libraries/libstratosphere/source/pm/pm_ams.os.horizon.h index 099752eee..b7c6c2217 100644 --- a/libraries/libstratosphere/source/pm/pm_ams.os.horizon.h +++ b/libraries/libstratosphere/source/pm/pm_ams.os.horizon.h @@ -26,6 +26,8 @@ Result pminfoAtmosphereGetProcessInfo(NcmProgramLocation *loc_out, CfgOverrideSt Result pmdmntAtmosphereGetProcessInfo(Handle *out, NcmProgramLocation *loc_out, CfgOverrideStatus *status_out, u64 pid); Result pmdmntAtmosphereGetCurrentLimitInfo(u64 *out_cur, u64 *out_lim, u32 group, u32 resource); +Result pmshellAtmosphereBoostSystemMemoryResourceLimitForMitm(u64 size); + #ifdef __cplusplus } #endif diff --git a/libraries/libstratosphere/source/pm/pm_shell_api.cpp b/libraries/libstratosphere/source/pm/pm_shell_api.cpp index 03470e47f..1b0364be7 100644 --- a/libraries/libstratosphere/source/pm/pm_shell_api.cpp +++ b/libraries/libstratosphere/source/pm/pm_shell_api.cpp @@ -14,6 +14,7 @@ * along with this program. If not, see . */ #include +#include "pm_ams.os.horizon.h" namespace ams::pm::shell { @@ -57,6 +58,10 @@ namespace ams::pm::shell { Result BoostSystemThreadResourceLimit() { R_RETURN(::pmshellBoostSystemThreadResourceLimit()); } + + Result AtmosphereBoostSystemMemoryResourceLimitForMitm(u64 size) { + R_RETURN(pmshellAtmosphereBoostSystemMemoryResourceLimitForMitm(size)); + } #endif } diff --git a/stratosphere/pm/source/impl/pm_process_manager.cpp b/stratosphere/pm/source/impl/pm_process_manager.cpp index 2f2d1b89a..6026f061c 100644 --- a/stratosphere/pm/source/impl/pm_process_manager.cpp +++ b/stratosphere/pm/source/impl/pm_process_manager.cpp @@ -713,4 +713,8 @@ namespace ams::pm::impl { R_RETURN(resource::GetResourceLimitValues(out_cur_val, out_lim_val, static_cast(group), static_cast(resource))); } + Result BoostSystemMemoryResourceLimitForMitm(u64 boost_size) { + R_RETURN(resource::BoostSystemMemoryResourceLimitForMitm(boost_size)); + } + } diff --git a/stratosphere/pm/source/impl/pm_process_manager.hpp b/stratosphere/pm/source/impl/pm_process_manager.hpp index d2af22ac2..83ccc7a85 100644 --- a/stratosphere/pm/source/impl/pm_process_manager.hpp +++ b/stratosphere/pm/source/impl/pm_process_manager.hpp @@ -55,5 +55,6 @@ namespace ams::pm::impl { Result GetAppletCurrentResourceLimitValues(pm::ResourceLimitValues *out); Result GetAppletPeakResourceLimitValues(pm::ResourceLimitValues *out); Result AtmosphereGetCurrentLimitInfo(s64 *out_cur_val, s64 *out_lim_val, u32 group, u32 resource); + Result BoostSystemMemoryResourceLimitForMitm(u64 boost_size); } diff --git a/stratosphere/pm/source/impl/pm_resource_manager.cpp b/stratosphere/pm/source/impl/pm_resource_manager.cpp index 644a8bb0e..6c5805b5d 100644 --- a/stratosphere/pm/source/impl/pm_resource_manager.cpp +++ b/stratosphere/pm/source/impl/pm_resource_manager.cpp @@ -52,9 +52,16 @@ namespace ams::pm::resource { constinit os::SdkMutex g_resource_limit_lock; constinit os::NativeHandle g_resource_limit_handles[ResourceLimitGroup_Count]; constinit spl::MemoryArrangement g_memory_arrangement = spl::MemoryArrangement_Standard; - constinit u64 g_system_memory_boost_size = 0; constinit u64 g_extra_threads_available[ResourceLimitGroup_Count]; + constinit os::SdkMutex g_system_memory_boost_lock; + constinit u64 g_system_memory_boost_size = 0; + constinit u64 g_system_memory_boost_size_for_mitm = 0; + + ALWAYS_INLINE u64 GetCurrentSystemMemoryBoostSize() { + return g_system_memory_boost_size + g_system_memory_boost_size_for_mitm; + } + constinit u64 g_resource_limits[ResourceLimitGroup_Count][svc::LimitableResource_Count] = { [ResourceLimitGroup_System] = { [svc::LimitableResource_PhysicalMemoryMax] = 0, /* Initialized dynamically later. */ @@ -220,6 +227,47 @@ namespace ams::pm::resource { R_SUCCEED(); } + Result BoostSystemMemoryResourceLimitLocked(u64 normal_boost, u64 mitm_boost) { + /* Check pre-conditions. */ + AMS_ASSERT(g_system_memory_boost_lock.IsLockedByCurrentThread()); + + /* Determine total boost. */ + const u64 boost_size = normal_boost + mitm_boost; + + /* Don't allow all application memory to be taken away. */ + R_UNLESS(boost_size <= g_memory_resource_limits[g_memory_arrangement][ResourceLimitGroup_Application], pm::ResultInvalidSize()); + + const u64 new_app_size = g_memory_resource_limits[g_memory_arrangement][ResourceLimitGroup_Application] - boost_size; + { + std::scoped_lock lk(g_resource_limit_lock); + + if (hos::GetVersion() >= hos::Version_5_0_0) { + /* Starting in 5.0.0, PM does not allow for only one of the sets to fail. */ + if (boost_size < GetCurrentSystemMemoryBoostSize()) { + R_TRY(svc::SetUnsafeLimit(boost_size)); + R_ABORT_UNLESS(SetMemoryResourceLimitLimitValue(ResourceLimitGroup_Application, new_app_size)); + } else { + R_TRY(SetMemoryResourceLimitLimitValue(ResourceLimitGroup_Application, new_app_size)); + R_ABORT_UNLESS(svc::SetUnsafeLimit(boost_size)); + } + } else { + const u64 new_sys_size = g_memory_resource_limits[g_memory_arrangement][ResourceLimitGroup_System] + boost_size; + if (boost_size < GetCurrentSystemMemoryBoostSize()) { + R_TRY(SetMemoryResourceLimitLimitValue(ResourceLimitGroup_System, new_sys_size)); + R_TRY(SetMemoryResourceLimitLimitValue(ResourceLimitGroup_Application, new_app_size)); + } else { + R_TRY(SetMemoryResourceLimitLimitValue(ResourceLimitGroup_Application, new_app_size)); + R_TRY(SetMemoryResourceLimitLimitValue(ResourceLimitGroup_System, new_sys_size)); + } + } + + g_system_memory_boost_size = normal_boost; + g_system_memory_boost_size_for_mitm = mitm_boost; + } + + R_SUCCEED(); + } + } /* Resource API. */ @@ -352,37 +400,19 @@ namespace ams::pm::resource { } Result BoostSystemMemoryResourceLimit(u64 boost_size) { - /* Don't allow all application memory to be taken away. */ - R_UNLESS(boost_size <= g_memory_resource_limits[g_memory_arrangement][ResourceLimitGroup_Application], pm::ResultInvalidSize()); + /* Ensure only one boost change happens at a time. */ + std::scoped_lock lk(g_system_memory_boost_lock); - const u64 new_app_size = g_memory_resource_limits[g_memory_arrangement][ResourceLimitGroup_Application] - boost_size; - { - std::scoped_lock lk(g_resource_limit_lock); + /* Boost to the appropriate total amount. */ + R_RETURN(BoostSystemMemoryResourceLimitLocked(boost_size, g_system_memory_boost_size_for_mitm)); + } - if (hos::GetVersion() >= hos::Version_5_0_0) { - /* Starting in 5.0.0, PM does not allow for only one of the sets to fail. */ - if (boost_size < g_system_memory_boost_size) { - R_TRY(svc::SetUnsafeLimit(boost_size)); - R_ABORT_UNLESS(SetMemoryResourceLimitLimitValue(ResourceLimitGroup_Application, new_app_size)); - } else { - R_TRY(SetMemoryResourceLimitLimitValue(ResourceLimitGroup_Application, new_app_size)); - R_ABORT_UNLESS(svc::SetUnsafeLimit(boost_size)); - } - } else { - const u64 new_sys_size = g_memory_resource_limits[g_memory_arrangement][ResourceLimitGroup_System] + boost_size; - if (boost_size < g_system_memory_boost_size) { - R_TRY(SetMemoryResourceLimitLimitValue(ResourceLimitGroup_System, new_sys_size)); - R_TRY(SetMemoryResourceLimitLimitValue(ResourceLimitGroup_Application, new_app_size)); - } else { - R_TRY(SetMemoryResourceLimitLimitValue(ResourceLimitGroup_Application, new_app_size)); - R_TRY(SetMemoryResourceLimitLimitValue(ResourceLimitGroup_System, new_sys_size)); - } - } + Result BoostSystemMemoryResourceLimitForMitm(u64 boost_size) { + /* Ensure only one boost change happens at a time. */ + std::scoped_lock lk(g_system_memory_boost_lock); - g_system_memory_boost_size = boost_size; - } - - R_SUCCEED(); + /* Boost to the appropriate total amount. */ + R_RETURN(BoostSystemMemoryResourceLimitLocked(g_system_memory_boost_size, boost_size)); } Result BoostApplicationThreadResourceLimit() { diff --git a/stratosphere/pm/source/impl/pm_resource_manager.hpp b/stratosphere/pm/source/impl/pm_resource_manager.hpp index bd59f28c8..029458203 100644 --- a/stratosphere/pm/source/impl/pm_resource_manager.hpp +++ b/stratosphere/pm/source/impl/pm_resource_manager.hpp @@ -24,6 +24,8 @@ namespace ams::pm::resource { Result BoostApplicationThreadResourceLimit(); Result BoostSystemThreadResourceLimit(); + Result BoostSystemMemoryResourceLimitForMitm(u64 boost_size); + os::NativeHandle GetResourceLimitHandle(ResourceLimitGroup group); os::NativeHandle GetResourceLimitHandle(const ldr::ProgramInfo *info); diff --git a/stratosphere/pm/source/pm_shell_service.cpp b/stratosphere/pm/source/pm_shell_service.cpp index 7248bc0e2..2e9b13bf1 100644 --- a/stratosphere/pm/source/pm_shell_service.cpp +++ b/stratosphere/pm/source/pm_shell_service.cpp @@ -87,4 +87,8 @@ namespace ams::pm { R_RETURN(impl::BoostSystemThreadResourceLimit()); } + Result ShellService::AtmosphereBoostSystemMemoryResourceLimitForMitm(u64 boost_size) { + R_RETURN(impl::BoostSystemMemoryResourceLimitForMitm(boost_size)); + } + } diff --git a/stratosphere/pm/source/pm_shell_service.hpp b/stratosphere/pm/source/pm_shell_service.hpp index bb08d80bd..0e7a3b190 100644 --- a/stratosphere/pm/source/pm_shell_service.hpp +++ b/stratosphere/pm/source/pm_shell_service.hpp @@ -34,6 +34,9 @@ namespace ams::pm { Result BoostApplicationThreadResourceLimit(); void GetBootFinishedEventHandle(sf::OutCopyHandle out); Result BoostSystemThreadResourceLimit(); + + /* Atmosphere extension command implementations. */ + Result AtmosphereBoostSystemMemoryResourceLimitForMitm(u64 boost_size); }; static_assert(pm::impl::IsIShellInterface);