Merge branch 'master' into npdmfixup

This commit is contained in:
SciresM
2018-10-31 18:02:07 +09:00
committed by GitHub
235 changed files with 6301 additions and 9851 deletions

View File

@@ -21,7 +21,7 @@ TARGET := $(notdir $(CURDIR))
BUILD := build
SOURCES := source
DATA := data
INCLUDES := include
INCLUDES := include ../../common/include
EXEFS_SRC := exefs_src
DEFINES := -DDISABLE_IPC

View File

@@ -13,63 +13,64 @@
{
"type": "syscalls",
"value": {
"svcSetHeapSize": "0x01",
"svcSetMemoryPermission": "0x02",
"svcSetMemoryAttribute": "0x03",
"svcMapMemory": "0x04",
"svcUnmapMemory": "0x05",
"svcQueryMemory": "0x06",
"svcExitProcess": "0x07",
"svcCreateThread": "0x08",
"svcStartThread": "0x09",
"svcExitThread": "0x0a",
"svcSleepThread": "0x0b",
"svcGetThreadPriority": "0x0c",
"svcSetThreadPriority": "0x0d",
"svcGetThreadCoreMask": "0x0e",
"svcSetThreadCoreMask": "0x0f",
"svcGetCurrentProcessorNumber": "0x10",
"svcSignalEvent": "0x11",
"svcClearEvent": "0x12",
"svcMapSharedMemory": "0x13",
"svcUnmapSharedMemory": "0x14",
"svcCreateTransferMemory": "0x15",
"svcCloseHandle": "0x16",
"svcResetSignal": "0x17",
"svcWaitSynchronization": "0x18",
"svcCancelSynchronization": "0x19",
"svcArbitrateLock": "0x1a",
"svcArbitrateUnlock": "0x1b",
"svcWaitProcessWideKeyAtomic": "0x1c",
"svcSignalProcessWideKey": "0x1d",
"svcGetSystemTick": "0x1e",
"svcConnectToNamedPort": "0x1f",
"svcSendSyncRequestLight": "0x20",
"svcSendSyncRequest": "0x21",
"svcSendSyncRequestWithUserBuffer": "0x22",
"svcSendAsyncRequestWithUserBuffer": "0x23",
"svcGetProcessId": "0x24",
"svcGetThreadId": "0x25",
"svcBreak": "0x26",
"svcOutputDebugString": "0x27",
"svcReturnFromException": "0x28",
"svcGetInfo": "0x29",
"svcWaitForAddress": "0x34",
"svcSignalToAddress": "0x35",
"svcCreateSession": "0x40",
"svcAcceptSession": "0x41",
"svcReplyAndReceiveLight": "0x42",
"svcReplyAndReceive": "0x43",
"svcReplyAndReceiveWithUserBuffer": "0x44",
"svcCreateEvent": "0x45",
"svcCreateInterruptEvent": "0x53",
"svcQueryIoMapping": "0x55",
"svcCreateDeviceAddressSpace": "0x56",
"svcAttachDeviceAddressSpace": "0x57",
"svcDetachDeviceAddressSpace": "0x58",
"svcMapDeviceAddressSpaceAligned": "0x5a",
"svcUnmapDeviceAddressSpace": "0x5c",
"svcGetSystemInfo": "0x6f"
"svcSetHeapSize": "0x01",
"svcSetMemoryPermission": "0x02",
"svcSetMemoryAttribute": "0x03",
"svcMapMemory": "0x04",
"svcUnmapMemory": "0x05",
"svcQueryMemory": "0x06",
"svcExitProcess": "0x07",
"svcCreateThread": "0x08",
"svcStartThread": "0x09",
"svcExitThread": "0x0a",
"svcSleepThread": "0x0b",
"svcGetThreadPriority": "0x0c",
"svcSetThreadPriority": "0x0d",
"svcGetThreadCoreMask": "0x0e",
"svcSetThreadCoreMask": "0x0f",
"svcGetCurrentProcessorNumber": "0x10",
"svcSignalEvent": "0x11",
"svcClearEvent": "0x12",
"svcMapSharedMemory": "0x13",
"svcUnmapSharedMemory": "0x14",
"svcCreateTransferMemory": "0x15",
"svcCloseHandle": "0x16",
"svcResetSignal": "0x17",
"svcWaitSynchronization": "0x18",
"svcCancelSynchronization": "0x19",
"svcArbitrateLock": "0x1a",
"svcArbitrateUnlock": "0x1b",
"svcWaitProcessWideKeyAtomic": "0x1c",
"svcSignalProcessWideKey": "0x1d",
"svcGetSystemTick": "0x1e",
"svcConnectToNamedPort": "0x1f",
"svcSendSyncRequestLight": "0x20",
"svcSendSyncRequest": "0x21",
"svcSendSyncRequestWithUserBuffer": "0x22",
"svcSendAsyncRequestWithUserBuffer": "0x23",
"svcGetProcessId": "0x24",
"svcGetThreadId": "0x25",
"svcBreak": "0x26",
"svcOutputDebugString": "0x27",
"svcReturnFromException": "0x28",
"svcGetInfo": "0x29",
"svcWaitForAddress": "0x34",
"svcSignalToAddress": "0x35",
"svcCreateSession": "0x40",
"svcAcceptSession": "0x41",
"svcReplyAndReceiveLight": "0x42",
"svcReplyAndReceive": "0x43",
"svcReplyAndReceiveWithUserBuffer": "0x44",
"svcCreateEvent": "0x45",
"svcCreateInterruptEvent": "0x53",
"svcReadWriteRegister": "0x4E",
"svcQueryIoMapping": "0x55",
"svcCreateDeviceAddressSpace": "0x56",
"svcAttachDeviceAddressSpace": "0x57",
"svcDetachDeviceAddressSpace": "0x58",
"svcMapDeviceAddressSpaceAligned": "0x5a",
"svcUnmapDeviceAddressSpace": "0x5c",
"svcGetSystemInfo": "0x6f"
}
}
]

View File

@@ -24,7 +24,5 @@ void Reboot() {
}
void Log(const void *data, int size) {
(void)(data);
(void)(size);
/* ... */
}

View File

@@ -21,21 +21,19 @@
#include "debug.hpp"
enum class FsIStorageCmd {
Read = 0,
Write = 1,
Flush = 2,
SetSize = 3,
GetSize = 4,
OperateRange = 5,
enum FsIStorageCmd : u32 {
FsIStorageCmd_Read = 0,
FsIStorageCmd_Write = 1,
FsIStorageCmd_Flush = 2,
FsIStorageCmd_SetSize = 3,
FsIStorageCmd_GetSize = 4,
FsIStorageCmd_OperateRange = 5,
};
class IStorage {
public:
virtual ~IStorage();
virtual IStorage *Clone() = 0;
virtual Result Read(void *buffer, size_t size, u64 offset) = 0;
virtual Result Write(void *buffer, size_t size, u64 offset) = 0;
virtual Result Flush() = 0;
@@ -51,88 +49,59 @@ class IStorageInterface : public IServiceObject {
IStorageInterface(IStorage *s) : base_storage(s) {
/* ... */
};
IStorageInterface *clone() override {
return new IStorageInterface(this->base_storage->Clone());
}
~IStorageInterface() {
delete base_storage;
};
Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) final {
Result rc = 0xF601;
switch ((FsIStorageCmd)cmd_id) {
case FsIStorageCmd::Read:
rc = WrapIpcCommandImpl<&IStorageInterface::read>(this, r, out_c, pointer_buffer, pointer_buffer_size);
break;
case FsIStorageCmd::Write:
rc = WrapIpcCommandImpl<&IStorageInterface::write>(this, r, out_c, pointer_buffer, pointer_buffer_size);
break;
case FsIStorageCmd::Flush:
rc = WrapIpcCommandImpl<&IStorageInterface::flush>(this, r, out_c, pointer_buffer, pointer_buffer_size);
break;
case FsIStorageCmd::SetSize:
rc = WrapIpcCommandImpl<&IStorageInterface::set_size>(this, r, out_c, pointer_buffer, pointer_buffer_size);
break;
case FsIStorageCmd::GetSize:
rc = WrapIpcCommandImpl<&IStorageInterface::get_size>(this, r, out_c, pointer_buffer, pointer_buffer_size);
break;
case FsIStorageCmd::OperateRange:
if (kernelAbove400()) {
rc = WrapIpcCommandImpl<&IStorageInterface::operate_range>(this, r, out_c, pointer_buffer, pointer_buffer_size);
}
break;
default:
break;
}
return rc;
};
Result handle_deferred() final {
/* TODO: Panic, we can never defer. */
return 0;
};
private:
/* Actual command API. */
virtual std::tuple<Result> read(OutBuffer<u8, BufferType_Type1> buffer, u64 offset, u64 size) final {
return {this->base_storage->Read(buffer.buffer, std::min(buffer.num_elements, size), offset)};
virtual Result Read(OutBuffer<u8, BufferType_Type1> buffer, u64 offset, u64 size) final {
return this->base_storage->Read(buffer.buffer, std::min(buffer.num_elements, size), offset);
};
virtual std::tuple<Result> write(InBuffer<u8, BufferType_Type1> buffer, u64 offset, u64 size) final {
return {this->base_storage->Write(buffer.buffer, std::min(buffer.num_elements, size), offset)};
virtual Result Write(InBuffer<u8, BufferType_Type1> buffer, u64 offset, u64 size) final {
return this->base_storage->Write(buffer.buffer, std::min(buffer.num_elements, size), offset);
};
virtual std::tuple<Result> flush() final {
return {this->base_storage->Flush()};
virtual Result Flush() final {
return this->base_storage->Flush();
};
virtual std::tuple<Result> set_size(u64 size) final {
return {this->base_storage->SetSize(size)};
virtual Result SetSize(u64 size) final {
return this->base_storage->SetSize(size);
};
virtual std::tuple<Result, u64> get_size() final {
u64 out_size = 0;
Result rc = this->base_storage->GetSize(&out_size);
return {rc, out_size};
virtual Result GetSize(Out<u64> size) final {
return this->base_storage->GetSize(size.GetPointer());
};
virtual std::tuple<Result, FsRangeInfo> operate_range(u32 operation_type, u64 offset, u64 size) final {
FsRangeInfo out_range_info = {0};
Result rc = this->base_storage->OperateRange(operation_type, offset, size, &out_range_info);
return {rc, out_range_info};
virtual Result OperateRange(Out<FsRangeInfo> range_info, u32 operation_type, u64 offset, u64 size) final {
return this->base_storage->OperateRange(operation_type, offset, size, range_info.GetPointer());
};
public:
DEFINE_SERVICE_DISPATCH_TABLE {
/* 1.0.0- */
MakeServiceCommandMeta<FsIStorageCmd_Read, &IStorageInterface::Read>(),
MakeServiceCommandMeta<FsIStorageCmd_Write, &IStorageInterface::Write>(),
MakeServiceCommandMeta<FsIStorageCmd_Flush, &IStorageInterface::Flush>(),
MakeServiceCommandMeta<FsIStorageCmd_SetSize, &IStorageInterface::SetSize>(),
MakeServiceCommandMeta<FsIStorageCmd_GetSize, &IStorageInterface::GetSize>(),
/* 4.0.0- */
MakeServiceCommandMeta<FsIStorageCmd_OperateRange, &IStorageInterface::OperateRange, FirmwareVersion_400>(),
};
};
class IROStorage : public IStorage {
public:
virtual Result Read(void *buffer, size_t size, u64 offset) = 0;
Result Write(void *buffer, size_t size, u64 offset) final {
virtual Result Write(void *buffer, size_t size, u64 offset) final {
(void)(buffer);
(void)(offset);
(void)(size);
return 0x313802;
};
Result Flush() final {
virtual Result Flush() final {
return 0x0;
};
Result SetSize(u64 size) final {
virtual Result SetSize(u64 size) final {
(void)(size);
return 0x313802;
};

View File

@@ -17,47 +17,6 @@
#include <switch.h>
#include "fs_shim.h"
/* Necessary evil. */
Result ipcCopyFromDomain(Handle session, u32 object_id, Service *out) {
u32* buf = (u32*)armGetTls();
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u32 object_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
buf[0] = IpcCommandType_Control;
raw->magic = SFCI_MAGIC;
raw->cmd_id = 1;
raw->object_id = object_id;
Result rc = ipcDispatch(session);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct ipcCopyFromDomainResponse {
u64 magic;
u64 result;
} *raw = (struct ipcCopyFromDomainResponse*)r.Raw;
rc = raw->result;
if (R_SUCCEEDED(rc)) {
serviceCreate(out, r.Handles[0]);
}
}
return rc;
}
/* Missing fsp-srv commands. */
Result fsOpenDataStorageByCurrentProcessFwd(Service* s, FsStorage* out) {
IpcCommand c;
@@ -68,7 +27,7 @@ Result fsOpenDataStorageByCurrentProcessFwd(Service* s, FsStorage* out) {
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw = serviceIpcPrepareHeader(s, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 200;
@@ -77,60 +36,25 @@ Result fsOpenDataStorageByCurrentProcessFwd(Service* s, FsStorage* out) {
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
} *resp;
serviceIpcParse(s, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
serviceCreate(&out->s, r.Handles[0]);
serviceCreateSubservice(&out->s, s, &r, 0);
}
}
return rc;
}
Result fsOpenDataStorageByCurrentProcessFromDomainFwd(Service* s, u32 *out_object_id) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeaderForDomain(&c, sizeof(*raw), s->object_id);
raw->magic = SFCI_MAGIC;
raw->cmd_id = 200;
Result rc = serviceIpcDispatch(s);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParseForDomain(&r);
struct {
u64 magic;
u64 result;
u32 object_id;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
*out_object_id = resp->object_id;
}
}
return rc;
}
Result fsOpenDataStorageByDataId(Service* s, FsStorageId storage_id, u64 data_id, FsStorage* out) {
Result fsOpenDataStorageByDataIdFwd(Service* s, FsStorageId storage_id, u64 data_id, FsStorage* out) {
IpcCommand c;
ipcInitialize(&c);
@@ -141,7 +65,7 @@ Result fsOpenDataStorageByDataId(Service* s, FsStorageId storage_id, u64 data_id
u64 data_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw = serviceIpcPrepareHeader(s, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 202;
@@ -152,58 +76,18 @@ Result fsOpenDataStorageByDataId(Service* s, FsStorageId storage_id, u64 data_id
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
} *resp;
serviceIpcParse(s, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
serviceCreate(&out->s, r.Handles[0]);
}
}
return rc;
}
Result fsOpenDataStorageByDataIdFromDomain(Service* s, FsStorageId storage_id, u64 data_id, u32 *out_object_id) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
FsStorageId storage_id;
u64 data_id;
} *raw;
raw = ipcPrepareHeaderForDomain(&c, sizeof(*raw), s->object_id);
raw->magic = SFCI_MAGIC;
raw->cmd_id = 202;
raw->storage_id = storage_id;
raw->data_id = data_id;
Result rc = serviceIpcDispatch(s);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParseForDomain(&r);
struct {
u64 magic;
u64 result;
u32 object_id;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
*out_object_id = resp->object_id;
serviceCreateSubservice(&out->s, s, &r, 0);
}
}
@@ -223,7 +107,7 @@ Result fsFileOperateRange(FsFile* f, u32 op_id, u64 off, u64 len, FsRangeInfo *o
u64 len;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw = serviceIpcPrepareHeader(&f->s, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 5;
@@ -235,13 +119,14 @@ Result fsFileOperateRange(FsFile* f, u32 op_id, u64 off, u64 len, FsRangeInfo *o
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
FsRangeInfo range_info;
} *resp = r.Raw;
} *resp;
serviceIpcParse(&f->s, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && out) *out = resp->range_info;
@@ -263,7 +148,7 @@ Result fsStorageOperateRange(FsStorage* s, u32 op_id, u64 off, u64 len, FsRangeI
u64 len;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw = serviceIpcPrepareHeader(&s->s, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 5;
@@ -275,13 +160,14 @@ Result fsStorageOperateRange(FsStorage* s, u32 op_id, u64 off, u64 len, FsRangeI
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
FsRangeInfo range_info;
} *resp = r.Raw;
} *resp;
serviceIpcParse(&s->s, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && out) *out = resp->range_info;

View File

@@ -16,14 +16,9 @@ typedef struct {
u32 flags[0x40/sizeof(u32)];
} FsRangeInfo;
/* Necessary evils. */
Result ipcCopyFromDomain(Handle session, u32 object_id, Service *out);
/* Missing fsp-srv commands. */
Result fsOpenDataStorageByCurrentProcessFwd(Service* s, FsStorage* out);
Result fsOpenDataStorageByCurrentProcessFromDomainFwd(Service* s, u32 *out_object_id);
Result fsOpenDataStorageByDataId(Service* s, FsStorageId storage_id, u64 data_id, FsStorage* out);
Result fsOpenDataStorageByDataIdFromDomain(Service* s, FsStorageId storage_id, u64 data_id, u32 *out_object_id);
Result fsOpenDataStorageByDataIdFwd(Service* s, FsStorageId storage_id, u64 data_id, FsStorage* out);
/* Missing FS File commands. */
Result fsFileOperateRange(FsFile* f, u32 op_id, u64 off, u64 len, FsRangeInfo *out);

View File

@@ -124,12 +124,14 @@ Result LayeredRomFS::Read(void *buffer, size_t size, u64 offset) {
fatalSimple(0xF601);
}
read_so_far += cur_read_size;
offset += cur_read_size;
} else {
/* Handle padding explicitly. */
cur_source_ind++;
/* Zero out the padding we skip, here. */
memset((void *)((uintptr_t)buffer + read_so_far), 0, ((*this->p_source_infos)[cur_source_ind]).virtual_offset - (cur_source->virtual_offset + cur_source->size));
read_so_far += ((*this->p_source_infos)[cur_source_ind]).virtual_offset - (cur_source->virtual_offset + cur_source->size);
memset((void *)((uintptr_t)buffer + read_so_far), 0, ((*this->p_source_infos)[cur_source_ind]).virtual_offset - offset);
read_so_far += ((*this->p_source_infos)[cur_source_ind]).virtual_offset - offset;
offset = ((*this->p_source_infos)[cur_source_ind]).virtual_offset;
}
}

View File

@@ -32,16 +32,12 @@ class LayeredRomFS : public IROStorage {
/* Information about the merged RomFS. */
u64 title_id;
std::shared_ptr<std::vector<RomFSSourceInfo>> p_source_infos;
LayeredRomFS *Clone() override {
return new LayeredRomFS(*this);
};
public:
LayeredRomFS(std::shared_ptr<RomInterfaceStorage> s_r, std::shared_ptr<RomFileStorage> f_r, u64 tid);
virtual ~LayeredRomFS() = default;
Result Read(void *buffer, size_t size, u64 offset) override;
Result GetSize(u64 *out_size) override;
Result OperateRange(u32 operation_type, u64 offset, u64 size, FsRangeInfo *out_range_info) override;
virtual Result Read(void *buffer, size_t size, u64 offset) override;
virtual Result GetSize(u64 *out_size) override;
virtual Result OperateRange(u32 operation_type, u64 offset, u64 size, FsRangeInfo *out_range_info) override;
};

View File

@@ -22,13 +22,7 @@
#include <switch.h>
#include <stratosphere.hpp>
#include "sm_mitm.h"
#include "mitm_server.hpp"
#include "fsmitm_service.hpp"
#include "fsmitm_worker.hpp"
#include "mitm_query_service.hpp"
#include "fsmitm_utils.hpp"
@@ -67,58 +61,32 @@ void __appInit(void) {
fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_SM));
}
rc = smMitMInitialize();
if (R_FAILED(rc)) {
fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_SM));
}
rc = fsInitialize();
if (R_FAILED(rc)) {
fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_FS));
}
rc = splInitialize();
if (R_FAILED(rc)) {
fatalSimple(0xCAFE << 4 | 3);
}
/* Check for exosphere API compatibility. */
u64 exosphere_cfg;
if (R_SUCCEEDED(splGetConfig((SplConfigItem)65000, &exosphere_cfg))) {
/* MitM requires Atmosphere API 0.1. */
u16 api_version = (exosphere_cfg >> 16) & 0xFFFF;
if (api_version < 0x0001) {
fatalSimple(0xCAFE << 4 | 0xFE);
}
} else {
fatalSimple(0xCAFE << 4 | 0xFF);
}
//splExit();
CheckAtmosphereVersion();
}
void __appExit(void) {
/* Cleanup services. */
fsExit();
smMitMExit();
smExit();
}
struct FsMitmManagerOptions {
static const size_t PointerBufferSize = 0x800;
static const size_t MaxDomains = 0x10;
static const size_t MaxDomainObjects = 0x4000;
};
using FsMitmManager = WaitableManager<FsMitmManagerOptions>;
int main(int argc, char **argv)
{
Thread worker_thread = {0};
Thread sd_initializer_thread = {0};
Thread hid_initializer_thread = {0};
consoleDebugInit(debugDevice_SVC);
consoleDebugInit(debugDevice_SVC);
if (R_FAILED(threadCreate(&worker_thread, &FsMitMWorker::Main, NULL, 0x20000, 45, 0))) {
/* TODO: Panic. */
}
if (R_FAILED(threadStart(&worker_thread))) {
/* TODO: Panic. */
}
if (R_FAILED(threadCreate(&sd_initializer_thread, &Utils::InitializeSdThreadFunc, NULL, 0x4000, 0x15, 0))) {
/* TODO: Panic. */
}
@@ -126,18 +94,23 @@ int main(int argc, char **argv)
/* TODO: Panic. */
}
if (R_FAILED(threadCreate(&hid_initializer_thread, &Utils::InitializeHidThreadFunc, NULL, 0x4000, 0x15, 0))) {
/* TODO: Panic. */
}
if (R_FAILED(threadStart(&hid_initializer_thread))) {
/* TODO: Panic. */
}
/* TODO: What's a good timeout value to use here? */
auto server_manager = std::make_unique<MultiThreadedWaitableManager>(1, U64_MAX, 0x20000);
//auto server_manager = std::make_unique<WaitableManager>(U64_MAX);
auto server_manager = new FsMitmManager(5);
/* Create fsp-srv mitm. */
ISession<MitMQueryService<FsMitMService>> *fs_query_srv = NULL;
MitMServer<FsMitMService> *fs_srv = new MitMServer<FsMitMService>(&fs_query_srv, "fsp-srv", 61);
server_manager->add_waitable(fs_srv);
server_manager->add_waitable(fs_query_srv);
AddMitmServerToManager<FsMitmService>(server_manager, "fsp-srv", 61);
/* Loop forever, servicing our services. */
server_manager->process();
server_manager->Process();
delete server_manager;
return 0;
}

View File

@@ -400,7 +400,7 @@ void RomFSBuildContext::Build(std::vector<RomFSSourceInfo> *out_infos) {
header->file_table_ofs = header->file_hash_table_ofs + header->file_hash_table_size;
/* For debugging, uncomment this to get a log of the generated metadata tables. */
/*
{
FsFileSystem sd_fs;
if (R_SUCCEEDED(fsMountSdcard(&sd_fs))) {
@@ -415,7 +415,7 @@ void RomFSBuildContext::Build(std::vector<RomFSSourceInfo> *out_infos) {
fsFsClose(&sd_fs);
}
}
*/
out_infos->emplace_back(header->dir_hash_table_ofs, this->dir_hash_table_size + this->dir_table_size + this->file_hash_table_size + this->file_table_size, metadata, RomFSDataSource::Memory);
}

View File

@@ -35,10 +35,6 @@ class RomFileStorage : public IROStorage {
fsFileClose(base_file);
delete base_file;
};
RomFileStorage *Clone() override {
return new RomFileStorage(this->base_file);
};
public:
Result Read(void *buffer, size_t size, u64 offset) override {
size_t out_sz = 0;
@@ -72,10 +68,6 @@ class RomInterfaceStorage : public IROStorage {
fsStorageClose(base_storage);
delete base_storage;
};
RomInterfaceStorage *Clone() override {
return new RomInterfaceStorage(this->base_storage);
};
public:
Result Read(void *buffer, size_t size, u64 offset) override {
return fsStorageRead(this->base_storage, offset, buffer, size);

View File

@@ -18,149 +18,115 @@
#include "fsmitm_service.hpp"
#include "fs_shim.h"
#include "fsmitm_worker.hpp"
#include "fsmitm_utils.hpp"
#include "fsmitm_romstorage.hpp"
#include "fsmitm_layeredrom.hpp"
#include "mitm_query_service.hpp"
#include "debug.hpp"
Result FsMitMService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) {
Result rc = 0xF601;
if (this->has_initialized) {
switch (static_cast<FspSrvCmd>(cmd_id)) {
case FspSrvCmd::OpenDataStorageByCurrentProcess:
rc = WrapIpcCommandImpl<&FsMitMService::open_data_storage_by_current_process>(this, r, out_c, pointer_buffer, pointer_buffer_size);
void FsMitmService::PostProcess(IMitmServiceObject *obj, IpcResponseContext *ctx) {
auto this_ptr = static_cast<FsMitmService *>(obj);
switch ((FspSrvCmd)ctx->cmd_id) {
case FspSrvCmd_SetCurrentProcess:
if (R_SUCCEEDED(ctx->rc)) {
this_ptr->has_initialized = true;
this_ptr->process_id = ctx->request.Pid;
this_ptr->title_id = this_ptr->process_id;
if (R_FAILED(MitmQueryUtils::GetAssociatedTidForPid(this_ptr->process_id, &this_ptr->title_id))) {
/* Log here, if desired. */
}
break;
case FspSrvCmd::OpenDataStorageByDataId:
rc = WrapIpcCommandImpl<&FsMitMService::open_data_storage_by_data_id>(this, r, out_c, pointer_buffer, pointer_buffer_size);
break;
default:
break;
}
} else {
if (static_cast<FspSrvCmd>(cmd_id) == FspSrvCmd::SetCurrentProcess) {
if (r.HasPid) {
this->init_pid = r.Pid;
}
}
}
return rc;
}
void FsMitMService::postprocess(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) {
struct {
u64 magic;
u64 result;
} *resp = (decltype(resp))r.Raw;
u64 *tls = (u64 *)armGetTls();
std::array<u64, 0x100/sizeof(u64)> backup_tls;
std::copy(tls, tls + backup_tls.size(), backup_tls.begin());
Result rc = (Result)resp->result;
switch (static_cast<FspSrvCmd>(cmd_id)) {
case FspSrvCmd::SetCurrentProcess:
if (R_SUCCEEDED(rc)) {
this->has_initialized = true;
}
this->process_id = this->init_pid;
this->title_id = this->process_id;
if (R_FAILED(MitMQueryUtils::get_associated_tid_for_pid(this->process_id, &this->title_id))) {
/* Log here, if desired. */
}
std::copy(backup_tls.begin(), backup_tls.end(), tls);
break;
default:
break;
}
resp->result = rc;
}
Result FsMitMService::handle_deferred() {
/* This service is never deferrable. */
return 0;
}
/* Add redirection for RomFS to the SD card. */
std::tuple<Result, OutSession<IStorageInterface>> FsMitMService::open_data_storage_by_current_process() {
IPCSession<IStorageInterface> *out_session = NULL;
std::shared_ptr<IStorageInterface> out_storage = nullptr;
Result FsMitmService::OpenDataStorageByCurrentProcess(Out<std::shared_ptr<IStorageInterface>> out_storage) {
std::shared_ptr<IStorageInterface> storage = nullptr;
u32 out_domain_id = 0;
Result rc;
Result rc = 0;
ON_SCOPE_EXIT {
if (R_SUCCEEDED(rc)) {
out_storage.SetValue(std::move(storage));
if (out_storage.IsDomain()) {
out_storage.ChangeObjectId(out_domain_id);
}
}
};
if (this->romfs_storage != nullptr) {
if (this->get_owner() != NULL) {
rc = fsOpenDataStorageByCurrentProcessFromDomainFwd(this->forward_service, &out_domain_id);
if (out_storage.IsDomain()) {
FsStorage s = {0};
rc = fsOpenDataStorageByCurrentProcessFwd(this->forward_service.get(), &s);
if (R_SUCCEEDED(rc)) {
out_domain_id = s.s.object_id;
}
} else {
rc = 0;
}
if (R_SUCCEEDED(rc)) {
out_storage = this->romfs_storage;
out_session = new IPCSession<IStorageInterface>(out_storage);
storage = this->romfs_storage;
}
} else {
FsStorage data_storage;
FsFile data_file;
rc = fsOpenDataStorageByCurrentProcessFwd(this->forward_service.get(), &data_storage);
if (this->get_owner() == NULL) {
rc = fsOpenDataStorageByCurrentProcessFwd(this->forward_service, &data_storage);
} else {
rc = fsOpenDataStorageByCurrentProcessFromDomainFwd(this->forward_service, &out_domain_id);
if (R_SUCCEEDED(rc)) {
rc = ipcCopyFromDomain(this->forward_service->handle, out_domain_id, &data_storage.s);
}
}
Log(armGetTls(), 0x100);
if (R_SUCCEEDED(rc)) {
/* TODO: Is there a sensible path that ends in ".romfs" we can use?" */
if (R_SUCCEEDED(Utils::OpenSdFileForAtmosphere(this->title_id, "romfs.bin", FS_OPEN_READ, &data_file))) {
out_storage = std::make_shared<IStorageInterface>(new LayeredRomFS(std::make_shared<RomInterfaceStorage>(data_storage), std::make_shared<RomFileStorage>(data_file), this->title_id));
storage = std::make_shared<IStorageInterface>(new LayeredRomFS(std::make_shared<RomInterfaceStorage>(data_storage), std::make_shared<RomFileStorage>(data_file), this->title_id));
} else {
out_storage = std::make_shared<IStorageInterface>(new LayeredRomFS(std::make_shared<RomInterfaceStorage>(data_storage), nullptr, this->title_id));
storage = std::make_shared<IStorageInterface>(new LayeredRomFS(std::make_shared<RomInterfaceStorage>(data_storage), nullptr, this->title_id));
}
this->romfs_storage = out_storage;
out_session = new IPCSession<IStorageInterface>(out_storage);
if (this->get_owner() == NULL) {
FsMitMWorker::AddWaitable(out_session);
this->romfs_storage = storage;
if (out_storage.IsDomain()) {
out_domain_id = data_storage.s.object_id;
}
}
}
OutSession out_s = OutSession(out_session);
out_s.domain_id = out_domain_id;
return {rc, out_s};
return rc;
}
/* Add redirection for System Data Archives to the SD card. */
std::tuple<Result, OutSession<IStorageInterface>> FsMitMService::open_data_storage_by_data_id(u64 sid, u64 data_id) {
Result FsMitmService::OpenDataStorageByDataId(Out<std::shared_ptr<IStorageInterface>> out_storage, u64 data_id, u8 sid) {
FsStorageId storage_id = (FsStorageId)sid;
IPCSession<IStorageInterface> *out_session = NULL;
FsStorage data_storage;
FsFile data_file;
std::shared_ptr<IStorageInterface> storage = nullptr;
u32 out_domain_id = 0;
Result rc;
if (this->get_owner() == NULL) {
rc = fsOpenDataStorageByDataId(this->forward_service, storage_id, data_id, &data_storage);
} else {
rc = fsOpenDataStorageByDataIdFromDomain(this->forward_service, storage_id, data_id, &out_domain_id);
Result rc = 0;
ON_SCOPE_EXIT {
if (R_SUCCEEDED(rc)) {
rc = ipcCopyFromDomain(this->forward_service->handle, out_domain_id, &data_storage.s);
out_storage.SetValue(std::move(storage));
if (out_storage.IsDomain()) {
out_storage.ChangeObjectId(out_domain_id);
}
}
}
};
rc = fsOpenDataStorageByDataIdFwd(this->forward_service.get(), storage_id, data_id, &data_storage);
if (R_SUCCEEDED(rc)) {
/* TODO: Is there a sensible path that ends in ".romfs" we can use?" */
if (R_SUCCEEDED(Utils::OpenSdFileForAtmosphere(data_id, "romfs.bin", FS_OPEN_READ, &data_file))) {
out_session = new IPCSession<IStorageInterface>(std::make_shared<IStorageInterface>(new LayeredRomFS(std::make_shared<RomInterfaceStorage>(data_storage), std::make_shared<RomFileStorage>(data_file), data_id)));
storage = std::make_shared<IStorageInterface>(new LayeredRomFS(std::make_shared<RomInterfaceStorage>(data_storage), std::make_shared<RomFileStorage>(data_file), data_id));
} else {
out_session = new IPCSession<IStorageInterface>(std::make_shared<IStorageInterface>(new LayeredRomFS(std::make_shared<RomInterfaceStorage>(data_storage), nullptr, data_id)));
storage = std::make_shared<IStorageInterface>(new LayeredRomFS(std::make_shared<RomInterfaceStorage>(data_storage), nullptr, data_id));
}
if (this->get_owner() == NULL) {
FsMitMWorker::AddWaitable(out_session);
if (out_storage.IsDomain()) {
out_domain_id = data_storage.s.object_id;
}
}
OutSession out_s = OutSession(out_session);
out_s.domain_id = out_domain_id;
return {rc, out_s};
return rc;
}

View File

@@ -16,49 +16,41 @@
#pragma once
#include <switch.h>
#include <stratosphere/iserviceobject.hpp>
#include "imitmserviceobject.hpp"
#include <stratosphere.hpp>
#include "fs_istorage.hpp"
#include "fsmitm_utils.hpp"
enum class FspSrvCmd {
SetCurrentProcess = 1,
OpenDataStorageByCurrentProcess = 200,
OpenDataStorageByDataId = 202,
enum FspSrvCmd : u32 {
FspSrvCmd_SetCurrentProcess = 1,
FspSrvCmd_OpenDataStorageByCurrentProcess = 200,
FspSrvCmd_OpenDataStorageByDataId = 202,
};
class FsMitMService : public IMitMServiceObject {
class FsMitmService : public IMitmServiceObject {
private:
bool has_initialized = false;
u64 init_pid = 0;
std::shared_ptr<IStorageInterface> romfs_storage;
public:
FsMitMService(Service *s) : IMitMServiceObject(s) {
FsMitmService(std::shared_ptr<Service> s) : IMitmServiceObject(s) {
/* ... */
}
static bool should_mitm(u64 pid, u64 tid) {
return tid >= 0x0100000000010000ULL || Utils::HasSdMitMFlag(tid);
static bool ShouldMitm(u64 pid, u64 tid) {
if (Utils::HasSdDisableMitMFlag(tid)) {
return false;
}
return (tid >= 0x0100000000010000ULL || Utils::HasSdMitMFlag(tid)) && Utils::HasOverrideButton(tid);
}
FsMitMService *clone() override {
auto new_srv = new FsMitMService((Service *)&this->forward_service);
this->clone_to(new_srv);
return new_srv;
}
void clone_to(void *o) override {
FsMitMService *other = (FsMitMService *)o;
other->has_initialized = has_initialized;
other->init_pid = init_pid;
}
virtual Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size);
virtual void postprocess(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size);
virtual Result handle_deferred();
static void PostProcess(IMitmServiceObject *obj, IpcResponseContext *ctx);
protected:
/* Overridden commands. */
std::tuple<Result, OutSession<IStorageInterface>> open_data_storage_by_current_process();
std::tuple<Result, OutSession<IStorageInterface>> open_data_storage_by_data_id(u64 storage_id, u64 data_id);
Result OpenDataStorageByCurrentProcess(Out<std::shared_ptr<IStorageInterface>> out);
Result OpenDataStorageByDataId(Out<std::shared_ptr<IStorageInterface>> out, u64 data_id, u8 storage_id);
public:
DEFINE_SERVICE_DISPATCH_TABLE {
MakeServiceCommandMeta<FspSrvCmd_OpenDataStorageByCurrentProcess, &FsMitmService::OpenDataStorageByCurrentProcess>(),
MakeServiceCommandMeta<FspSrvCmd_OpenDataStorageByDataId, &FsMitmService::OpenDataStorageByDataId>(),
};
};

View File

@@ -18,14 +18,23 @@
#include <stratosphere.hpp>
#include <atomic>
#include <algorithm>
#include <strings.h>
#include "sm_mitm.h"
#include "debug.hpp"
#include "fsmitm_utils.hpp"
#include "ini.h"
static FsFileSystem g_sd_filesystem = {0};
static std::vector<u64> g_mitm_flagged_tids;
static std::vector<u64> g_disable_mitm_flagged_tids;
static std::atomic_bool g_has_initialized = false;
static std::atomic_bool g_has_hid_session = false;
static u64 g_override_key_combination = KEY_R;
static bool g_override_by_default = true;
/* Static buffer for loader.ini contents at runtime. */
static char g_config_ini_data[0x800];
static bool IsHexadecimal(const char *str) {
while (*str) {
@@ -72,20 +81,45 @@ void Utils::InitializeSdThreadFunc(void *args) {
g_mitm_flagged_tids.push_back(title_id);
fsFileClose(&f);
}
memset(title_path, 0, sizeof(title_path));
strcpy(title_path, "/atmosphere/titles/");
strcat(title_path, dir_entry.name);
strcat(title_path, "/fsmitm_disable.flag");
if (R_SUCCEEDED(fsFsOpenFile(&g_sd_filesystem, title_path, FS_OPEN_READ, &f))) {
g_disable_mitm_flagged_tids.push_back(title_id);
fsFileClose(&f);
}
}
}
fsDirClose(&titles_dir);
}
Utils::RefreshConfiguration();
g_has_initialized = true;
svcExitThread();
}
void Utils::InitializeHidThreadFunc(void *args) {
while (R_FAILED(hidInitialize())) {
svcSleepThread(1000ULL);
}
g_has_hid_session = true;
svcExitThread();
}
bool Utils::IsSdInitialized() {
return g_has_initialized;
}
bool Utils::IsHidInitialized() {
return g_has_hid_session;
}
Result Utils::OpenSdFile(const char *fn, int flags, FsFile *out) {
if (!IsSdInitialized()) {
return 0xFA202;
@@ -189,3 +223,115 @@ bool Utils::HasSdMitMFlag(u64 tid) {
}
return false;
}
bool Utils::HasSdDisableMitMFlag(u64 tid) {
if (IsSdInitialized()) {
return std::find(g_disable_mitm_flagged_tids.begin(), g_disable_mitm_flagged_tids.end(), tid) != g_disable_mitm_flagged_tids.end();
}
return false;
}
Result Utils::GetKeysDown(u64 *keys) {
if (!Utils::IsHidInitialized()) {
return MAKERESULT(Module_Libnx, LibnxError_InitFail_HID);
}
hidScanInput();
*keys = hidKeysDown(CONTROLLER_P1_AUTO);
return 0x0;
}
bool Utils::HasOverrideButton(u64 tid) {
if (tid < 0x0100000000010000ULL || !IsSdInitialized()) {
/* Disable button override disable for non-applications. */
return true;
}
/* Unconditionally refresh loader.ini contents. */
RefreshConfiguration();
u64 kDown = 0;
bool keys_triggered = (R_SUCCEEDED(GetKeysDown(&kDown)) && ((kDown & g_override_key_combination) != 0));
return IsSdInitialized() && (g_override_by_default ^ keys_triggered);
}
static int FsMitMIniHandler(void *user, const char *section, const char *name, const char *value) {
/* Taken and modified, with love, from Rajkosto's implementation. */
if (strcasecmp(section, "config") == 0) {
if (strcasecmp(name, "override_key") == 0) {
if (value[0] == '!') {
g_override_by_default = true;
value++;
} else {
g_override_by_default = false;
}
if (strcasecmp(value, "A") == 0) {
g_override_key_combination = KEY_A;
} else if (strcasecmp(value, "B") == 0) {
g_override_key_combination = KEY_B;
} else if (strcasecmp(value, "X") == 0) {
g_override_key_combination = KEY_X;
} else if (strcasecmp(value, "Y") == 0) {
g_override_key_combination = KEY_Y;
} else if (strcasecmp(value, "LS") == 0) {
g_override_key_combination = KEY_LSTICK;
} else if (strcasecmp(value, "RS") == 0) {
g_override_key_combination = KEY_RSTICK;
} else if (strcasecmp(value, "L") == 0) {
g_override_key_combination = KEY_L;
} else if (strcasecmp(value, "R") == 0) {
g_override_key_combination = KEY_R;
} else if (strcasecmp(value, "ZL") == 0) {
g_override_key_combination = KEY_ZL;
} else if (strcasecmp(value, "ZR") == 0) {
g_override_key_combination = KEY_ZR;
} else if (strcasecmp(value, "PLUS") == 0) {
g_override_key_combination = KEY_PLUS;
} else if (strcasecmp(value, "MINUS") == 0) {
g_override_key_combination = KEY_MINUS;
} else if (strcasecmp(value, "DLEFT") == 0) {
g_override_key_combination = KEY_DLEFT;
} else if (strcasecmp(value, "DUP") == 0) {
g_override_key_combination = KEY_DUP;
} else if (strcasecmp(value, "DRIGHT") == 0) {
g_override_key_combination = KEY_DRIGHT;
} else if (strcasecmp(value, "DDOWN") == 0) {
g_override_key_combination = KEY_DDOWN;
} else if (strcasecmp(value, "SL") == 0) {
g_override_key_combination = KEY_SL;
} else if (strcasecmp(value, "SR") == 0) {
g_override_key_combination = KEY_SR;
} else {
g_override_key_combination = 0;
}
}
} else {
return 0;
}
return 1;
}
void Utils::RefreshConfiguration() {
FsFile config_file;
if (R_FAILED(fsFsOpenFile(&g_sd_filesystem, "/atmosphere/loader.ini", FS_OPEN_READ, &config_file))) {
return;
}
u64 size;
if (R_FAILED(fsFileGetSize(&config_file, &size))) {
return;
}
size = std::min(size, (decltype(size))0x7FF);
/* Read in string. */
std::fill(g_config_ini_data, g_config_ini_data + 0x800, 0);
size_t r_s;
fsFileRead(&config_file, 0, g_config_ini_data, size, &r_s);
fsFileClose(&config_file);
ini_parse_string(g_config_ini_data, FsMitMIniHandler, NULL);
}

View File

@@ -37,4 +37,13 @@ class Utils {
/* SD card Initialization + MitM detection. */
static void InitializeSdThreadFunc(void *args);
static bool HasSdMitMFlag(u64 tid);
static bool HasSdDisableMitMFlag(u64 tid);
static bool IsHidInitialized();
static void InitializeHidThreadFunc(void *args);
static Result GetKeysDown(u64 *keys);
static bool HasOverrideButton(u64 tid);
private:
static void RefreshConfiguration();
};

View File

@@ -1,53 +0,0 @@
/*
* Copyright (c) 2018 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 <mutex>
#include <switch.h>
#include <stratosphere.hpp>
#include "fsmitm_worker.hpp"
static SystemEvent *g_new_waitable_event = NULL;
static HosMutex g_new_waitable_mutex;
static HosSemaphore g_sema_new_waitable_finish;
static std::unique_ptr<WaitableManager> g_worker_waiter;
Result FsMitMWorker::AddWaitableCallback(void *arg, Handle *handles, size_t num_handles, u64 timeout) {
(void)arg;
svcClearEvent(handles[0]);
g_sema_new_waitable_finish.Signal();
return 0;
}
void FsMitMWorker::AddWaitable(IWaitable *waitable) {
g_worker_waiter->add_waitable(waitable);
std::scoped_lock lk{g_new_waitable_mutex};
g_new_waitable_event->signal_event();
g_sema_new_waitable_finish.Wait();
}
void FsMitMWorker::Main(void *arg) {
/* Initialize waitable event. */
g_new_waitable_event = new SystemEvent(NULL, &FsMitMWorker::AddWaitableCallback);
/* Make a new waitable manager. */
g_worker_waiter = std::make_unique<WaitableManager>(U64_MAX);
g_worker_waiter->add_waitable(g_new_waitable_event);
/* Service processes. */
g_worker_waiter->process();
}

View File

@@ -1,27 +0,0 @@
/*
* Copyright (c) 2018 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/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
class FsMitMWorker {
private:
static Result AddWaitableCallback(void *arg, Handle *handles, size_t num_handles, u64 timeout);
public:
static void Main(void *arg);
static void AddWaitable(IWaitable *waitable);
};

View File

@@ -1,45 +0,0 @@
/*
* Copyright (c) 2018 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/>.
*/
#pragma once
#include <switch.h>
#include <atomic>
#include <stratosphere.hpp>
#include "debug.hpp"
class IMitMServiceObject : public IServiceObject {
protected:
Service *forward_service;
u64 process_id = 0;
u64 title_id = 0;
public:
IMitMServiceObject(Service *s) : forward_service(s) {
}
static bool should_mitm(u64 pid, u64 tid) {
return true;
}
virtual void clone_to(void *o) = 0;
protected:
virtual ~IMitMServiceObject() = default;
virtual Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) = 0;
virtual void postprocess(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) = 0;
virtual Result handle_deferred() = 0;
};

View File

@@ -0,0 +1,269 @@
/* inih -- simple .INI file parser
inih is released under the New BSD license (see LICENSE.txt). Go to the project
home page for more info:
https://github.com/benhoyt/inih
*/
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "ini.h"
#if !INI_USE_STACK
#include <stdlib.h>
#endif
#define MAX_SECTION 50
#define MAX_NAME 50
/* Used by ini_parse_string() to keep track of string parsing state. */
typedef struct {
const char* ptr;
size_t num_left;
} ini_parse_string_ctx;
/* Strip whitespace chars off end of given string, in place. Return s. */
static char* rstrip(char* s)
{
char* p = s + strlen(s);
while (p > s && isspace((unsigned char)(*--p)))
*p = '\0';
return s;
}
/* Return pointer to first non-whitespace char in given string. */
static char* lskip(const char* s)
{
while (*s && isspace((unsigned char)(*s)))
s++;
return (char*)s;
}
/* Return pointer to first char (of chars) or inline comment in given string,
or pointer to null at end of string if neither found. Inline comment must
be prefixed by a whitespace character to register as a comment. */
static char* find_chars_or_comment(const char* s, const char* chars)
{
#if INI_ALLOW_INLINE_COMMENTS
int was_space = 0;
while (*s && (!chars || !strchr(chars, *s)) &&
!(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s))) {
was_space = isspace((unsigned char)(*s));
s++;
}
#else
while (*s && (!chars || !strchr(chars, *s))) {
s++;
}
#endif
return (char*)s;
}
/* Version of strncpy that ensures dest (size bytes) is null-terminated. */
static char* strncpy0(char* dest, const char* src, size_t size)
{
strncpy(dest, src, size - 1);
dest[size - 1] = '\0';
return dest;
}
/* See documentation in header file. */
int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
void* user)
{
/* Uses a fair bit of stack (use heap instead if you need to) */
#if INI_USE_STACK
char line[INI_MAX_LINE];
int max_line = INI_MAX_LINE;
#else
char* line;
int max_line = INI_INITIAL_ALLOC;
#endif
#if INI_ALLOW_REALLOC
char* new_line;
int offset;
#endif
char section[MAX_SECTION] = "";
char prev_name[MAX_NAME] = "";
char* start;
char* end;
char* name;
char* value;
int lineno = 0;
int error = 0;
#if !INI_USE_STACK
line = (char*)malloc(INI_INITIAL_ALLOC);
if (!line) {
return -2;
}
#endif
#if INI_HANDLER_LINENO
#define HANDLER(u, s, n, v) handler(u, s, n, v, lineno)
#else
#define HANDLER(u, s, n, v) handler(u, s, n, v)
#endif
/* Scan through stream line by line */
while (reader(line, max_line, stream) != NULL) {
#if INI_ALLOW_REALLOC
offset = strlen(line);
while (offset == max_line - 1 && line[offset - 1] != '\n') {
max_line *= 2;
if (max_line > INI_MAX_LINE)
max_line = INI_MAX_LINE;
new_line = realloc(line, max_line);
if (!new_line) {
free(line);
return -2;
}
line = new_line;
if (reader(line + offset, max_line - offset, stream) == NULL)
break;
if (max_line >= INI_MAX_LINE)
break;
offset += strlen(line + offset);
}
#endif
lineno++;
start = line;
#if INI_ALLOW_BOM
if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
(unsigned char)start[1] == 0xBB &&
(unsigned char)start[2] == 0xBF) {
start += 3;
}
#endif
start = lskip(rstrip(start));
if (strchr(INI_START_COMMENT_PREFIXES, *start)) {
/* Start-of-line comment */
}
#if INI_ALLOW_MULTILINE
else if (*prev_name && *start && start > line) {
/* Non-blank line with leading whitespace, treat as continuation
of previous name's value (as per Python configparser). */
if (!HANDLER(user, section, prev_name, start) && !error)
error = lineno;
}
#endif
else if (*start == '[') {
/* A "[section]" line */
end = find_chars_or_comment(start + 1, "]");
if (*end == ']') {
*end = '\0';
strncpy0(section, start + 1, sizeof(section));
*prev_name = '\0';
}
else if (!error) {
/* No ']' found on section line */
error = lineno;
}
}
else if (*start) {
/* Not a comment, must be a name[=:]value pair */
end = find_chars_or_comment(start, "=:");
if (*end == '=' || *end == ':') {
*end = '\0';
name = rstrip(start);
value = end + 1;
#if INI_ALLOW_INLINE_COMMENTS
end = find_chars_or_comment(value, NULL);
if (*end)
*end = '\0';
#endif
value = lskip(value);
rstrip(value);
/* Valid name[=:]value pair found, call handler */
strncpy0(prev_name, name, sizeof(prev_name));
if (!HANDLER(user, section, name, value) && !error)
error = lineno;
}
else if (!error) {
/* No '=' or ':' found on name[=:]value line */
error = lineno;
}
}
#if INI_STOP_ON_FIRST_ERROR
if (error)
break;
#endif
}
#if !INI_USE_STACK
free(line);
#endif
return error;
}
/* See documentation in header file. */
int ini_parse_file(FILE* file, ini_handler handler, void* user)
{
return ini_parse_stream((ini_reader)fgets, file, handler, user);
}
/* See documentation in header file. */
int ini_parse(const char* filename, ini_handler handler, void* user)
{
FILE* file;
int error;
file = fopen(filename, "r");
if (!file)
return -1;
error = ini_parse_file(file, handler, user);
fclose(file);
return error;
}
/* An ini_reader function to read the next line from a string buffer. This
is the fgets() equivalent used by ini_parse_string(). */
static char* ini_reader_string(char* str, int num, void* stream) {
ini_parse_string_ctx* ctx = (ini_parse_string_ctx*)stream;
const char* ctx_ptr = ctx->ptr;
size_t ctx_num_left = ctx->num_left;
char* strp = str;
char c;
if (ctx_num_left == 0 || num < 2)
return NULL;
while (num > 1 && ctx_num_left != 0) {
c = *ctx_ptr++;
ctx_num_left--;
*strp++ = c;
if (c == '\n')
break;
num--;
}
*strp = '\0';
ctx->ptr = ctx_ptr;
ctx->num_left = ctx_num_left;
return str;
}
/* See documentation in header file. */
int ini_parse_string(const char* string, ini_handler handler, void* user) {
ini_parse_string_ctx ctx;
ctx.ptr = string;
ctx.num_left = strlen(string);
return ini_parse_stream((ini_reader)ini_reader_string, &ctx, handler,
user);
}

View File

@@ -0,0 +1,130 @@
/* inih -- simple .INI file parser
inih is released under the New BSD license (see LICENSE.txt). Go to the project
home page for more info:
https://github.com/benhoyt/inih
*/
#ifndef __INI_H__
#define __INI_H__
/* Make this header file easier to include in C++ code */
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
/* Nonzero if ini_handler callback should accept lineno parameter. */
#ifndef INI_HANDLER_LINENO
#define INI_HANDLER_LINENO 0
#endif
/* Typedef for prototype of handler function. */
#if INI_HANDLER_LINENO
typedef int (*ini_handler)(void* user, const char* section,
const char* name, const char* value,
int lineno);
#else
typedef int (*ini_handler)(void* user, const char* section,
const char* name, const char* value);
#endif
/* Typedef for prototype of fgets-style reader function. */
typedef char* (*ini_reader)(char* str, int num, void* stream);
/* Parse given INI-style file. May have [section]s, name=value pairs
(whitespace stripped), and comments starting with ';' (semicolon). Section
is "" if name=value pair parsed before any section heading. name:value
pairs are also supported as a concession to Python's configparser.
For each name=value pair parsed, call handler function with given user
pointer as well as section, name, and value (data only valid for duration
of handler call). Handler should return nonzero on success, zero on error.
Returns 0 on success, line number of first error on parse error (doesn't
stop on first error), -1 on file open error, or -2 on memory allocation
error (only when INI_USE_STACK is zero).
*/
int ini_parse(const char* filename, ini_handler handler, void* user);
/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't
close the file when it's finished -- the caller must do that. */
int ini_parse_file(FILE* file, ini_handler handler, void* user);
/* Same as ini_parse(), but takes an ini_reader function pointer instead of
filename. Used for implementing custom or string-based I/O (see also
ini_parse_string). */
int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
void* user);
/* Same as ini_parse(), but takes a zero-terminated string with the INI data
instead of a file. Useful for parsing INI data from a network socket or
already in memory. */
int ini_parse_string(const char* string, ini_handler handler, void* user);
/* Nonzero to allow multi-line value parsing, in the style of Python's
configparser. If allowed, ini_parse() will call the handler with the same
name for each subsequent line parsed. */
#ifndef INI_ALLOW_MULTILINE
#define INI_ALLOW_MULTILINE 1
#endif
/* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of
the file. See http://code.google.com/p/inih/issues/detail?id=21 */
#ifndef INI_ALLOW_BOM
#define INI_ALLOW_BOM 1
#endif
/* Chars that begin a start-of-line comment. Per Python configparser, allow
both ; and # comments at the start of a line by default. */
#ifndef INI_START_COMMENT_PREFIXES
#define INI_START_COMMENT_PREFIXES ";#"
#endif
/* Nonzero to allow inline comments (with valid inline comment characters
specified by INI_INLINE_COMMENT_PREFIXES). Set to 0 to turn off and match
Python 3.2+ configparser behaviour. */
#ifndef INI_ALLOW_INLINE_COMMENTS
#define INI_ALLOW_INLINE_COMMENTS 1
#endif
#ifndef INI_INLINE_COMMENT_PREFIXES
#define INI_INLINE_COMMENT_PREFIXES ";"
#endif
/* Nonzero to use stack for line buffer, zero to use heap (malloc/free). */
#ifndef INI_USE_STACK
#define INI_USE_STACK 1
#endif
/* Maximum line length for any line in INI file (stack or heap). Note that
this must be 3 more than the longest line (due to '\r', '\n', and '\0'). */
#ifndef INI_MAX_LINE
#define INI_MAX_LINE 200
#endif
/* Nonzero to allow heap line buffer to grow via realloc(), zero for a
fixed-size buffer of INI_MAX_LINE bytes. Only applies if INI_USE_STACK is
zero. */
#ifndef INI_ALLOW_REALLOC
#define INI_ALLOW_REALLOC 0
#endif
/* Initial size in bytes for heap line buffer. Only applies if INI_USE_STACK
is zero. */
#ifndef INI_INITIAL_ALLOC
#define INI_INITIAL_ALLOC 200
#endif
/* Stop parsing on first error (default is to keep parsing). */
#ifndef INI_STOP_ON_FIRST_ERROR
#define INI_STOP_ON_FIRST_ERROR 0
#endif
#ifdef __cplusplus
}
#endif
#endif /* __INI_H__ */

View File

@@ -1,43 +0,0 @@
/*
* Copyright (c) 2018 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 <mutex>
#include <switch.h>
#include <stratosphere.hpp>
#include "mitm_query_service.hpp"
static std::vector<u64> g_known_pids;
static std::vector<u64> g_known_tids;
static HosMutex g_pid_tid_mutex;
Result MitMQueryUtils::get_associated_tid_for_pid(u64 pid, u64 *tid) {
Result rc = 0xCAFE;
std::scoped_lock lk{g_pid_tid_mutex};
for (unsigned int i = 0; i < g_known_pids.size(); i++) {
if (g_known_pids[i] == pid) {
*tid = g_known_tids[i];
rc = 0x0;
break;
}
}
return rc;
}
void MitMQueryUtils::associate_pid_to_tid(u64 pid, u64 tid) {
std::scoped_lock lk{g_pid_tid_mutex};
g_known_pids.push_back(pid);
g_known_tids.push_back(tid);
}

View File

@@ -1,75 +0,0 @@
/*
* Copyright (c) 2018 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/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere/iserviceobject.hpp>
#include "debug.hpp"
enum MitMQueryServiceCommand {
MQS_Cmd_ShouldMitm = 65000,
MQS_Cmd_AssociatePidTid = 65001
};
namespace MitMQueryUtils {
Result get_associated_tid_for_pid(u64 pid, u64 *tid);
void associate_pid_to_tid(u64 pid, u64 tid);
}
template <typename T>
class MitMQueryService : public IServiceObject {
public:
MitMQueryService<T> *clone() override {
return new MitMQueryService<T>();
}
Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) override {
Log(armGetTls(), 0x100);
switch (cmd_id) {
case MQS_Cmd_ShouldMitm:
return WrapIpcCommandImpl<&MitMQueryService::should_mitm>(this, r, out_c, pointer_buffer, pointer_buffer_size);
case MQS_Cmd_AssociatePidTid:
return WrapIpcCommandImpl<&MitMQueryService::associate_pid_tid>(this, r, out_c, pointer_buffer, pointer_buffer_size);
default:
return 0xF601;
}
if (cmd_id == 65000) {
} else {
return 0xF601;
}
}
Result handle_deferred() override {
/* This service is never deferrable. */
return 0;
}
protected:
std::tuple<Result, u64> should_mitm(u64 pid) {
u64 should_mitm = 0;
u64 tid = 0;
if (R_SUCCEEDED(MitMQueryUtils::get_associated_tid_for_pid(pid, &tid))) {
should_mitm = T::should_mitm(pid, tid);
}
return {0, should_mitm};
}
std::tuple<Result> associate_pid_tid(u64 pid, u64 tid) {
MitMQueryUtils::associate_pid_to_tid(pid, tid);
return {0x0};
}
};

View File

@@ -1,69 +0,0 @@
/*
* Copyright (c) 2018 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/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
#include "mitm_query_service.hpp"
#include "sm_mitm.h"
#include "mitm_session.hpp"
#include "debug.hpp"
template <typename T>
class MitMSession;
template <typename T>
class MitMServer final : public IServer<T> {
static_assert(std::is_base_of<IServiceObject, T>::value, "Service Objects must derive from IServiceObject");
private:
char mitm_name[9];
public:
MitMServer(ISession<MitMQueryService<T>> **out_query_session, const char *service_name, unsigned int max_s, bool s_d = false) : IServer<T>(service_name, max_s, s_d) {
Handle tmp_hnd;
Handle out_query_h;
Result rc;
if (R_SUCCEEDED((rc = smGetServiceOriginal(&tmp_hnd, smEncodeName(service_name))))) {
svcCloseHandle(tmp_hnd);
} else {
fatalSimple(rc);
}
strncpy(mitm_name, service_name, 8);
mitm_name[8] = '\x00';
if (R_FAILED((rc = smMitMInstall(&this->port_handle, &out_query_h, mitm_name)))) {
fatalSimple(rc);
}
*out_query_session = new ServiceSession<MitMQueryService<T>>(NULL, out_query_h, 0);
}
virtual ~MitMServer() {
if (this->port_handle) {
if (R_FAILED(smMitMUninstall(this->mitm_name))) {
/* TODO: Panic. */
}
/* svcCloseHandle(port_handle); was called by ~IServer. */
}
}
ISession<T> *get_new_session(Handle session_h) override {
return new MitMSession<T>(this, session_h, 0, mitm_name);
}
};

View File

@@ -1,244 +0,0 @@
/*
* Copyright (c) 2018 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/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
#include "imitmserviceobject.hpp"
#include "mitm_query_service.hpp"
#include "mitm_server.hpp"
#include "fsmitm_worker.hpp"
#include "debug.hpp"
template <typename T>
class MitMServer;
template <typename T>
class MitMSession final : public ISession<T> {
static_assert(std::is_base_of<IMitMServiceObject, T>::value, "MitM Service Objects must derive from IMitMServiceObject");
/* This will be for the actual session. */
Service forward_service;
IpcParsedCommand cur_out_r;
u32 mitm_domain_id = 0;
bool got_first_message;
public:
MitMSession<T>(MitMServer<T> *s, Handle s_h, Handle c_h, const char *srv) : ISession<T>(s, s_h, c_h, NULL, 0), got_first_message(false) {
this->server = s;
this->server_handle = s_h;
this->client_handle = c_h;
if (R_FAILED(smMitMGetService(&forward_service, srv))) {
/* TODO: Panic. */
}
size_t pointer_buffer_size = 0;
if (R_FAILED(ipcQueryPointerBufferSize(forward_service.handle, &pointer_buffer_size))) {
/* TODO: Panic. */
}
this->service_object = std::make_shared<T>(&forward_service);
this->pointer_buffer.resize(pointer_buffer_size);
}
MitMSession<T>(MitMServer<T> *s, Handle s_h, Handle c_h, Handle f_h) : ISession<T>(s, s_h, c_h, NULL, 0), got_first_message(true) {
this->server = s;
this->server_handle = s_h;
this->client_handle = c_h;
serviceCreate(&this->forward_service, f_h);
size_t pointer_buffer_size = 0;
if (R_FAILED(ipcQueryPointerBufferSize(forward_service.handle, &pointer_buffer_size))) {
/* TODO: Panic. */
}
this->service_object = std::make_shared<T>(&forward_service);
this->pointer_buffer.resize(pointer_buffer_size);
}
virtual ~MitMSession() {
serviceClose(&forward_service);
}
Result handle_message(IpcParsedCommand &r) override {
IpcCommand c;
ipcInitialize(&c);
u64 cmd_id = ((u32 *)r.Raw)[2];
Result retval = 0xF601;
cur_out_r.NumHandles = 0;
Log(armGetTls(), 0x100);
u32 *cmdbuf = (u32 *)armGetTls();
if (r.CommandType == IpcCommandType_Close) {
Reboot();
}
if (r.CommandType == IpcCommandType_Request || r.CommandType == IpcCommandType_RequestWithContext) {
std::shared_ptr<IServiceObject> obj;
if (r.IsDomainMessage) {
obj = this->domain->get_domain_object(r.ThisObjectId);
if (obj != nullptr && r.MessageType == DomainMessageType_Close) {
if (r.ThisObjectId == this->mitm_domain_id) {
Reboot();
}
this->domain->delete_object(r.ThisObjectId);
struct {
u64 magic;
u64 result;
} *o_resp;
o_resp = (decltype(o_resp)) ipcPrepareHeaderForDomain(&c, sizeof(*o_resp), 0);
*(DomainMessageHeader *)((uintptr_t)o_resp - sizeof(DomainMessageHeader)) = {0};
o_resp->magic = SFCO_MAGIC;
o_resp->result = 0x0;
Log(armGetTls(), 0x100);
return o_resp->result;
}
} else {
obj = this->service_object;
}
if (obj != nullptr) {
retval = obj->dispatch(r, c, cmd_id, (u8 *)this->pointer_buffer.data(), this->pointer_buffer.size());
if (R_SUCCEEDED(retval)) {
if (r.IsDomainMessage) {
ipcParseForDomain(&cur_out_r);
} else {
ipcParse(&cur_out_r);
}
return retval;
}
}
} else if (r.CommandType == IpcCommandType_Control || r.CommandType == IpcCommandType_ControlWithContext) {
/* Ipc Clone Current Object. */
retval = serviceIpcDispatch(&forward_service);
Log(armGetTls(), 0x100);
if (R_SUCCEEDED(retval)) {
ipcParse(&cur_out_r);
struct {
u64 magic;
u64 result;
} *resp = (decltype(resp))cur_out_r.Raw;
retval = resp->result;
if ((cmd_id == IpcCtrl_Cmd_CloneCurrentObject || cmd_id == IpcCtrl_Cmd_CloneCurrentObjectEx)) {
if (R_SUCCEEDED(retval)) {
Handle s_h;
Handle c_h;
Result rc;
if (R_FAILED((rc = svcCreateSession(&s_h, &c_h, 0, 0)))) {
fatalSimple(rc);
}
if (cur_out_r.NumHandles != 1) {
Reboot();
}
MitMSession<T> *new_sess = new MitMSession<T>((MitMServer<T> *)this->server, s_h, c_h, cur_out_r.Handles[0]);
new_sess->service_object = this->service_object;
if (this->is_domain) {
new_sess->is_domain = true;
new_sess->domain = this->domain;
new_sess->mitm_domain_id = this->mitm_domain_id;
new_sess->forward_service.type = this->forward_service.type;
new_sess->forward_service.object_id = this->forward_service.object_id;
}
this->get_manager()->add_waitable(new_sess);
ipcSendHandleMove(&c, c_h);
struct {
u64 magic;
u64 result;
} *o_resp;
o_resp = (decltype(o_resp)) ipcPrepareHeader(&c, sizeof(*o_resp));
o_resp->magic = SFCO_MAGIC;
o_resp->result = 0x0;
}
}
}
Log(armGetTls(), 0x100);
return retval;
}
/* 0xF601 --> Dispatch onwards. */
if (retval == 0xF601) {
/* Patch PID Descriptor, if relevant. */
if (r.HasPid) {
/* [ctrl 0] [ctrl 1] [handle desc 0] [pid low] [pid high] */
cmdbuf[4] = 0xFFFE0000UL | (cmdbuf[4] & 0xFFFFUL);
}
Log(armGetTls(), 0x100);
retval = serviceIpcDispatch(&forward_service);
if (R_SUCCEEDED(retval)) {
if (r.IsDomainMessage) {
ipcParseForDomain(&cur_out_r);
} else {
ipcParse(&cur_out_r);
}
struct {
u64 magic;
u64 result;
} *resp = (decltype(resp))cur_out_r.Raw;
retval = resp->result;
}
}
Log(armGetTls(), 0x100);
Log(&cmd_id, sizeof(u64));
u64 retval_for_log = retval;
Log(&retval_for_log, sizeof(u64));
if (R_FAILED(retval)) {
//Reboot();
}
return retval;
}
void postprocess(IpcParsedCommand &r, u64 cmd_id) override {
if (this->active_object == this->service_object && (r.CommandType == IpcCommandType_Request || r.CommandType == IpcCommandType_RequestWithContext)) {
IpcCommand c;
ipcInitialize(&c);
this->service_object->postprocess(cur_out_r, c, cmd_id, (u8 *)this->pointer_buffer.data(), this->pointer_buffer.size());
} else if (r.CommandType == IpcCommandType_Control || r.CommandType == IpcCommandType_ControlWithContext) {
if (cmd_id == IpcCtrl_Cmd_ConvertCurrentObjectToDomain) {
this->is_domain = true;
this->domain = std::make_shared<DomainOwner>();
struct {
u64 magic;
u64 result;
u32 domain_id;
} *resp = (decltype(resp))cur_out_r.Raw;
Result rc;
if (R_FAILED((rc = this->domain->set_object(this->service_object, resp->domain_id)))) {
fatalSimple(rc);
}
this->mitm_domain_id = resp->domain_id;
this->forward_service.type = ServiceType_Domain;
this->forward_service.object_id = resp->domain_id;
}
}
}
void cleanup() override {
/* Clean up copy handles. */
for (unsigned int i = 0; i < cur_out_r.NumHandles; i++) {
if (cur_out_r.WasHandleCopied[i]) {
svcCloseHandle(cur_out_r.Handles[i]);
}
}
}
};

View File

@@ -1,190 +0,0 @@
/*
* Copyright (c) 2018 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 <switch.h>
#include <switch/arm/atomics.h>
#include "sm_mitm.h"
static Handle g_smMitmHandle = INVALID_HANDLE;
static u64 g_refCnt;
Result smMitMInitialize(void) {
atomicIncrement64(&g_refCnt);
if (g_smMitmHandle != INVALID_HANDLE)
return 0;
Result rc = svcConnectToNamedPort(&g_smMitmHandle, "sm:");
if (R_SUCCEEDED(rc)) {
IpcCommand c;
ipcInitialize(&c);
ipcSendPid(&c);
struct {
u64 magic;
u64 cmd_id;
u64 zero;
u64 reserved[2];
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 0;
raw->zero = 0;
rc = ipcDispatch(g_smMitmHandle);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
}
if (R_FAILED(rc))
smExit();
return rc;
}
void smMitMExit(void) {
if (atomicDecrement64(&g_refCnt) == 0) {
svcCloseHandle(g_smMitmHandle);
g_smMitmHandle = INVALID_HANDLE;
}
}
Result smMitMGetService(Service* service_out, const char *name_str)
{
u64 name = smEncodeName(name_str);
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u64 service_name;
u64 reserved[2];
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 1;
raw->service_name = name;
Result rc = ipcDispatch(g_smMitmHandle);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
service_out->type = ServiceType_Normal;
service_out->handle = r.Handles[0];
}
}
return rc;
}
Result smMitMInstall(Handle *handle_out, Handle *query_out, const char *name) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u64 service_name;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 65000;
raw->service_name = smEncodeName(name);
Result rc = ipcDispatch(g_smMitmHandle);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
*handle_out = r.Handles[0];
*query_out = r.Handles[1];
}
}
return rc;
}
Result smMitMUninstall(const char *name) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u64 service_name;
u64 reserved;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 65001;
raw->service_name = smEncodeName(name);
Result rc = ipcDispatch(g_smMitmHandle);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
}

View File

@@ -1,22 +0,0 @@
/**
* @file sm_mitm.h
* @brief Service manager (sm) IPC wrapper for Atmosphere extensions.
* @author SciresM
* @copyright libnx Authors
*/
#pragma once
#include <switch.h>
#ifdef __cplusplus
extern "C" {
#endif
Result smMitMInitialize(void);
void smMitMExit(void);
Result smMitMGetService(Service* service_out, const char *name);
Result smMitMInstall(Handle *handle_out, Handle *query_out, const char *name);
Result smMitMUninstall(const char *name);
#ifdef __cplusplus
}
#endif