sf: implement mitm forwarding + domains.

This commit is contained in:
Michael Scire
2019-10-21 02:45:52 -07:00
committed by SciresM
parent 0b22af1206
commit 4f455dacf4
14 changed files with 509 additions and 68 deletions

View File

@@ -63,8 +63,50 @@ namespace sts::sf::hipc {
}
Result ConvertCurrentObjectToDomain(sf::Out<cmif::DomainObjectId> out) {
/* TODO */
return ResultHipcOutOfDomains;
/* Allocate a domain. */
auto domain = this->manager->AllocateDomainServiceObject();
R_UNLESS(domain, ResultHipcOutOfDomains);
cmif::DomainObjectId object_id = cmif::InvalidDomainObjectId;
cmif::ServiceObjectHolder new_holder;
if (this->is_mitm_session) {
/* If we're a mitm session, we need to convert the remote session to domain. */
STS_ASSERT(session->forward_service->own_handle);
R_TRY_CLEANUP(serviceConvertToDomain(session->forward_service.get()), {
this->manager->FreeDomainServiceObject(domain);
});
/* The object ID reservation cannot fail here, as that would cause desynchronization from target domain. */
object_id = cmif::DomainObjectId{session->forward_service->object_id};
domain->ReserveSpecificIds(&object_id, 1);
/* Create new object. */
cmif::MitmDomainServiceObject *domain_ptr = static_cast<cmif::MitmDomainServiceObject *>(domain);
new_holder = cmif::ServiceObjectHolder(std::move(std::shared_ptr<cmif::MitmDomainServiceObject>(domain_ptr, [&](cmif::MitmDomainServiceObject *obj) {
this->manager->FreeDomainServiceObject(domain);
})));
} else {
/* We're not a mitm session. Reserve a new object in the domain. */
R_TRY(domain->ReserveIds(&object_id, 1));
/* Create new object. */
cmif::DomainServiceObject *domain_ptr = static_cast<cmif::DomainServiceObject *>(domain);
new_holder = cmif::ServiceObjectHolder(std::move(std::shared_ptr<cmif::DomainServiceObject>(domain_ptr, [&](cmif::DomainServiceObject *obj) {
this->manager->FreeDomainServiceObject(domain);
})));
}
STS_ASSERT(object_id != cmif::InvalidDomainObjectId);
STS_ASSERT(static_cast<bool>(new_holder));
/* We succeeded! */
domain->RegisterObject(object_id, std::move(session->srv_obj_holder));
session->srv_obj_holder = std::move(new_holder);
out.SetValue(object_id);
return ResultSuccess;
}
Result CopyFromCurrentDomain(sf::OutMoveHandle out, cmif::DomainObjectId object_id) {

View File

@@ -17,6 +17,57 @@
namespace sts::sf::hipc {
namespace {
constexpr inline void PreProcessCommandBufferForMitm(const cmif::ServiceDispatchContext &ctx, const cmif::PointerAndSize &pointer_buffer, uintptr_t cmd_buffer) {
/* TODO: Less gross method of editing command buffer? */
if (ctx.request.meta.send_pid) {
constexpr u64 MitmProcessIdTag = 0xFFFE000000000000ul;
constexpr u64 OldProcessIdMask = 0x0000FFFFFFFFFFFFul;
u64 *process_id = reinterpret_cast<u64 *>(cmd_buffer + sizeof(HipcHeader) + sizeof(HipcSpecialHeader));
*process_id = (MitmProcessIdTag) | (*process_id & OldProcessIdMask);
}
if (ctx.request.meta.num_recv_statics) {
/* TODO: Can we do this without gross bit-hackery? */
reinterpret_cast<HipcHeader *>(cmd_buffer)->recv_static_mode = 2;
const uintptr_t old_recv_list_entry = reinterpret_cast<uintptr_t>(ctx.request.data.recv_list);
const size_t old_recv_list_offset = old_recv_list_entry - util::AlignDown(old_recv_list_entry, TlsMessageBufferSize);
*reinterpret_cast<HipcRecvListEntry *>(cmd_buffer + old_recv_list_offset) = hipcMakeRecvStatic(pointer_buffer.GetPointer(), pointer_buffer.GetSize());
}
}
}
Result ServerSession::ForwardRequest(const cmif::ServiceDispatchContext &ctx) const {
STS_ASSERT(this->IsMitmSession());
/* TODO: Support non-TLS messages? */
STS_ASSERT(this->saved_message.GetPointer() != nullptr);
STS_ASSERT(this->saved_message.GetSize() == TlsMessageBufferSize);
/* Copy saved TLS in. */
std::memcpy(armGetTls(), this->saved_message.GetPointer(), this->saved_message.GetSize());
/* Prepare buffer. */
PreProcessCommandBufferForMitm(ctx, this->pointer_buffer, reinterpret_cast<uintptr_t>(armGetTls()));
/* Dispatch forwards. */
R_TRY(svcSendSyncRequest(this->forward_service->session));
/* Parse, to ensure we catch any copy handles and close them. */
{
const auto response = hipcParseResponse(armGetTls());
if (response.num_copy_handles) {
ctx.handles_to_close->num_handles = response.num_copy_handles;
for (size_t i = 0; i < response.num_copy_handles; i++) {
ctx.handles_to_close->handles[i] = response.copy_handles[i];
}
}
}
return ResultSuccess;
}
void ServerSessionManager::DestroySession(ServerSession *session) {
/* Destroy object. */
session->~ServerSession();
@@ -63,6 +114,9 @@ namespace sts::sf::hipc {
/* Assign session resources. */
session_memory->pointer_buffer = this->GetSessionPointerBuffer(session_memory);
session_memory->saved_message = this->GetSessionSavedMessageBuffer(session_memory);
/* Validate session pointer buffer. */
STS_ASSERT(session_memory->pointer_buffer.GetSize() >= session_memory->forward_service->pointer_buffer_size);
session_memory->pointer_buffer = cmif::PointerAndSize(session_memory->pointer_buffer.GetAddress(), session_memory->forward_service->pointer_buffer_size);
/* Register to wait list. */
this->RegisterSessionToWaitList(session_memory);
return ResultSuccess;
@@ -205,6 +259,7 @@ namespace sts::sf::hipc {
cmif::ServiceDispatchContext dispatch_ctx = {
.srv_obj = obj_holder.GetServiceObjectUnsafe(),
.manager = this,
.session = session,
.processor = nullptr, /* Filled in by template implementations. */
.handles_to_close = &handles_to_close,
.pointer_buffer = session->pointer_buffer,