From 99b5458539be07da347b3c9fcd7f7446e87fb8d0 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 7 Sep 2020 10:40:43 -0700 Subject: [PATCH] sm: fix deadlock semantics surrounding mitm installation --- .../sm/impl/sm_user_interface.hpp | 1 + .../include/stratosphere/sm/sm_mitm_api.hpp | 1 + .../source/sf/hipc/sf_hipc_server_manager.cpp | 4 ++ libraries/libstratosphere/source/sm/sm_ams.c | 4 ++ libraries/libstratosphere/source/sm/sm_ams.h | 1 + .../libstratosphere/source/sm/sm_mitm_api.cpp | 6 +++ .../sm/source/impl/sm_service_manager.cpp | 41 +++++++++++++++++-- .../sm/source/impl/sm_service_manager.hpp | 1 + stratosphere/sm/source/sm_user_service.cpp | 5 +++ stratosphere/sm/source/sm_user_service.hpp | 1 + 10 files changed, 62 insertions(+), 3 deletions(-) diff --git a/libraries/libstratosphere/include/stratosphere/sm/impl/sm_user_interface.hpp b/libraries/libstratosphere/include/stratosphere/sm/impl/sm_user_interface.hpp index 843162857..6bb7c72f5 100644 --- a/libraries/libstratosphere/include/stratosphere/sm/impl/sm_user_interface.hpp +++ b/libraries/libstratosphere/include/stratosphere/sm/impl/sm_user_interface.hpp @@ -32,6 +32,7 @@ namespace ams::sm::impl { AMS_SF_METHOD_INFO(C, H, 65004, Result, AtmosphereHasMitm, (sf::Out out, ServiceName service)) \ AMS_SF_METHOD_INFO(C, H, 65005, Result, AtmosphereWaitMitm, (ServiceName service)) \ AMS_SF_METHOD_INFO(C, H, 65006, Result, AtmosphereDeclareFutureMitm, (ServiceName service)) \ + AMS_SF_METHOD_INFO(C, H, 65007, Result, AtmosphereClearFutureMitm, (ServiceName service)) \ AMS_SF_METHOD_INFO(C, H, 65100, Result, AtmosphereHasService, (sf::Out out, ServiceName service)) \ AMS_SF_METHOD_INFO(C, H, 65101, Result, AtmosphereWaitService, (ServiceName service)) diff --git a/libraries/libstratosphere/include/stratosphere/sm/sm_mitm_api.hpp b/libraries/libstratosphere/include/stratosphere/sm/sm_mitm_api.hpp index fcdd46c55..d78f63b1b 100644 --- a/libraries/libstratosphere/include/stratosphere/sm/sm_mitm_api.hpp +++ b/libraries/libstratosphere/include/stratosphere/sm/sm_mitm_api.hpp @@ -24,6 +24,7 @@ namespace ams::sm::mitm { Result InstallMitm(Handle *out_port, Handle *out_query, ServiceName name); Result UninstallMitm(ServiceName name); Result DeclareFutureMitm(ServiceName name); + Result ClearFutureMitm(ServiceName name); Result AcknowledgeSession(Service *out_service, MitmProcessInfo *out_info, ServiceName name); Result HasMitm(bool *out, ServiceName name); Result WaitMitm(ServiceName name); diff --git a/libraries/libstratosphere/source/sf/hipc/sf_hipc_server_manager.cpp b/libraries/libstratosphere/source/sf/hipc/sf_hipc_server_manager.cpp index c763dbae2..37b786262 100644 --- a/libraries/libstratosphere/source/sf/hipc/sf_hipc_server_manager.cpp +++ b/libraries/libstratosphere/source/sf/hipc/sf_hipc_server_manager.cpp @@ -27,6 +27,10 @@ namespace ams::sf::hipc { /* Register the query handle. */ impl::RegisterMitmQueryHandle(query_handle, query_func); + + /* Clear future declarations if any, now that our query handler is present. */ + R_ABORT_UNLESS(sm::mitm::ClearFutureMitm(service_name)); + return ResultSuccess(); } diff --git a/libraries/libstratosphere/source/sm/sm_ams.c b/libraries/libstratosphere/source/sm/sm_ams.c index 233c79378..1ceb23f88 100644 --- a/libraries/libstratosphere/source/sm/sm_ams.c +++ b/libraries/libstratosphere/source/sm/sm_ams.c @@ -107,6 +107,10 @@ Result smAtmosphereMitmDeclareFuture(SmServiceName name) { return _smAtmosphereCmdInServiceNameNoOut(name, smGetServiceSession(), 65006); } +Result smAtmosphereMitmClearFuture(SmServiceName name) { + return _smAtmosphereCmdInServiceNameNoOut(name, smGetServiceSession(), 65007); +} + Result smAtmosphereMitmAcknowledgeSession(Service *srv_out, void *_out, SmServiceName name) { struct { u64 process_id; diff --git a/libraries/libstratosphere/source/sm/sm_ams.h b/libraries/libstratosphere/source/sm/sm_ams.h index 6bdf435b4..3a4885ccb 100644 --- a/libraries/libstratosphere/source/sm/sm_ams.h +++ b/libraries/libstratosphere/source/sm/sm_ams.h @@ -26,6 +26,7 @@ void smAtmosphereCloseSession(Service *srv); Result smAtmosphereMitmInstall(Service *fwd_srv, Handle *handle_out, Handle *query_out, SmServiceName name); Result smAtmosphereMitmUninstall(SmServiceName name); Result smAtmosphereMitmDeclareFuture(SmServiceName name); +Result smAtmosphereMitmClearFuture(SmServiceName name); Result smAtmosphereMitmAcknowledgeSession(Service *srv_out, void *info_out, SmServiceName name); #ifdef __cplusplus diff --git a/libraries/libstratosphere/source/sm/sm_mitm_api.cpp b/libraries/libstratosphere/source/sm/sm_mitm_api.cpp index 431c3b96c..8e5c80023 100644 --- a/libraries/libstratosphere/source/sm/sm_mitm_api.cpp +++ b/libraries/libstratosphere/source/sm/sm_mitm_api.cpp @@ -37,6 +37,12 @@ namespace ams::sm::mitm { }); } + Result ClearFutureMitm(ServiceName name) { + return impl::DoWithUserSession([&]() { + return smAtmosphereMitmClearFuture(impl::ConvertName(name)); + }); + } + Result AcknowledgeSession(Service *out_service, MitmProcessInfo *out_info, ServiceName name) { return impl::DoWithMitmAcknowledgementSession([&]() { return smAtmosphereMitmAcknowledgeSession(out_service, reinterpret_cast(out_info), impl::ConvertName(name)); diff --git a/stratosphere/sm/source/impl/sm_service_manager.cpp b/stratosphere/sm/source/impl/sm_service_manager.cpp index 33812ddb3..96be1cbac 100644 --- a/stratosphere/sm/source/impl/sm_service_manager.cpp +++ b/stratosphere/sm/source/impl/sm_service_manager.cpp @@ -588,6 +588,15 @@ namespace ams::sm::impl { *out = INVALID_HANDLE; *out_query = INVALID_HANDLE; + /* If we don't have a future mitm declaration, add one. */ + /* Client will clear this when ready to process. */ + bool has_existing_future_declaration = HasFutureMitmDeclaration(service); + if (!has_existing_future_declaration) { + R_TRY(AddFutureMitmDeclaration(service)); + } + + auto future_guard = SCOPE_GUARD { if (!has_existing_future_declaration) { ClearFutureMitmDeclaration(service); } }; + /* Create mitm handles. */ { os::ManagedHandle hnd, port_hnd, qry_hnd, mitm_qry_hnd; @@ -603,9 +612,7 @@ namespace ams::sm::impl { *out_query = qry_hnd.Move(); } - /* Clear the future declaration, if one exists. */ - ClearFutureMitmDeclaration(service); - + future_guard.Cancel(); return ResultSuccess(); } @@ -651,6 +658,34 @@ namespace ams::sm::impl { return ResultSuccess(); } + Result ClearFutureMitm(os::ProcessId process_id, ServiceName service) { + /* Validate service name. */ + R_TRY(ValidateServiceName(service)); + + /* Check that the process is registered and allowed to register the service. */ + if (!IsInitialProcess(process_id)) { + ProcessInfo *proc = GetProcessInfo(process_id); + R_UNLESS(proc != nullptr, sm::ResultInvalidClient()); + R_TRY(ValidateAccessControl(AccessControlEntry(proc->access_control, proc->access_control_size), service, true, false)); + } + + /* Check that a future mitm declaration is present or we have a mitm. */ + if (HasMitm(service)) { + /* Validate that the service exists. */ + ServiceInfo *service_info = GetServiceInfo(service); + R_UNLESS(service_info != nullptr, sm::ResultNotRegistered()); + + /* Validate that the client process_id is the mitm process. */ + R_UNLESS(service_info->mitm_process_id == process_id, sm::ResultNotAllowed()); + } else { + R_UNLESS(HasFutureMitmDeclaration(service), sm::ResultNotRegistered()); + } + + /* Clear the forward declaration. */ + ClearFutureMitmDeclaration(service); + return ResultSuccess(); + } + Result AcknowledgeMitmSession(MitmProcessInfo *out_info, Handle *out_hnd, os::ProcessId process_id, ServiceName service) { /* Validate service name. */ R_TRY(ValidateServiceName(service)); diff --git a/stratosphere/sm/source/impl/sm_service_manager.hpp b/stratosphere/sm/source/impl/sm_service_manager.hpp index f3ae700fd..e27a18c86 100644 --- a/stratosphere/sm/source/impl/sm_service_manager.hpp +++ b/stratosphere/sm/source/impl/sm_service_manager.hpp @@ -37,6 +37,7 @@ namespace ams::sm::impl { Result InstallMitm(Handle *out, Handle *out_query, os::ProcessId process_id, ServiceName service); Result UninstallMitm(os::ProcessId process_id, ServiceName service); Result DeclareFutureMitm(os::ProcessId process_id, ServiceName service); + Result ClearFutureMitm(os::ProcessId process_id, ServiceName service); Result AcknowledgeMitmSession(MitmProcessInfo *out_info, Handle *out_hnd, os::ProcessId process_id, ServiceName service); /* Dmnt record extensions. */ diff --git a/stratosphere/sm/source/sm_user_service.cpp b/stratosphere/sm/source/sm_user_service.cpp index 67143af19..bf5eb4162 100644 --- a/stratosphere/sm/source/sm_user_service.cpp +++ b/stratosphere/sm/source/sm_user_service.cpp @@ -75,6 +75,11 @@ namespace ams::sm { return impl::DeclareFutureMitm(this->process_id, service); } + Result UserService::AtmosphereClearFutureMitm(ServiceName service) { + R_TRY(this->EnsureInitialized()); + return impl::ClearFutureMitm(this->process_id, service); + } + Result UserService::AtmosphereHasService(sf::Out out, ServiceName service) { R_TRY(this->EnsureInitialized()); diff --git a/stratosphere/sm/source/sm_user_service.hpp b/stratosphere/sm/source/sm_user_service.hpp index bc2c02f3f..1bf82caad 100644 --- a/stratosphere/sm/source/sm_user_service.hpp +++ b/stratosphere/sm/source/sm_user_service.hpp @@ -40,6 +40,7 @@ namespace ams::sm { Result AtmosphereHasMitm(sf::Out out, ServiceName service); Result AtmosphereWaitMitm(ServiceName service); Result AtmosphereDeclareFutureMitm(ServiceName service); + Result AtmosphereClearFutureMitm(ServiceName service); Result AtmosphereHasService(sf::Out out, ServiceName service); Result AtmosphereWaitService(ServiceName service);