diff --git a/libraries/libstratosphere/include/stratosphere/tipc/tipc_object_manager.hpp b/libraries/libstratosphere/include/stratosphere/tipc/tipc_object_manager.hpp index 221e09a64..4a4044f3a 100644 --- a/libraries/libstratosphere/include/stratosphere/tipc/tipc_object_manager.hpp +++ b/libraries/libstratosphere/include/stratosphere/tipc/tipc_object_manager.hpp @@ -141,14 +141,45 @@ namespace ams::tipc { } Result ProcessRequest(ObjectHolder &object) { + /* Get the message buffer. */ + const svc::ipc::MessageBuffer message_buffer(svc::ipc::GetMessageBuffer()); + /* Get the method id. */ - const auto method_id = svc::ipc::MessageBuffer::MessageHeader(svc::ipc::MessageBuffer(svc::ipc::GetMessageBuffer())).GetTag(); + const auto method_id = svc::ipc::MessageBuffer::MessageHeader(message_buffer).GetTag(); + + /* Ensure that we clean up any handles that get sent our way. */ + auto handle_guard = SCOPE_GUARD { + const svc::ipc::MessageBuffer::MessageHeader message_header(message_buffer); + const svc::ipc::MessageBuffer::SpecialHeader special_header(message_buffer, message_header); + + /* Determine the offset to the start of handles. */ + auto offset = message_buffer.GetSpecialDataIndex(message_header, special_header); + if (special_header.GetHasProcessId()) { + offset += sizeof(u64) / sizeof(u32); + } + + /* Close all copy handles. */ + for (auto i = 0; i < special_header.GetCopyHandleCount(); ++i) { + svc::CloseHandle(message_buffer.GetHandle(offset)); + offset += sizeof(ams::svc::Handle) / sizeof(u32); + } + }; /* Check that the method id is valid. */ R_UNLESS(method_id != MethodId_Invalid, tipc::ResultInvalidMethod()); /* If we're closing the object, do so. */ if (method_id == MethodId_CloseSession) { + /* Validate the command format. */ + { + using CloseSessionCommandMeta = impl::CommandMetaInfo>; + using CloseSessionProcessor = impl::CommandProcessor; + + /* Validate that the command is valid. */ + R_TRY(CloseSessionProcessor::ValidateCommandFormat(message_buffer)); + } + + /* Get the object handle. */ const auto handle = object.GetHandle(); /* Close the object itself. */ @@ -158,13 +189,16 @@ namespace ams::tipc { /* NOTE: Nintendo does not check that this succeeds. */ R_ABORT_UNLESS(svc::CloseHandle(handle)); - /* Return result to signify we closed the object. */ + /* Return result to signify we closed the object (and don't close input handles). */ + handle_guard.Cancel(); return tipc::ResultSessionClosed(); } /* Process the generic method for the object. */ R_TRY(object.GetObject()->ProcessRequest()); + /* We successfully processed, so we don't need to clean up handles. */ + handle_guard.Cancel(); return ResultSuccess(); } };