sf: prevent emitting mitm/defer code unless server in process supports it

This commit is contained in:
Michael Scire 2021-10-11 19:01:27 -07:00
parent d27fe8a229
commit bd1bcdf52b
21 changed files with 230 additions and 107 deletions

View file

@ -27,7 +27,7 @@ namespace ams::sf::hipc::impl {
class MitmQueryService {
private:
ServerManagerBase::MitmQueryFunction m_query_function;
const ServerManagerBase::MitmQueryFunction m_query_function;
public:
MitmQueryService(ServerManagerBase::MitmQueryFunction qf) : m_query_function(qf) { /* ... */ }

View file

@ -32,7 +32,7 @@ namespace ams::sf::hipc {
private:
ServerDomainSessionManager *m_manager;
ServerSession *m_session;
bool m_is_mitm_session;
const bool m_is_mitm_session;
private:
Result CloneCurrentObjectImpl(sf::OutMoveHandle &out_client_handle, ServerSessionManager *tagged_manager) {
/* Clone the object. */
@ -47,9 +47,12 @@ namespace ams::sf::hipc {
if (!m_is_mitm_session) {
R_ABORT_UNLESS(tagged_manager->RegisterSession(server_handle, std::move(clone)));
} else {
/* Check that we can create a mitm session. */
AMS_ABORT_UNLESS(ServerManagerBase::CanAnyManageMitmServers());
/* Clone the forward service. */
std::shared_ptr<::Service> new_forward_service = std::move(ServerSession::CreateForwardService());
R_ABORT_UNLESS(serviceClone(m_session->m_forward_service.get(), new_forward_service.get()));
R_ABORT_UNLESS(serviceClone(util::GetReference(m_session->m_forward_service).get(), new_forward_service.get()));
R_ABORT_UNLESS(tagged_manager->RegisterMitmSession(server_handle, std::move(clone), std::move(new_forward_service)));
}
@ -58,7 +61,7 @@ namespace ams::sf::hipc {
return ResultSuccess();
}
public:
explicit HipcManagerImpl(ServerDomainSessionManager *m, ServerSession *s) : m_manager(m), m_session(s), m_is_mitm_session(s->m_forward_service != nullptr) {
explicit HipcManagerImpl(ServerDomainSessionManager *m, ServerSession *s) : m_manager(m), m_session(s), m_is_mitm_session(s->IsMitmSession()) {
/* ... */
}
@ -70,15 +73,18 @@ namespace ams::sf::hipc {
/* Set up the new domain object. */
cmif::DomainObjectId object_id = cmif::InvalidDomainObjectId;
if (m_is_mitm_session) {
/* Check that we can create a mitm session. */
AMS_ABORT_UNLESS(ServerManagerBase::CanAnyManageMitmServers());
/* Make a new shared pointer to manage the allocated domain. */
SharedPointer<cmif::MitmDomainServiceObject> cmif_domain(static_cast<cmif::MitmDomainServiceObject *>(domain), false);
/* Convert the remote session to domain. */
AMS_ABORT_UNLESS(m_session->m_forward_service->own_handle);
R_TRY(serviceConvertToDomain(m_session->m_forward_service.get()));
AMS_ABORT_UNLESS(util::GetReference(m_session->m_forward_service)->own_handle);
R_TRY(serviceConvertToDomain(util::GetReference(m_session->m_forward_service).get()));
/* The object ID reservation cannot fail here, as that would cause desynchronization from target domain. */
object_id = cmif::DomainObjectId{m_session->m_forward_service->object_id};
object_id = cmif::DomainObjectId{util::GetReference(m_session->m_forward_service)->object_id};
domain->ReserveSpecificIds(std::addressof(object_id), 1);
/* Register the object. */
@ -116,14 +122,17 @@ namespace ams::sf::hipc {
if (!object) {
R_UNLESS(m_is_mitm_session, sf::hipc::ResultDomainObjectNotFound());
/* Check that we can create a mitm session. */
AMS_ABORT_UNLESS(ServerManagerBase::CanAnyManageMitmServers());
os::NativeHandle handle;
R_TRY(cmifCopyFromCurrentDomain(m_session->m_forward_service->session, object_id.value, std::addressof(handle)));
R_TRY(cmifCopyFromCurrentDomain(util::GetReference(m_session->m_forward_service)->session, object_id.value, std::addressof(handle)));
out.SetValue(handle, false);
return ResultSuccess();
}
if (!m_is_mitm_session || object_id.value != serviceGetObjectId(m_session->m_forward_service.get())) {
if (!m_is_mitm_session || (ServerManagerBase::CanAnyManageMitmServers() && object_id.value != serviceGetObjectId(util::GetReference(m_session->m_forward_service).get()))) {
/* Create new session handles. */
os::NativeHandle server_handle, client_handle;
R_ABORT_UNLESS(hipc::CreateSession(std::addressof(server_handle), std::addressof(client_handle)));
@ -134,9 +143,12 @@ namespace ams::sf::hipc {
/* Set output client handle. */
out.SetValue(client_handle, false);
} else {
/* Check that we can create a mitm session. */
AMS_ABORT_UNLESS(ServerManagerBase::CanAnyManageMitmServers());
/* Copy from the target domain. */
os::NativeHandle new_forward_target;
R_TRY(cmifCopyFromCurrentDomain(m_session->m_forward_service->session, object_id.value, std::addressof(new_forward_target)));
R_TRY(cmifCopyFromCurrentDomain(util::GetReference(m_session->m_forward_service)->session, object_id.value, std::addressof(new_forward_target)));
/* Create new session handles. */
os::NativeHandle server_handle, client_handle;

View file

@ -114,21 +114,34 @@ namespace ams::sf::hipc {
ServerSession *session = static_cast<ServerSession *>(holder);
cmif::PointerAndSize tls_message(svc::GetThreadLocalRegion()->message_buffer, hipc::TlsMessageBufferSize);
const cmif::PointerAndSize &saved_message = session->m_saved_message;
AMS_ABORT_UNLESS(tls_message.GetSize() == saved_message.GetSize());
if (!session->m_has_received) {
R_TRY(this->ReceiveRequest(session, tls_message));
session->m_has_received = true;
std::memcpy(saved_message.GetPointer(), tls_message.GetPointer(), tls_message.GetSize());
} else {
/* We were deferred and are re-receiving, so just memcpy. */
std::memcpy(tls_message.GetPointer(), saved_message.GetPointer(), tls_message.GetSize());
}
if (this->CanDeferInvokeRequest()) {
const cmif::PointerAndSize &saved_message = session->m_saved_message;
AMS_ABORT_UNLESS(tls_message.GetSize() == saved_message.GetSize());
/* Treat a meta "Context Invalidated" message as a success. */
R_TRY_CATCH(this->ProcessRequest(session, tls_message)) {
R_CONVERT(sf::impl::ResultRequestInvalidated, ResultSuccess());
} R_END_TRY_CATCH;
if (!session->m_has_received) {
R_TRY(this->ReceiveRequest(session, tls_message));
session->m_has_received = true;
std::memcpy(saved_message.GetPointer(), tls_message.GetPointer(), tls_message.GetSize());
} else {
/* We were deferred and are re-receiving, so just memcpy. */
std::memcpy(tls_message.GetPointer(), saved_message.GetPointer(), tls_message.GetSize());
}
/* Treat a meta "Context Invalidated" message as a success. */
R_TRY_CATCH(this->ProcessRequest(session, tls_message)) {
R_CONVERT(sf::impl::ResultRequestInvalidated, ResultSuccess());
} R_END_TRY_CATCH;
} else {
if (!session->m_has_received) {
R_TRY(this->ReceiveRequest(session, tls_message));
session->m_has_received = true;
}
R_TRY_CATCH(this->ProcessRequest(session, tls_message)) {
R_CATCH(sf::ResultRequestDeferred) { AMS_ABORT("Request Deferred on server which does not support deferral"); }
R_CATCH(sf::impl::ResultRequestInvalidated) { AMS_ABORT("Request Invalidated on server which does not support deferral"); }
} R_END_TRY_CATCH;
}
return ResultSuccess();
}
@ -138,6 +151,7 @@ namespace ams::sf::hipc {
case UserDataTag::Server:
return this->ProcessForServer(holder);
case UserDataTag::MitmServer:
AMS_ABORT_UNLESS(this->CanManageMitmServers());
return this->ProcessForMitmServer(holder);
case UserDataTag::Session:
return this->ProcessForSession(holder);

View file

@ -40,7 +40,9 @@ namespace ams::sf::hipc {
}
Result ServerSession::ForwardRequest(const cmif::ServiceDispatchContext &ctx) const {
AMS_ABORT_UNLESS(ServerManagerBase::CanAnyManageMitmServers());
AMS_ABORT_UNLESS(this->IsMitmSession());
/* TODO: Support non-TLS messages? */
AMS_ABORT_UNLESS(m_saved_message.GetPointer() != nullptr);
AMS_ABORT_UNLESS(m_saved_message.GetSize() == TlsMessageBufferSize);
@ -55,7 +57,7 @@ namespace ams::sf::hipc {
PreProcessCommandBufferForMitm(ctx, m_pointer_buffer, reinterpret_cast<uintptr_t>(message_buffer));
/* Dispatch forwards. */
R_TRY(svc::SendSyncRequest(m_forward_service->session));
R_TRY(svc::SendSyncRequest(util::GetReference(m_forward_service)->session));
/* Parse, to ensure we catch any copy handles and close them. */
{
@ -114,6 +116,8 @@ namespace ams::sf::hipc {
}
Result ServerSessionManager::RegisterMitmSessionImpl(ServerSession *session_memory, os::NativeHandle mitm_session_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv) {
AMS_ABORT_UNLESS(ServerManagerBase::CanAnyManageMitmServers());
/* Create session object. */
std::construct_at(session_memory, mitm_session_handle, std::forward<cmif::ServiceObjectHolder>(obj), std::forward<std::shared_ptr<::Service>>(fsrv));
@ -122,8 +126,8 @@ namespace ams::sf::hipc {
session_memory->m_saved_message = this->GetSessionSavedMessageBuffer(session_memory);
/* Validate session pointer buffer. */
AMS_ABORT_UNLESS(session_memory->m_pointer_buffer.GetSize() >= session_memory->m_forward_service->pointer_buffer_size);
session_memory->m_pointer_buffer = cmif::PointerAndSize(session_memory->m_pointer_buffer.GetAddress(), session_memory->m_forward_service->pointer_buffer_size);
AMS_ABORT_UNLESS(session_memory->m_pointer_buffer.GetSize() >= util::GetReference(session_memory->m_forward_service)->pointer_buffer_size);
session_memory->m_pointer_buffer = cmif::PointerAndSize(session_memory->m_pointer_buffer.GetAddress(), util::GetReference(session_memory->m_forward_service)->pointer_buffer_size);
/* Register to wait list. */
this->RegisterServerSessionToWait(session_memory);
@ -131,6 +135,8 @@ namespace ams::sf::hipc {
}
Result ServerSessionManager::AcceptMitmSessionImpl(ServerSession *session_memory, os::NativeHandle mitm_port_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv) {
AMS_ABORT_UNLESS(ServerManagerBase::CanAnyManageMitmServers());
/* Create session handle. */
os::NativeHandle mitm_session_handle;
R_TRY(svc::AcceptSession(std::addressof(mitm_session_handle), mitm_port_handle));
@ -201,7 +207,7 @@ namespace ams::sf::hipc {
namespace {
NX_CONSTEXPR u32 GetCmifCommandType(const cmif::PointerAndSize &message) {
constexpr ALWAYS_INLINE u32 GetCmifCommandType(const cmif::PointerAndSize &message) {
HipcHeader hdr = {};
__builtin_memcpy(std::addressof(hdr), message.GetPointer(), sizeof(hdr));
return hdr.type;