diff --git a/stratosphere/sm/source/sm_registration.cpp b/stratosphere/sm/source/sm_registration.cpp index 89636b8e9..f27dd5ee4 100644 --- a/stratosphere/sm/source/sm_registration.cpp +++ b/stratosphere/sm/source/sm_registration.cpp @@ -176,7 +176,7 @@ bool Registration::HasService(u64 service) { return false; } -Result Registration::GetServiceHandle(u64 service, Handle *out) { +Result Registration::GetServiceHandle(u64 pid, u64 service, Handle *out) { Registration::Service *target_service = GetService(service); if (target_service == NULL) { /* Note: This defers the result until later. */ @@ -184,7 +184,12 @@ Result Registration::GetServiceHandle(u64 service, Handle *out) { } *out = 0; - Result rc = svcConnectToPort(out, target_service->port_h); + Result rc; + if (target_service->mitm_pid == 0 || target_service->mitm_pid == pid) { + rc = svcConnectToPort(out, target_service->port_h); + } else { + rc = svcConnectToPort(out, target_service->mitm_port_h); + } if (R_FAILED(rc)) { if ((rc & 0x3FFFFF) == 0xE01) { return 0x615; @@ -217,7 +222,7 @@ Result Registration::GetServiceForPid(u64 pid, u64 service, Handle *out) { } } - return GetServiceHandle(service, out); + return GetServiceHandle(pid, service, out); } Result Registration::RegisterServiceForPid(u64 pid, u64 service, u64 max_sessions, bool is_light, Handle *out) { @@ -294,6 +299,8 @@ Result Registration::RegisterServiceForSelf(u64 service, u64 max_sessions, bool if (R_SUCCEEDED(rc)) { free_service->service_name = service; free_service->owner_pid = pid; + free_service->max_sessions = max_sessions; + free_service->is_light = is_light; } return rc; @@ -321,6 +328,80 @@ Result Registration::UnregisterServiceForPid(u64 pid, u64 service) { } svcCloseHandle(target_service->port_h); + svcCloseHandle(target_service->mitm_port_h); *target_service = (const Registration::Service){0}; return 0; } + + +Result Registration::InstallMitmForPid(u64 pid, u64 service, Handle *out) { + if (!service) { + return 0xC15; + } + + 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 0xC15; + } + + /* Verify we're allowed to mitm the service. */ + if (!IsInitialProcess(pid)) { + Registration::Process *proc = GetProcessForPid(pid); + if (proc == NULL) { + return 0x415; + } + + if (!IsValidForSac(proc->sac, proc->sac_size, service, true)) { + return 0x1015; + } + } + + /* Verify the service exists. */ + Registration::Service *target_service = GetService(service); + if (target_service == NULL) { + return 0xE15; + } + + /* Verify the service isn't already being mitm'd. */ + if (target_service->mitm_pid != 0) { + return 0x815; + } + + *out = 0; + u64 x = 0; + Result rc = svcCreatePort(out, &target_service->mitm_port_h, target_service->max_sessions, target_service->is_light, (char *)&x); + + if (R_SUCCEEDED(rc)) { + target_service->mitm_pid = pid; + } + + return rc; +} + +Result Registration::UninstallMitmForPid(u64 pid, u64 service) { + if (!service) { + return 0xC15; + } + + 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 0xC15; + } + + Registration::Service *target_service = GetService(service); + if (target_service == NULL) { + return 0xE15; + } + + if (!IsInitialProcess(pid) && target_service->mitm_pid != pid) { + return 0x1015; + } + + svcCloseHandle(target_service->mitm_port_h); + target_service->mitm_pid = 0; + return 0; +} diff --git a/stratosphere/sm/source/sm_registration.hpp b/stratosphere/sm/source/sm_registration.hpp index 5c7af1f27..fe7ccdceb 100644 --- a/stratosphere/sm/source/sm_registration.hpp +++ b/stratosphere/sm/source/sm_registration.hpp @@ -18,6 +18,14 @@ class Registration { u64 service_name; u64 owner_pid; Handle port_h; + + /* Debug. */ + u64 max_sessions; + bool is_light; + + /* Extension. */ + u64 mitm_pid; + Handle mitm_port_h; }; /* Utilities. */ @@ -37,9 +45,13 @@ class Registration { /* Service management. */ static bool HasService(u64 service); - static Result GetServiceHandle(u64 service, 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); + static Result UninstallMitmForPid(u64 pid, u64 service); }; diff --git a/stratosphere/sm/source/sm_user_service.cpp b/stratosphere/sm/source/sm_user_service.cpp index 0e3d91025..a5c36ce6d 100644 --- a/stratosphere/sm/source/sm_user_service.cpp +++ b/stratosphere/sm/source/sm_user_service.cpp @@ -18,6 +18,12 @@ Result UserService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, case User_Cmd_UnregisterService: rc = WrapIpcCommandImpl<&UserService::unregister_service>(this, r, out_c, pointer_buffer, pointer_buffer_size); break; + case User_Cmd_AtmosphereInstallMitm: + rc = WrapIpcCommandImpl<&UserService::install_mitm>(this, r, out_c, pointer_buffer, pointer_buffer_size); + break; + case User_Cmd_AtmosphereUninstallMitm: + rc = WrapIpcCommandImpl<&UserService::uninstall_mitm>(this, r, out_c, pointer_buffer, pointer_buffer_size); + break; default: break; } @@ -56,7 +62,7 @@ std::tuple UserService::get_service(u64 service) { std::tuple UserService::deferred_get_service(u64 service) { Handle session_h = 0; - Result rc = Registration::GetServiceHandle(service, &session_h); + Result rc = Registration::GetServiceHandle(this->pid, service, &session_h); return {rc, MovedHandle{session_h}}; } @@ -86,3 +92,20 @@ std::tuple UserService::unregister_service(u64 service) { } return {rc}; } + +std::tuple UserService::install_mitm(u64 service) { + Handle service_h = 0; + Result rc = 0x415; + if (this->has_initialized) { + rc = Registration::InstallMitmForPid(this->pid, service, &service_h); + } + return {rc, MovedHandle{service_h}}; +} + +std::tuple UserService::uninstall_mitm(u64 service) { + Result rc = 0x415; + if (this->has_initialized) { + rc = Registration::UninstallMitmForPid(this->pid, service); + } + return {rc}; +} \ No newline at end of file diff --git a/stratosphere/sm/source/sm_user_service.hpp b/stratosphere/sm/source/sm_user_service.hpp index eddf75723..5911bd768 100644 --- a/stratosphere/sm/source/sm_user_service.hpp +++ b/stratosphere/sm/source/sm_user_service.hpp @@ -6,7 +6,10 @@ enum UserServiceCmd { User_Cmd_Initialize = 0, User_Cmd_GetService = 1, User_Cmd_RegisterService = 2, - User_Cmd_UnregisterService = 3 + User_Cmd_UnregisterService = 3, + + User_Cmd_AtmosphereInstallMitm = 65000, + User_Cmd_AtmosphereUninstallMitm = 65001 }; class UserService : IServiceObject { @@ -26,4 +29,8 @@ class UserService : IServiceObject { std::tuple deferred_get_service(u64 service); std::tuple register_service(u64 service, u8 is_light, u32 max_sessions); std::tuple unregister_service(u64 service); + + /* Atmosphere commands. */ + std::tuple install_mitm(u64 service); + std::tuple uninstall_mitm(u64 service); }; \ No newline at end of file