mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-12-22 18:32:05 +00:00
sf: implement mitm forwarding + domains.
This commit is contained in:
parent
0b22af1206
commit
4f455dacf4
14 changed files with 509 additions and 68 deletions
|
@ -19,18 +19,20 @@
|
|||
|
||||
static constexpr u32 Module_ServiceFramework = 10;
|
||||
|
||||
static constexpr Result ResultServiceFrameworkNotSupported = MAKERESULT(Module_ServiceFramework, 1);
|
||||
static constexpr Result ResultServiceFrameworkPreconditionViolation = MAKERESULT(Module_ServiceFramework, 3);
|
||||
static constexpr Result ResultServiceFrameworkNotSupported = MAKERESULT(Module_ServiceFramework, 1);
|
||||
static constexpr Result ResultServiceFrameworkPreconditionViolation = MAKERESULT(Module_ServiceFramework, 3);
|
||||
|
||||
static constexpr Result ResultServiceFrameworkInvalidCmifHeaderSize = MAKERESULT(Module_ServiceFramework, 202);
|
||||
static constexpr Result ResultServiceFrameworkInvalidCmifInHeader = MAKERESULT(Module_ServiceFramework, 211);
|
||||
static constexpr Result ResultServiceFrameworkUnknownCmifCommandId = MAKERESULT(Module_ServiceFramework, 221);
|
||||
static constexpr Result ResultServiceFrameworkInvalidCmifOutRawSize = MAKERESULT(Module_ServiceFramework, 232);
|
||||
static constexpr Result ResultServiceFrameworkInvalidCmifHeaderSize = MAKERESULT(Module_ServiceFramework, 202);
|
||||
static constexpr Result ResultServiceFrameworkInvalidCmifInHeader = MAKERESULT(Module_ServiceFramework, 211);
|
||||
static constexpr Result ResultServiceFrameworkUnknownCmifCommandId = MAKERESULT(Module_ServiceFramework, 221);
|
||||
static constexpr Result ResultServiceFrameworkInvalidCmifOutRawSize = MAKERESULT(Module_ServiceFramework, 232);
|
||||
static constexpr Result ResultServiceFrameworkInvalidCmifNumInObjects = MAKERESULT(Module_ServiceFramework, 235);
|
||||
static constexpr Result ResultServiceFrameworkInvalidCmifNumOutObjects = MAKERESULT(Module_ServiceFramework, 236);
|
||||
|
||||
static constexpr Result ResultServiceFrameworkTargetNotFound = MAKERESULT(Module_ServiceFramework, 261);
|
||||
static constexpr Result ResultServiceFrameworkTargetNotFound = MAKERESULT(Module_ServiceFramework, 261);
|
||||
|
||||
static constexpr Result ResultServiceFrameworkOutOfDomainEntries = MAKERESULT(Module_ServiceFramework, 301);
|
||||
static constexpr Result ResultServiceFrameworkOutOfDomainEntries = MAKERESULT(Module_ServiceFramework, 301);
|
||||
|
||||
|
||||
static constexpr Result ResultServiceFrameworkRequestDeferred = MAKERESULT(Module_ServiceFramework, 811);
|
||||
static constexpr Result ResultServiceFrameworkRequestDeferredByUser = MAKERESULT(Module_ServiceFramework, 812);
|
||||
static constexpr Result ResultServiceFrameworkRequestDeferred = MAKERESULT(Module_ServiceFramework, 811);
|
||||
static constexpr Result ResultServiceFrameworkRequestDeferredByUser = MAKERESULT(Module_ServiceFramework, 812);
|
||||
|
|
|
@ -57,7 +57,7 @@ namespace sts::sf::cmif {
|
|||
class ServerDomainBase {
|
||||
public:
|
||||
virtual Result ReserveIds(DomainObjectId *out_ids, size_t count) = 0;
|
||||
virtual Result AlterReservedIds(const DomainObjectId *old_reserved_ids, const DomainObjectId *new_reserved_ids, size_t count) = 0;
|
||||
virtual void ReserveSpecificIds(const DomainObjectId *ids, size_t count) = 0;
|
||||
virtual void UnreserveIds(const DomainObjectId *ids, size_t count) = 0;
|
||||
virtual void RegisterObject(DomainObjectId id, ServiceObjectHolder &&obj) = 0;
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ namespace sts::sf::cmif {
|
|||
}
|
||||
|
||||
virtual Result ReserveIds(DomainObjectId *out_ids, size_t count) override final;
|
||||
virtual Result AlterReservedIds(const DomainObjectId *old_reserved_ids, const DomainObjectId *new_reserved_ids, size_t count) override final;
|
||||
virtual void ReserveSpecificIds(const DomainObjectId *ids, size_t count) override final;
|
||||
virtual void UnreserveIds(const DomainObjectId *ids, size_t count) override final;
|
||||
virtual void RegisterObject(DomainObjectId id, ServiceObjectHolder &&obj) override final;
|
||||
|
||||
|
@ -81,7 +81,7 @@ namespace sts::sf::cmif {
|
|||
Entry *AllocateEntry();
|
||||
void FreeEntry(Entry *);
|
||||
|
||||
void ReallocateEntries(const DomainObjectId *old_reserved_ids, const DomainObjectId *new_reserved_ids, size_t count);
|
||||
void AllocateSpecificEntries(const DomainObjectId *ids, size_t count);
|
||||
|
||||
inline DomainObjectId GetId(Entry *e) {
|
||||
const size_t index = e - this->entries;
|
||||
|
@ -116,6 +116,11 @@ namespace sts::sf::cmif {
|
|||
}
|
||||
return new (storage) Domain(this);
|
||||
}
|
||||
|
||||
inline void FreeDomainServiceObject(DomainServiceObject *object) {
|
||||
static_cast<Domain *>(object)->~Domain();
|
||||
this->FreeDomain(object);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -24,8 +24,10 @@ namespace sts::sf::cmif {
|
|||
class DomainServiceObjectDispatchTable : public impl::ServiceDispatchTableBase {
|
||||
private:
|
||||
Result ProcessMessageImpl(ServiceDispatchContext &ctx, ServerDomainBase *domain, const cmif::PointerAndSize &in_raw_data) const;
|
||||
Result ProcessMessageForMitmImpl(ServiceDispatchContext &ctx, ServerDomainBase *domain, const cmif::PointerAndSize &in_raw_data) const;
|
||||
public:
|
||||
Result ProcessMessage(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const;
|
||||
Result ProcessMessageForMitm(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const;
|
||||
};
|
||||
|
||||
|
||||
|
@ -33,6 +35,30 @@ namespace sts::sf::cmif {
|
|||
private:
|
||||
ServerMessageProcessor *impl_processor;
|
||||
ServerDomainBase *domain;
|
||||
DomainObjectId *in_object_ids;
|
||||
DomainObjectId *out_object_ids;
|
||||
size_t num_in_objects;
|
||||
ServerMessageRuntimeMetadata impl_metadata;
|
||||
public:
|
||||
DomainServiceObjectProcessor(ServerDomainBase *d, DomainObjectId *in_obj_ids, size_t num_in_objs) : domain(d), in_object_ids(in_obj_ids), num_in_objects(num_in_objs) {
|
||||
STS_ASSERT(this->domain != nullptr);
|
||||
STS_ASSERT(this->in_object_ids != nullptr);
|
||||
this->impl_processor = nullptr;
|
||||
this->out_object_ids = nullptr;
|
||||
this->impl_metadata = {};
|
||||
}
|
||||
|
||||
constexpr size_t GetInObjectCount() const {
|
||||
return this->num_in_objects;
|
||||
}
|
||||
|
||||
constexpr size_t GetOutObjectCount() const {
|
||||
return this->impl_metadata.GetOutObjectCount();
|
||||
}
|
||||
|
||||
constexpr size_t GetImplOutDataTotalSize() const {
|
||||
return this->impl_metadata.GetOutDataSize() + this->impl_metadata.GetOutHeadersSize();
|
||||
}
|
||||
public:
|
||||
/* Used to enabled templated message processors. */
|
||||
virtual void SetImplementationProcessor(ServerMessageProcessor *impl) override final {
|
||||
|
@ -41,16 +67,32 @@ namespace sts::sf::cmif {
|
|||
} else {
|
||||
this->impl_processor->SetImplementationProcessor(impl);
|
||||
}
|
||||
|
||||
this->impl_metadata = this->impl_processor->GetRuntimeMetadata();
|
||||
}
|
||||
|
||||
virtual Result PrepareForProcess(const ServiceDispatchContext &ctx, size_t &headers_size) const override final;
|
||||
virtual const ServerMessageRuntimeMetadata GetRuntimeMetadata() const override final {
|
||||
const auto runtime_metadata = this->impl_processor->GetRuntimeMetadata();
|
||||
|
||||
return ServerMessageRuntimeMetadata {
|
||||
.in_data_size = static_cast<u16>(runtime_metadata.GetInDataSize() + runtime_metadata.GetInObjectCount() * sizeof(DomainObjectId)),
|
||||
.out_data_size = static_cast<u16>(runtime_metadata.GetOutDataSize() + runtime_metadata.GetOutObjectCount() * sizeof(DomainObjectId)),
|
||||
.in_headers_size = static_cast<u8>(runtime_metadata.GetInHeadersSize() + sizeof(CmifDomainInHeader)),
|
||||
.out_headers_size = static_cast<u8>(runtime_metadata.GetOutHeadersSize() + sizeof(CmifDomainOutHeader)),
|
||||
.in_object_count = 0,
|
||||
.out_object_count = 0,
|
||||
};
|
||||
}
|
||||
|
||||
virtual Result PrepareForProcess(const ServiceDispatchContext &ctx, const ServerMessageRuntimeMetadata runtime_metadata) const override final;
|
||||
virtual Result GetInObjects(ServiceObjectHolder *in_objects) const override final;
|
||||
virtual HipcRequest PrepareForReply(const cmif::ServiceDispatchContext &ctx, PointerAndSize &out_raw_data, const size_t headers_size, size_t &num_out_object_handles) override final;
|
||||
virtual void PrepareForErrorReply(const cmif::ServiceDispatchContext &ctx, PointerAndSize &out_raw_data, const size_t headers_size) override final;
|
||||
virtual HipcRequest PrepareForReply(const cmif::ServiceDispatchContext &ctx, PointerAndSize &out_raw_data, const ServerMessageRuntimeMetadata runtime_metadata) override final;
|
||||
virtual void PrepareForErrorReply(const cmif::ServiceDispatchContext &ctx, PointerAndSize &out_raw_data, const ServerMessageRuntimeMetadata runtime_metadata) override final;
|
||||
virtual void SetOutObjects(const cmif::ServiceDispatchContext &ctx, const HipcRequest &response, ServiceObjectHolder *out_objects, DomainObjectId *ids) override final;
|
||||
};
|
||||
|
||||
class DomainServiceObject : public IServiceObject, public ServerDomainBase {
|
||||
friend class DomainServiceObjectDispatchTable;
|
||||
public:
|
||||
static constexpr inline DomainServiceObjectDispatchTable s_CmifServiceDispatchTable{};
|
||||
private:
|
||||
|
@ -59,6 +101,8 @@ namespace sts::sf::cmif {
|
|||
/* TODO: Implement to use domain object processor. */
|
||||
};
|
||||
|
||||
class MitmDomainServiceObject : public DomainServiceObject{};
|
||||
|
||||
template<>
|
||||
struct ServiceDispatchTraits<DomainServiceObject> {
|
||||
static_assert(std::is_base_of<sf::IServiceObject, DomainServiceObject>::value, "DomainServiceObject must derive from sf::IServiceObject");
|
||||
|
@ -71,4 +115,16 @@ namespace sts::sf::cmif {
|
|||
static constexpr inline ServiceDispatchMeta Meta{&DomainServiceObject::s_CmifServiceDispatchTable, ProcessHandlerImpl};
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ServiceDispatchTraits<MitmDomainServiceObject> {
|
||||
static_assert(std::is_base_of<DomainServiceObject, MitmDomainServiceObject>::value, "MitmDomainServiceObject must derive from DomainServiceObject");
|
||||
using ProcessHandlerType = decltype(ServiceDispatchMeta::ProcessHandler);
|
||||
|
||||
using DispatchTableType = DomainServiceObjectDispatchTable;
|
||||
static constexpr ProcessHandlerType ProcessHandlerImpl = &impl::ServiceDispatchTableBase::ProcessMessageForMitm<DispatchTableType>;
|
||||
|
||||
static constexpr inline ServiceDispatchMeta Meta{&DomainServiceObject::s_CmifServiceDispatchTable, ProcessHandlerImpl};
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -25,15 +25,57 @@ namespace sts::sf::cmif {
|
|||
class ServiceObjectHolder;
|
||||
struct DomainObjectId;
|
||||
|
||||
/* This is needed for non-templated domain message processing. */
|
||||
struct ServerMessageRuntimeMetadata {
|
||||
u16 in_data_size;
|
||||
u16 out_data_size;
|
||||
u8 in_headers_size;
|
||||
u8 out_headers_size;
|
||||
u8 in_object_count;
|
||||
u8 out_object_count;
|
||||
|
||||
constexpr size_t GetInDataSize() const {
|
||||
return size_t(this->in_data_size);
|
||||
}
|
||||
|
||||
constexpr size_t GetOutDataSize() const {
|
||||
return size_t(this->out_data_size);
|
||||
}
|
||||
|
||||
constexpr size_t GetInHeadersSize() const {
|
||||
return size_t(this->in_headers_size);
|
||||
}
|
||||
|
||||
constexpr size_t GetOutHeadersSize() const {
|
||||
return size_t(this->out_headers_size);
|
||||
}
|
||||
|
||||
constexpr size_t GetInObjectCount() const {
|
||||
return size_t(this->in_object_count);
|
||||
}
|
||||
|
||||
constexpr size_t GetOutObjectCount() const {
|
||||
return size_t(this->out_object_count);
|
||||
}
|
||||
|
||||
constexpr size_t GetUnfixedOutPointerSizeOffset() const {
|
||||
return this->GetInDataSize() + this->GetInHeadersSize() + 0x10 /* padding. */;
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(std::is_pod<ServerMessageRuntimeMetadata>::value, "std::is_pod<ServerMessageRuntimeMetadata>::value");
|
||||
static_assert(sizeof(ServerMessageRuntimeMetadata) == sizeof(u64), "sizeof(ServerMessageRuntimeMetadata)");
|
||||
|
||||
class ServerMessageProcessor {
|
||||
public:
|
||||
/* Used to enabled templated message processors. */
|
||||
virtual void SetImplementationProcessor(ServerMessageProcessor *impl) { /* ... */ }
|
||||
virtual const ServerMessageRuntimeMetadata GetRuntimeMetadata() const = 0;
|
||||
|
||||
virtual Result PrepareForProcess(const ServiceDispatchContext &ctx, size_t &headers_size) const = 0;
|
||||
virtual Result PrepareForProcess(const ServiceDispatchContext &ctx, const ServerMessageRuntimeMetadata runtime_metadata) const = 0;
|
||||
virtual Result GetInObjects(ServiceObjectHolder *in_objects) const = 0;
|
||||
virtual HipcRequest PrepareForReply(const cmif::ServiceDispatchContext &ctx, PointerAndSize &out_raw_data, const size_t headers_size, size_t &num_out_object_handles) = 0;
|
||||
virtual void PrepareForErrorReply(const cmif::ServiceDispatchContext &ctx, PointerAndSize &out_raw_data, const size_t headers_size) = 0;
|
||||
virtual HipcRequest PrepareForReply(const cmif::ServiceDispatchContext &ctx, PointerAndSize &out_raw_data, const ServerMessageRuntimeMetadata runtime_metadata) = 0;
|
||||
virtual void PrepareForErrorReply(const cmif::ServiceDispatchContext &ctx, PointerAndSize &out_raw_data, const ServerMessageRuntimeMetadata runtime_metadata) = 0;
|
||||
virtual void SetOutObjects(const cmif::ServiceDispatchContext &ctx, const HipcRequest &response, ServiceObjectHolder *out_objects, DomainObjectId *ids) = 0;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
namespace sts::sf::hipc {
|
||||
|
||||
class ServerSessionManager;
|
||||
class ServerSession;
|
||||
|
||||
}
|
||||
|
||||
|
@ -37,6 +38,7 @@ namespace sts::sf::cmif {
|
|||
struct ServiceDispatchContext {
|
||||
sf::IServiceObject *srv_obj;
|
||||
hipc::ServerSessionManager *manager;
|
||||
hipc::ServerSession *session;
|
||||
ServerMessageProcessor *processor;
|
||||
HandlesToClose *handles_to_close;
|
||||
const PointerAndSize pointer_buffer;
|
||||
|
|
|
@ -28,6 +28,14 @@ namespace sts::sf::hipc {
|
|||
virtual Result DispatchManagerRequest(ServerSession *session, const cmif::PointerAndSize &in_message, const cmif::PointerAndSize &out_message) override final;
|
||||
public:
|
||||
ServerDomainSessionManager(DomainEntryStorage *entry_storage, size_t entry_count) : ServerDomainManager(entry_storage, entry_count) { /* ... */ }
|
||||
|
||||
inline cmif::DomainServiceObject *AllocateDomainServiceObject() {
|
||||
return cmif::ServerDomainManager::AllocateDomainServiceObject();
|
||||
}
|
||||
|
||||
inline void FreeDomainServiceObject(cmif::DomainServiceObject *object) {
|
||||
cmif::ServerDomainManager::FreeDomainServiceObject(object);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -21,6 +21,12 @@
|
|||
#include "../cmif/sf_cmif_service_object_holder.hpp"
|
||||
#include "sf_hipc_api.hpp"
|
||||
|
||||
namespace sts::sf::cmif {
|
||||
|
||||
struct ServiceDispatchContext;
|
||||
|
||||
}
|
||||
|
||||
namespace sts::sf::hipc {
|
||||
|
||||
class ServerSessionManager;
|
||||
|
@ -65,6 +71,8 @@ namespace sts::sf::hipc {
|
|||
bool IsMitmSession() const {
|
||||
return this->forward_service != nullptr;
|
||||
}
|
||||
|
||||
Result ForwardRequest(const cmif::ServiceDispatchContext &ctx) const;
|
||||
};
|
||||
|
||||
class ServerSessionManager {
|
||||
|
|
|
@ -442,8 +442,7 @@ namespace sts::sf::impl {
|
|||
|
||||
/* In/Out data marshalling. */
|
||||
static constexpr std::array<size_t, NumInDatas+1> InDataOffsets = RawDataOffsetCalculator<InDatas>::Offsets;
|
||||
static constexpr size_t InDataRawUnfixedOutPointerSizeOffset = util::AlignUp(InDataOffsets[NumInDatas] + 0x10, alignof(u16));
|
||||
static constexpr size_t InDataSize = util::AlignUp(util::AlignUp(InDataOffsets[NumInDatas], alignof(u16)) + sizeof(u16) * NumUnfixedSizeOutHipcPointerBuffers, alignof(u32));
|
||||
static constexpr size_t InDataSize = util::AlignUp(InDataOffsets[NumInDatas], alignof(u16));
|
||||
|
||||
static constexpr std::array<size_t, NumOutDatas+1> OutDataOffsets = RawDataOffsetCalculator<OutDatas>::Offsets;
|
||||
static constexpr size_t OutDataSize = util::AlignUp(OutDataOffsets[NumOutDatas], alignof(u32));
|
||||
|
@ -464,6 +463,16 @@ namespace sts::sf::impl {
|
|||
static_assert(NumInMoveHandles + NumInCopyHandles == NumInHandles, "NumInMoveHandles + NumInCopyHandles == NumInHandles");
|
||||
static_assert(NumOutMoveHandles + NumOutCopyHandles == NumOutHandles, "NumOutMoveHandles + NumOutCopyHandles == NumOutHandles");
|
||||
|
||||
/* Used by server message processor at runtime. */
|
||||
static constexpr inline const cmif::ServerMessageRuntimeMetadata RuntimeMetadata = cmif::ServerMessageRuntimeMetadata{
|
||||
.in_data_size = InDataSize,
|
||||
.out_data_size = OutDataSize,
|
||||
.in_headers_size = sizeof(CmifInHeader),
|
||||
.out_headers_size = sizeof(CmifOutHeader),
|
||||
.in_object_count = NumInObjects,
|
||||
.out_object_count = NumOutObjects,
|
||||
};
|
||||
|
||||
/* Construction of argument serialization structs. */
|
||||
private:
|
||||
template<typename>
|
||||
|
@ -686,7 +695,11 @@ namespace sts::sf::impl {
|
|||
template<typename CommandMeta>
|
||||
struct HipcCommandProcessor : public sf::cmif::ServerMessageProcessor {
|
||||
public:
|
||||
virtual Result PrepareForProcess(const cmif::ServiceDispatchContext &ctx, size_t &headers_size) const override final {
|
||||
virtual const cmif::ServerMessageRuntimeMetadata GetRuntimeMetadata() const override final {
|
||||
return CommandMeta::RuntimeMetadata;
|
||||
}
|
||||
|
||||
virtual Result PrepareForProcess(const cmif::ServiceDispatchContext &ctx, const cmif::ServerMessageRuntimeMetadata runtime_metadata) const override final {
|
||||
const auto &meta = ctx.request.meta;
|
||||
bool is_request_valid = true;
|
||||
is_request_valid &= meta.send_pid == CommandMeta::HasInProcessIdHolder;
|
||||
|
@ -699,30 +712,33 @@ namespace sts::sf::impl {
|
|||
is_request_valid &= meta.num_move_handles == CommandMeta::NumInMoveHandles;
|
||||
|
||||
const size_t meta_raw_size = meta.num_data_words * sizeof(u32);
|
||||
is_request_valid &= meta_raw_size >= CommandMeta::InDataSize + 0x10 /* padding */ + headers_size /* headers */;
|
||||
const size_t command_raw_size = util::AlignUp(runtime_metadata.GetUnfixedOutPointerSizeOffset() + (CommandMeta::NumUnfixedSizeOutHipcPointerBuffers * sizeof(u16)), alignof(u32));
|
||||
is_request_valid &= meta_raw_size >= command_raw_size;
|
||||
|
||||
R_UNLESS(is_request_valid, ResultHipcInvalidRequest);
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
virtual HipcRequest PrepareForReply(const cmif::ServiceDispatchContext &ctx, cmif::PointerAndSize &out_raw_data, const size_t headers_size, size_t &num_out_object_handles) override final {
|
||||
virtual HipcRequest PrepareForReply(const cmif::ServiceDispatchContext &ctx, cmif::PointerAndSize &out_raw_data, const cmif::ServerMessageRuntimeMetadata runtime_metadata) override final {
|
||||
const size_t raw_size = runtime_metadata.GetOutDataSize() + runtime_metadata.GetOutHeadersSize();
|
||||
const auto response = hipcMakeRequestInline(ctx.out_message_buffer.GetPointer(),
|
||||
.type = CmifCommandType_Invalid, /* Really response */
|
||||
.num_send_statics = CommandMeta::NumOutHipcPointerBuffers,
|
||||
.num_data_words = static_cast<u32>((util::AlignUp(CommandMeta::OutDataSize + headers_size, 0x4) + 0x10 /* padding */) / sizeof(u32)),
|
||||
.num_data_words = static_cast<u32>((util::AlignUp(raw_size, 0x4) + 0x10 /* padding */) / sizeof(u32)),
|
||||
.num_copy_handles = CommandMeta::NumOutCopyHandles,
|
||||
.num_move_handles = static_cast<u32>(CommandMeta::NumOutMoveHandles + num_out_object_handles),
|
||||
.num_move_handles = static_cast<u32>(CommandMeta::NumOutMoveHandles + runtime_metadata.GetOutObjectCount()),
|
||||
);
|
||||
out_raw_data = cmif::PointerAndSize(util::AlignUp(reinterpret_cast<uintptr_t>(response.data_words), 0x10), CommandMeta::OutDataSize + headers_size);
|
||||
out_raw_data = cmif::PointerAndSize(util::AlignUp(reinterpret_cast<uintptr_t>(response.data_words), 0x10), raw_size);
|
||||
return response;
|
||||
}
|
||||
|
||||
virtual void PrepareForErrorReply(const cmif::ServiceDispatchContext &ctx, cmif::PointerAndSize &out_raw_data, const size_t headers_size) override final {
|
||||
virtual void PrepareForErrorReply(const cmif::ServiceDispatchContext &ctx, cmif::PointerAndSize &out_raw_data, const cmif::ServerMessageRuntimeMetadata runtime_metadata) override final {
|
||||
const size_t raw_size = runtime_metadata.GetOutHeadersSize();
|
||||
const auto response = hipcMakeRequestInline(ctx.out_message_buffer.GetPointer(),
|
||||
.type = CmifCommandType_Invalid, /* Really response */
|
||||
.num_data_words = static_cast<u32>((util::AlignUp(headers_size, 0x4) + 0x10 /* padding */) / sizeof(u32)),
|
||||
.num_data_words = static_cast<u32>((util::AlignUp(raw_size, 0x4) + 0x10 /* padding */) / sizeof(u32)),
|
||||
);
|
||||
out_raw_data = cmif::PointerAndSize(util::AlignUp(reinterpret_cast<uintptr_t>(response.data_words), 0x10), headers_size);
|
||||
out_raw_data = cmif::PointerAndSize(util::AlignUp(reinterpret_cast<uintptr_t>(response.data_words), 0x10), raw_size);
|
||||
}
|
||||
|
||||
virtual Result GetInObjects(cmif::ServiceObjectHolder *in_objects) const override final {
|
||||
|
@ -789,7 +805,7 @@ namespace sts::sf::impl {
|
|||
}();
|
||||
|
||||
template<size_t BufferIndex, size_t Index = GetIndexFromBufferIndex<BufferIndex>>
|
||||
NX_CONSTEXPR void ProcessBufferImpl(const cmif::ServiceDispatchContext &ctx, cmif::PointerAndSize &buffer, bool &is_buffer_map_alias, bool &map_alias_buffers_valid, size_t &pointer_buffer_head, size_t &pointer_buffer_tail, size_t in_headers_size) {
|
||||
NX_CONSTEXPR void ProcessBufferImpl(const cmif::ServiceDispatchContext &ctx, cmif::PointerAndSize &buffer, bool &is_buffer_map_alias, bool &map_alias_buffers_valid, size_t &pointer_buffer_head, size_t &pointer_buffer_tail, const cmif::ServerMessageRuntimeMetadata runtime_metadata) {
|
||||
static_assert(Index != std::numeric_limits<size_t>::max(), "Invalid Index From Buffer Index");
|
||||
constexpr auto Info = CommandMeta::ArgumentSerializationInfos[Index];
|
||||
constexpr auto Attributes = CommandMeta::BufferAttributes[BufferIndex];
|
||||
|
@ -824,7 +840,7 @@ namespace sts::sf::impl {
|
|||
pointer_buffer_head = util::AlignDown(pointer_buffer_head - size, 0x10);
|
||||
buffer = cmif::PointerAndSize(pointer_buffer_head, size);
|
||||
} else {
|
||||
const u16 *recv_pointer_sizes = reinterpret_cast<const u16 *>(reinterpret_cast<uintptr_t>(ctx.request.data.data_words) + in_headers_size + CommandMeta::InDataRawUnfixedOutPointerSizeOffset);
|
||||
const u16 *recv_pointer_sizes = reinterpret_cast<const u16 *>(reinterpret_cast<uintptr_t>(ctx.request.data.data_words) + runtime_metadata.GetUnfixedOutPointerSizeOffset());
|
||||
const size_t size = size_t(recv_pointer_sizes[Info.unfixed_recv_pointer_index]);
|
||||
pointer_buffer_head = util::AlignDown(pointer_buffer_head - size, 0x10);
|
||||
buffer = cmif::PointerAndSize(pointer_buffer_head, size);
|
||||
|
@ -860,7 +876,7 @@ namespace sts::sf::impl {
|
|||
pointer_buffer_head = util::AlignDown(pointer_buffer_head - size, 0x10);
|
||||
buffer = cmif::PointerAndSize(pointer_buffer_head, size);
|
||||
} else {
|
||||
const u16 *recv_pointer_sizes = reinterpret_cast<const u16 *>(reinterpret_cast<uintptr_t>(ctx.request.data.data_words) + CommandMeta::InDataRawUnfixedOutPointerSizeOffset);
|
||||
const u16 *recv_pointer_sizes = reinterpret_cast<const u16 *>(reinterpret_cast<uintptr_t>(ctx.request.data.data_words) + runtime_metadata.GetUnfixedOutPointerSizeOffset());
|
||||
const size_t size = size_t(recv_pointer_sizes[Info.unfixed_recv_pointer_index]);
|
||||
pointer_buffer_head = util::AlignDown(pointer_buffer_head - size, 0x10);
|
||||
buffer = cmif::PointerAndSize(pointer_buffer_head, size);
|
||||
|
@ -894,11 +910,11 @@ namespace sts::sf::impl {
|
|||
}
|
||||
}
|
||||
public:
|
||||
NX_CONSTEXPR Result ProcessBuffers(const cmif::ServiceDispatchContext &ctx, BufferArrayType &buffers, std::array<bool, CommandMeta::NumBuffers> &is_buffer_map_alias, size_t in_headers_size) {
|
||||
NX_CONSTEXPR Result ProcessBuffers(const cmif::ServiceDispatchContext &ctx, BufferArrayType &buffers, std::array<bool, CommandMeta::NumBuffers> &is_buffer_map_alias, const cmif::ServerMessageRuntimeMetadata runtime_metadata) {
|
||||
bool map_alias_buffers_valid = true;
|
||||
size_t pointer_buffer_tail = ctx.pointer_buffer.GetAddress();
|
||||
size_t pointer_buffer_head = pointer_buffer_tail + ctx.pointer_buffer.GetSize();
|
||||
#define _SF_IMPL_PROCESSOR_PROCESS_BUFFER_IMPL(n) do { if constexpr (CommandMeta::NumBuffers > n) { ProcessBufferImpl<n>(ctx, buffers[n], is_buffer_map_alias[n], map_alias_buffers_valid, pointer_buffer_head, pointer_buffer_tail, in_headers_size); } } while (0)
|
||||
#define _SF_IMPL_PROCESSOR_PROCESS_BUFFER_IMPL(n) do { if constexpr (CommandMeta::NumBuffers > n) { ProcessBufferImpl<n>(ctx, buffers[n], is_buffer_map_alias[n], map_alias_buffers_valid, pointer_buffer_head, pointer_buffer_tail, runtime_metadata); } } while (0)
|
||||
_SF_IMPL_PROCESSOR_PROCESS_BUFFER_IMPL(0);
|
||||
_SF_IMPL_PROCESSOR_PROCESS_BUFFER_IMPL(1);
|
||||
_SF_IMPL_PROCESSOR_PROCESS_BUFFER_IMPL(2);
|
||||
|
@ -1032,8 +1048,8 @@ namespace sts::sf::impl {
|
|||
}
|
||||
|
||||
/* Validate the metadata has the expected counts. */
|
||||
size_t in_headers_size = sizeof(CmifInHeader);
|
||||
R_TRY(ctx.processor->PrepareForProcess(ctx, in_headers_size));
|
||||
const auto runtime_metadata = ctx.processor->GetRuntimeMetadata();
|
||||
R_TRY(ctx.processor->PrepareForProcess(ctx, runtime_metadata));
|
||||
|
||||
/* Storage for output. */
|
||||
BufferArrayType buffers;
|
||||
|
@ -1043,7 +1059,7 @@ namespace sts::sf::impl {
|
|||
InOutObjectHolderType in_out_objects_holder;
|
||||
|
||||
/* Process buffers. */
|
||||
R_TRY(ImplProcessorType::ProcessBuffers(ctx, buffers, is_buffer_map_alias, in_headers_size));
|
||||
R_TRY(ImplProcessorType::ProcessBuffers(ctx, buffers, is_buffer_map_alias, runtime_metadata));
|
||||
|
||||
/* Process input/output objects. */
|
||||
R_TRY(in_out_objects_holder.GetInObjects(ctx.processor));
|
||||
|
@ -1062,7 +1078,7 @@ namespace sts::sf::impl {
|
|||
if constexpr (CommandMeta::ReturnsResult) {
|
||||
R_TRY_CLEANUP(std::apply([=](auto&&... args) { return (this_ptr->*ServiceCommandImpl)(args...); }, args_tuple), {
|
||||
cmif::PointerAndSize out_raw_data;
|
||||
ctx.processor->PrepareForErrorReply(ctx, out_raw_data, sizeof(CmifOutHeader));
|
||||
ctx.processor->PrepareForErrorReply(ctx, out_raw_data, runtime_metadata);
|
||||
R_TRY(GetCmifOutHeaderPointer(out_header_ptr, out_raw_data));
|
||||
});
|
||||
} else {
|
||||
|
@ -1072,8 +1088,7 @@ namespace sts::sf::impl {
|
|||
|
||||
/* Encode. */
|
||||
cmif::PointerAndSize out_raw_data;
|
||||
size_t num_out_object_handles = CommandMeta::NumOutObjects;
|
||||
const auto response = ctx.processor->PrepareForReply(ctx, out_raw_data, sizeof(CmifOutHeader), num_out_object_handles);
|
||||
const auto response = ctx.processor->PrepareForReply(ctx, out_raw_data, runtime_metadata);
|
||||
R_TRY(GetCmifOutHeaderPointer(out_header_ptr, out_raw_data));
|
||||
|
||||
/* Copy raw data output struct. */
|
||||
|
@ -1084,7 +1099,7 @@ namespace sts::sf::impl {
|
|||
ImplProcessorType::SetOutBuffers(response, buffers, is_buffer_map_alias);
|
||||
|
||||
/* Set out handles. */
|
||||
out_handles_holder.CopyTo(response, num_out_object_handles);
|
||||
out_handles_holder.CopyTo(response, runtime_metadata.GetOutObjectCount());
|
||||
|
||||
/* Set output objects. */
|
||||
in_out_objects_holder.SetOutObjects(ctx, response);
|
||||
|
|
|
@ -41,9 +41,8 @@ namespace sts::sf::cmif {
|
|||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result ServerDomainManager::Domain::AlterReservedIds(const DomainObjectId *old_reserved_ids, const DomainObjectId *new_reserved_ids, size_t count) {
|
||||
this->manager->entry_manager.ReallocateEntries(old_reserved_ids, new_reserved_ids, count);
|
||||
return ResultSuccess;
|
||||
void ServerDomainManager::Domain::ReserveSpecificIds(const DomainObjectId *ids, size_t count) {
|
||||
this->manager->entry_manager.AllocateSpecificEntries(ids, count);
|
||||
}
|
||||
|
||||
void ServerDomainManager::Domain::UnreserveIds(const DomainObjectId *ids, size_t count) {
|
||||
|
@ -132,27 +131,16 @@ namespace sts::sf::cmif {
|
|||
this->free_list.push_front(*entry);
|
||||
}
|
||||
|
||||
void ServerDomainManager::EntryManager::ReallocateEntries(const DomainObjectId *old_reserved_ids, const DomainObjectId *new_reserved_ids, size_t count) {
|
||||
void ServerDomainManager::EntryManager::AllocateSpecificEntries(const DomainObjectId *ids, size_t count) {
|
||||
std::scoped_lock lk(this->lock);
|
||||
|
||||
/* Free old ids. */
|
||||
/* Allocate new IDs. */
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
const auto id = old_reserved_ids[i];
|
||||
const auto id = ids[i];
|
||||
Entry *entry = this->GetEntry(id);
|
||||
if (id != InvalidDomainObjectId) {
|
||||
STS_ASSERT(entry != nullptr);
|
||||
STS_ASSERT(entry->owner == nullptr);
|
||||
STS_ASSERT(!entry->object);
|
||||
this->free_list.push_front(*entry);
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate new IDs. */
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
const auto id = old_reserved_ids[i];
|
||||
Entry *entry = this->GetEntry(id);
|
||||
if (id != InvalidDomainObjectId) {
|
||||
STS_ASSERT(entry != nullptr);
|
||||
this->free_list.erase(this->free_list.iterator_to(*entry));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <functional>
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace sts::sf::cmif {
|
||||
|
||||
Result DomainServiceObjectDispatchTable::ProcessMessage(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const {
|
||||
return this->ProcessMessageImpl(ctx, static_cast<DomainServiceObject *>(ctx.srv_obj)->GetServerDomain(), in_raw_data);
|
||||
}
|
||||
|
||||
Result DomainServiceObjectDispatchTable::ProcessMessageForMitm(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const {
|
||||
return this->ProcessMessageForMitmImpl(ctx, static_cast<DomainServiceObject *>(ctx.srv_obj)->GetServerDomain(), in_raw_data);
|
||||
}
|
||||
|
||||
Result DomainServiceObjectDispatchTable::ProcessMessageImpl(ServiceDispatchContext &ctx, ServerDomainBase *domain, const cmif::PointerAndSize &in_raw_data) const {
|
||||
const CmifDomainInHeader *in_header = reinterpret_cast<const CmifDomainInHeader *>(in_raw_data.GetPointer());
|
||||
R_UNLESS(in_raw_data.GetSize() >= sizeof(*in_header), ResultServiceFrameworkInvalidCmifHeaderSize);
|
||||
const cmif::PointerAndSize in_domain_raw_data = cmif::PointerAndSize(in_raw_data.GetAddress() + sizeof(*in_header), in_raw_data.GetSize() - sizeof(*in_header));
|
||||
|
||||
const DomainObjectId target_object_id = DomainObjectId{in_header->object_id};
|
||||
switch (in_header->type) {
|
||||
case CmifDomainRequestType_SendMessage:
|
||||
{
|
||||
auto target_object = domain->GetObject(target_object_id);
|
||||
R_UNLESS(static_cast<bool>(target_object), ResultServiceFrameworkTargetNotFound);
|
||||
R_UNLESS(in_header->data_size + in_header->num_in_objects * sizeof(DomainObjectId) <= in_domain_raw_data.GetSize(), ResultServiceFrameworkInvalidCmifHeaderSize);
|
||||
const cmif::PointerAndSize in_message_raw_data = cmif::PointerAndSize(in_domain_raw_data.GetAddress(), in_header->data_size);
|
||||
DomainObjectId in_object_ids[8];
|
||||
R_UNLESS(in_header->num_in_objects <= util::size(in_object_ids), ResultServiceFrameworkInvalidCmifNumInObjects);
|
||||
std::memcpy(in_object_ids, reinterpret_cast<DomainObjectId *>(in_message_raw_data.GetAddress() + in_message_raw_data.GetSize()), sizeof(DomainObjectId) * in_header->num_in_objects);
|
||||
DomainServiceObjectProcessor domain_processor(domain, in_object_ids, in_header->num_in_objects);
|
||||
if (ctx.processor == nullptr) {
|
||||
ctx.processor = &domain_processor;
|
||||
} else {
|
||||
ctx.processor->SetImplementationProcessor(&domain_processor);
|
||||
}
|
||||
return target_object.ProcessMessage(ctx, in_message_raw_data);
|
||||
}
|
||||
case CmifDomainRequestType_Close:
|
||||
/* TODO: N doesn't error check here. Should we? */
|
||||
domain->UnregisterObject(target_object_id);
|
||||
return ResultSuccess;
|
||||
default:
|
||||
return ResultServiceFrameworkInvalidCmifInHeader;
|
||||
}
|
||||
}
|
||||
|
||||
Result DomainServiceObjectDispatchTable::ProcessMessageForMitmImpl(ServiceDispatchContext &ctx, ServerDomainBase *domain, const cmif::PointerAndSize &in_raw_data) const {
|
||||
const CmifDomainInHeader *in_header = reinterpret_cast<const CmifDomainInHeader *>(in_raw_data.GetPointer());
|
||||
R_UNLESS(in_raw_data.GetSize() >= sizeof(*in_header), ResultServiceFrameworkInvalidCmifHeaderSize);
|
||||
const cmif::PointerAndSize in_domain_raw_data = cmif::PointerAndSize(in_raw_data.GetAddress() + sizeof(*in_header), in_raw_data.GetSize() - sizeof(*in_header));
|
||||
|
||||
const DomainObjectId target_object_id = DomainObjectId{in_header->object_id};
|
||||
switch (in_header->type) {
|
||||
case CmifDomainRequestType_SendMessage:
|
||||
{
|
||||
auto target_object = domain->GetObject(target_object_id);
|
||||
|
||||
/* Mitm. If we don't have a target object, we should forward to let the server handle. */
|
||||
if (!target_object) {
|
||||
return ctx.session->ForwardRequest(ctx);
|
||||
}
|
||||
|
||||
R_UNLESS(in_header->data_size + in_header->num_in_objects * sizeof(DomainObjectId) <= in_domain_raw_data.GetSize(), ResultServiceFrameworkInvalidCmifHeaderSize);
|
||||
const cmif::PointerAndSize in_message_raw_data = cmif::PointerAndSize(in_domain_raw_data.GetAddress(), in_header->data_size);
|
||||
DomainObjectId in_object_ids[8];
|
||||
R_UNLESS(in_header->num_in_objects <= util::size(in_object_ids), ResultServiceFrameworkInvalidCmifNumInObjects);
|
||||
std::memcpy(in_object_ids, reinterpret_cast<DomainObjectId *>(in_message_raw_data.GetAddress() + in_message_raw_data.GetSize()), sizeof(DomainObjectId) * in_header->num_in_objects);
|
||||
DomainServiceObjectProcessor domain_processor(domain, in_object_ids, in_header->num_in_objects);
|
||||
if (ctx.processor == nullptr) {
|
||||
ctx.processor = &domain_processor;
|
||||
} else {
|
||||
ctx.processor->SetImplementationProcessor(&domain_processor);
|
||||
}
|
||||
return target_object.ProcessMessage(ctx, in_message_raw_data);
|
||||
}
|
||||
case CmifDomainRequestType_Close:
|
||||
{
|
||||
auto target_object = domain->GetObject(target_object_id);
|
||||
|
||||
/* If the object is not in the domain, tell the server to close it. */
|
||||
if (!target_object) {
|
||||
return ctx.session->ForwardRequest(ctx);
|
||||
}
|
||||
|
||||
/* If the object is in the domain, close our copy of it. Mitm objects are required to close their associated domain id, so this shouldn't cause desynch. */
|
||||
domain->UnregisterObject(target_object_id);
|
||||
return ResultSuccess;
|
||||
}
|
||||
default:
|
||||
return ResultServiceFrameworkInvalidCmifInHeader;
|
||||
}
|
||||
}
|
||||
|
||||
Result DomainServiceObjectProcessor::PrepareForProcess(const ServiceDispatchContext &ctx, const ServerMessageRuntimeMetadata runtime_metadata) const {
|
||||
/* Validate in object count. */
|
||||
R_UNLESS(this->impl_metadata.GetInObjectCount() == this->GetInObjectCount(), ResultServiceFrameworkInvalidCmifNumInObjects);
|
||||
|
||||
/* Nintendo reserves domain object IDs here. We do this later, to support mitm semantics. */
|
||||
|
||||
/* Pass onwards. */
|
||||
return this->impl_processor->PrepareForProcess(ctx, runtime_metadata);
|
||||
}
|
||||
|
||||
Result DomainServiceObjectProcessor::GetInObjects(ServiceObjectHolder *in_objects) const {
|
||||
for (size_t i = 0; i < this->GetInObjectCount(); i++) {
|
||||
in_objects[i] = this->domain->GetObject(this->in_object_ids[i]);
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
HipcRequest DomainServiceObjectProcessor::PrepareForReply(const cmif::ServiceDispatchContext &ctx, PointerAndSize &out_raw_data, const ServerMessageRuntimeMetadata runtime_metadata) {
|
||||
/* Call into impl processor, get request. */
|
||||
PointerAndSize raw_data;
|
||||
HipcRequest request = this->impl_processor->PrepareForReply(ctx, raw_data, runtime_metadata);
|
||||
|
||||
/* Write out header. */
|
||||
constexpr size_t out_header_size = sizeof(CmifDomainOutHeader);
|
||||
const size_t impl_out_data_total_size = this->GetImplOutDataTotalSize();
|
||||
STS_ASSERT(out_header_size + impl_out_data_total_size + sizeof(DomainObjectId) * this->GetOutObjectCount() <= raw_data.GetSize());
|
||||
*reinterpret_cast<CmifDomainOutHeader *>(raw_data.GetPointer()) = CmifDomainOutHeader{ .num_out_objects = static_cast<u32>(this->GetOutObjectCount()), };
|
||||
|
||||
/* Set output raw data. */
|
||||
out_raw_data = cmif::PointerAndSize(raw_data.GetAddress() + out_header_size, raw_data.GetSize() - out_header_size);
|
||||
this->out_object_ids = reinterpret_cast<DomainObjectId *>(out_raw_data.GetAddress() + out_raw_data.GetSize());
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
void DomainServiceObjectProcessor::PrepareForErrorReply(const cmif::ServiceDispatchContext &ctx, PointerAndSize &out_raw_data, const ServerMessageRuntimeMetadata runtime_metadata) {
|
||||
/* Call into impl processor, get request. */
|
||||
PointerAndSize raw_data;
|
||||
this->impl_processor->PrepareForErrorReply(ctx, raw_data, runtime_metadata);
|
||||
|
||||
/* Write out header. */
|
||||
constexpr size_t out_header_size = sizeof(CmifDomainOutHeader);
|
||||
const size_t impl_out_data_total_size = this->GetImplOutDataTotalSize();
|
||||
STS_ASSERT(out_header_size + impl_out_data_total_size <= raw_data.GetSize());
|
||||
*reinterpret_cast<CmifDomainOutHeader *>(raw_data.GetPointer()) = CmifDomainOutHeader{ .num_out_objects = 0, };
|
||||
|
||||
/* Set output raw data. */
|
||||
out_raw_data = cmif::PointerAndSize(raw_data.GetAddress() + out_header_size, raw_data.GetSize() - out_header_size);
|
||||
|
||||
/* Nintendo unreserves domain entries here, but we haven't reserved them yet. */
|
||||
}
|
||||
|
||||
void DomainServiceObjectProcessor::SetOutObjects(const cmif::ServiceDispatchContext &ctx, const HipcRequest &response, ServiceObjectHolder *out_objects, DomainObjectId *selected_ids) {
|
||||
const size_t num_out_objects = this->GetOutObjectCount();
|
||||
|
||||
/* Copy input object IDs from command impl (normally these are Invalid, in mitm they should be set). */
|
||||
DomainObjectId object_ids[8];
|
||||
bool is_reserved[8];
|
||||
for (size_t i = 0; i < num_out_objects; i++) {
|
||||
object_ids[i] = selected_ids[i];
|
||||
is_reserved[i] = false;
|
||||
}
|
||||
|
||||
/* Reserve object IDs as necessary. */
|
||||
{
|
||||
DomainObjectId reservations[8];
|
||||
{
|
||||
size_t num_unreserved_ids = 0;
|
||||
DomainObjectId specific_ids[8];
|
||||
size_t num_specific_ids = 0;
|
||||
for (size_t i = 0; i < num_out_objects; i++) {
|
||||
/* In the mitm case, we must not reserve IDs in use by other objects, so mitm objects will set this. */
|
||||
if (object_ids[i] == InvalidDomainObjectId) {
|
||||
num_unreserved_ids++;
|
||||
} else {
|
||||
specific_ids[num_specific_ids++] = object_ids[i];
|
||||
}
|
||||
}
|
||||
/* TODO: Can we make this error non-fatal? It isn't for N, since they can reserve IDs earlier due to not having to worry about mitm. */
|
||||
R_ASSERT(this->domain->ReserveIds(reservations, num_unreserved_ids));
|
||||
this->domain->ReserveSpecificIds(specific_ids, num_specific_ids);
|
||||
}
|
||||
|
||||
size_t reservation_index = 0;
|
||||
for (size_t i = 0; i < num_out_objects; i++) {
|
||||
if (object_ids[i] == InvalidDomainObjectId) {
|
||||
object_ids[i] = reservations[reservation_index++];
|
||||
is_reserved[i] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Actually set out objects. */
|
||||
for (size_t i = 0; i < num_out_objects; i++) {
|
||||
if (!out_objects[i]) {
|
||||
if (is_reserved[i]) {
|
||||
this->domain->UnreserveIds(object_ids + i, 1);
|
||||
}
|
||||
object_ids[i] = InvalidDomainObjectId;
|
||||
continue;
|
||||
}
|
||||
this->domain->RegisterObject(object_ids[i], std::move(out_objects[i]));
|
||||
}
|
||||
|
||||
/* Set out object IDs in message. */
|
||||
for (size_t i = 0; i < num_out_objects; i++) {
|
||||
this->out_object_ids[i] = object_ids[i];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -26,6 +26,7 @@ namespace sts::sf::cmif {
|
|||
const CmifInHeader *in_header = reinterpret_cast<const CmifInHeader *>(in_raw_data.GetPointer());
|
||||
R_UNLESS(in_raw_data.GetSize() >= sizeof(*in_header), ResultServiceFrameworkInvalidCmifHeaderSize);
|
||||
R_UNLESS(in_header->magic == CMIF_IN_HEADER_MAGIC && in_header->version <= max_cmif_version, ResultServiceFrameworkInvalidCmifInHeader);
|
||||
const cmif::PointerAndSize in_message_raw_data = cmif::PointerAndSize(in_raw_data.GetAddress() + sizeof(*in_header), in_raw_data.GetSize() - sizeof(*in_header));
|
||||
const u32 cmd_id = in_header->command_id;
|
||||
|
||||
/* Find a handler. */
|
||||
|
@ -40,7 +41,7 @@ namespace sts::sf::cmif {
|
|||
|
||||
/* Invoke handler. */
|
||||
CmifOutHeader *out_header = nullptr;
|
||||
Result command_result = cmd_handler(&out_header, ctx, cmif::PointerAndSize(in_raw_data.GetAddress() + sizeof(*in_header), in_raw_data.GetSize() - sizeof(*in_header)));
|
||||
Result command_result = cmd_handler(&out_header, ctx, in_message_raw_data);
|
||||
|
||||
/* Forward forwardable results, otherwise ensure we can send result to user. */
|
||||
R_TRY_CATCH(command_result) {
|
||||
|
@ -65,6 +66,7 @@ namespace sts::sf::cmif {
|
|||
const CmifInHeader *in_header = reinterpret_cast<const CmifInHeader *>(in_raw_data.GetPointer());
|
||||
R_UNLESS(in_raw_data.GetSize() >= sizeof(*in_header), ResultServiceFrameworkInvalidCmifHeaderSize);
|
||||
R_UNLESS(in_header->magic == CMIF_IN_HEADER_MAGIC && in_header->version <= max_cmif_version, ResultServiceFrameworkInvalidCmifInHeader);
|
||||
const cmif::PointerAndSize in_message_raw_data = cmif::PointerAndSize(in_raw_data.GetAddress() + sizeof(*in_header), in_raw_data.GetSize() - sizeof(*in_header));
|
||||
const u32 cmd_id = in_header->command_id;
|
||||
|
||||
/* Find a handler. */
|
||||
|
@ -78,21 +80,18 @@ namespace sts::sf::cmif {
|
|||
|
||||
/* If we didn't find a handler, forward the request. */
|
||||
if (cmd_handler == nullptr) {
|
||||
/* TODO: FORWARD REQUEST */
|
||||
STS_ASSERT(false);
|
||||
return ctx.session->ForwardRequest(ctx);
|
||||
}
|
||||
|
||||
/* Invoke handler. */
|
||||
CmifOutHeader *out_header = nullptr;
|
||||
Result command_result = cmd_handler(&out_header, ctx, cmif::PointerAndSize(in_raw_data.GetAddress() + sizeof(*in_header), in_raw_data.GetSize() - sizeof(*in_header)));
|
||||
Result command_result = cmd_handler(&out_header, ctx, in_message_raw_data);
|
||||
|
||||
/* Forward forwardable results, otherwise ensure we can send result to user. */
|
||||
R_TRY_CATCH(command_result) {
|
||||
R_CATCH(ResultServiceFrameworkRequestDeferredByUser) { return ResultServiceFrameworkRequestDeferredByUser; }
|
||||
R_CATCH(ResultAtmosphereMitmShouldForwardToSession) {
|
||||
/* TODO: Restore TLS. */
|
||||
/* TODO: FORWARD REQUEST */
|
||||
STS_ASSERT(false);
|
||||
return ctx.session->ForwardRequest(ctx);
|
||||
}
|
||||
R_CATCH_ALL() { STS_ASSERT(out_header != nullptr); }
|
||||
} R_END_TRY_CATCH;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue