mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-05 19:51:45 +00:00
fs.mitm: update for libstratosphere refactor
This commit is contained in:
parent
887b4e0275
commit
aef7d36300
21 changed files with 154 additions and 1064 deletions
|
@ -58,6 +58,7 @@
|
||||||
"svcReplyAndReceiveWithUserBuffer": "0x44",
|
"svcReplyAndReceiveWithUserBuffer": "0x44",
|
||||||
"svcCreateEvent": "0x45",
|
"svcCreateEvent": "0x45",
|
||||||
"svcCreateInterruptEvent": "0x53",
|
"svcCreateInterruptEvent": "0x53",
|
||||||
|
"svcReadWriteRegister": "0x4E",
|
||||||
"svcQueryIoMapping": "0x55",
|
"svcQueryIoMapping": "0x55",
|
||||||
"svcCreateDeviceAddressSpace": "0x56",
|
"svcCreateDeviceAddressSpace": "0x56",
|
||||||
"svcAttachDeviceAddressSpace": "0x57",
|
"svcAttachDeviceAddressSpace": "0x57",
|
||||||
|
|
|
@ -24,7 +24,5 @@ void Reboot() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Log(const void *data, int size) {
|
void Log(const void *data, int size) {
|
||||||
(void)(data);
|
|
||||||
(void)(size);
|
|
||||||
/* ... */
|
/* ... */
|
||||||
}
|
}
|
|
@ -21,21 +21,19 @@
|
||||||
|
|
||||||
#include "debug.hpp"
|
#include "debug.hpp"
|
||||||
|
|
||||||
enum class FsIStorageCmd {
|
enum FsIStorageCmd : u32 {
|
||||||
Read = 0,
|
FsIStorageCmd_Read = 0,
|
||||||
Write = 1,
|
FsIStorageCmd_Write = 1,
|
||||||
Flush = 2,
|
FsIStorageCmd_Flush = 2,
|
||||||
SetSize = 3,
|
FsIStorageCmd_SetSize = 3,
|
||||||
GetSize = 4,
|
FsIStorageCmd_GetSize = 4,
|
||||||
OperateRange = 5,
|
FsIStorageCmd_OperateRange = 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
class IStorage {
|
class IStorage {
|
||||||
public:
|
public:
|
||||||
virtual ~IStorage();
|
virtual ~IStorage();
|
||||||
|
|
||||||
virtual IStorage *Clone() = 0;
|
|
||||||
|
|
||||||
virtual Result Read(void *buffer, size_t size, u64 offset) = 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 Write(void *buffer, size_t size, u64 offset) = 0;
|
||||||
virtual Result Flush() = 0;
|
virtual Result Flush() = 0;
|
||||||
|
@ -52,87 +50,58 @@ class IStorageInterface : public IServiceObject {
|
||||||
/* ... */
|
/* ... */
|
||||||
};
|
};
|
||||||
|
|
||||||
IStorageInterface *clone() override {
|
|
||||||
return new IStorageInterface(this->base_storage->Clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
~IStorageInterface() {
|
~IStorageInterface() {
|
||||||
delete base_storage;
|
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:
|
private:
|
||||||
/* Actual command API. */
|
/* Actual command API. */
|
||||||
virtual std::tuple<Result> read(OutBuffer<u8, BufferType_Type1> buffer, u64 offset, u64 size) final {
|
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)};
|
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 {
|
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)};
|
return this->base_storage->Write(buffer.buffer, std::min(buffer.num_elements, size), offset);
|
||||||
|
|
||||||
};
|
};
|
||||||
virtual std::tuple<Result> flush() final {
|
virtual Result Flush() final {
|
||||||
return {this->base_storage->Flush()};
|
return this->base_storage->Flush();
|
||||||
};
|
};
|
||||||
virtual std::tuple<Result> set_size(u64 size) final {
|
virtual Result SetSize(u64 size) final {
|
||||||
return {this->base_storage->SetSize(size)};
|
return this->base_storage->SetSize(size);
|
||||||
};
|
};
|
||||||
virtual std::tuple<Result, u64> get_size() final {
|
virtual Result GetSize(Out<u64> size) final {
|
||||||
u64 out_size = 0;
|
return this->base_storage->GetSize(size.GetPointer());
|
||||||
Result rc = this->base_storage->GetSize(&out_size);
|
|
||||||
return {rc, out_size};
|
|
||||||
};
|
};
|
||||||
virtual std::tuple<Result, FsRangeInfo> operate_range(u32 operation_type, u64 offset, u64 size) final {
|
virtual Result OperateRange(Out<FsRangeInfo> range_info, u32 operation_type, u64 offset, u64 size) final {
|
||||||
FsRangeInfo out_range_info = {0};
|
return this->base_storage->OperateRange(operation_type, offset, size, range_info.GetPointer());
|
||||||
Result rc = this->base_storage->OperateRange(operation_type, offset, size, &out_range_info);
|
};
|
||||||
return {rc, out_range_info};
|
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 {
|
class IROStorage : public IStorage {
|
||||||
public:
|
public:
|
||||||
virtual Result Read(void *buffer, size_t size, u64 offset) = 0;
|
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)(buffer);
|
||||||
(void)(offset);
|
(void)(offset);
|
||||||
(void)(size);
|
(void)(size);
|
||||||
return 0x313802;
|
return 0x313802;
|
||||||
};
|
};
|
||||||
Result Flush() final {
|
virtual Result Flush() final {
|
||||||
return 0x0;
|
return 0x0;
|
||||||
};
|
};
|
||||||
Result SetSize(u64 size) final {
|
virtual Result SetSize(u64 size) final {
|
||||||
(void)(size);
|
(void)(size);
|
||||||
return 0x313802;
|
return 0x313802;
|
||||||
};
|
};
|
||||||
|
|
|
@ -33,15 +33,11 @@ class LayeredRomFS : public IROStorage {
|
||||||
u64 title_id;
|
u64 title_id;
|
||||||
std::shared_ptr<std::vector<RomFSSourceInfo>> p_source_infos;
|
std::shared_ptr<std::vector<RomFSSourceInfo>> p_source_infos;
|
||||||
|
|
||||||
LayeredRomFS *Clone() override {
|
|
||||||
return new LayeredRomFS(*this);
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LayeredRomFS(std::shared_ptr<RomInterfaceStorage> s_r, std::shared_ptr<RomFileStorage> f_r, u64 tid);
|
LayeredRomFS(std::shared_ptr<RomInterfaceStorage> s_r, std::shared_ptr<RomFileStorage> f_r, u64 tid);
|
||||||
virtual ~LayeredRomFS() = default;
|
virtual ~LayeredRomFS() = default;
|
||||||
|
|
||||||
Result Read(void *buffer, size_t size, u64 offset) override;
|
virtual Result Read(void *buffer, size_t size, u64 offset) override;
|
||||||
Result GetSize(u64 *out_size) override;
|
virtual Result GetSize(u64 *out_size) override;
|
||||||
Result OperateRange(u32 operation_type, u64 offset, u64 size, FsRangeInfo *out_range_info) override;
|
virtual Result OperateRange(u32 operation_type, u64 offset, u64 size, FsRangeInfo *out_range_info) override;
|
||||||
};
|
};
|
||||||
|
|
|
@ -22,13 +22,7 @@
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
#include "sm_mitm.h"
|
|
||||||
|
|
||||||
#include "mitm_server.hpp"
|
|
||||||
#include "fsmitm_service.hpp"
|
#include "fsmitm_service.hpp"
|
||||||
#include "fsmitm_worker.hpp"
|
|
||||||
|
|
||||||
#include "mitm_query_service.hpp"
|
|
||||||
|
|
||||||
#include "fsmitm_utils.hpp"
|
#include "fsmitm_utils.hpp"
|
||||||
|
|
||||||
|
@ -88,37 +82,34 @@ void __appExit(void) {
|
||||||
smExit();
|
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>;
|
||||||
|
|
||||||
void CreateSettingsMitMServer(void *arg) {
|
void CreateSettingsMitMServer(void *arg) {
|
||||||
MultiThreadedWaitableManager *server_manager = (MultiThreadedWaitableManager *)arg;
|
auto server_manager = (FsMitmManager *)arg;
|
||||||
|
|
||||||
Result rc;
|
Result rc;
|
||||||
if (R_FAILED((rc = setsysInitialize()))) {
|
if (R_FAILED((rc = setsysInitialize()))) {
|
||||||
fatalSimple(rc);
|
fatalSimple(rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
ISession<MitMQueryService<SetSysMitMService>> *setsys_query_srv = NULL;
|
AddMitmServerToManager<SetSysMitmService>(server_manager, "set:sys", 5);
|
||||||
MitMServer<SetSysMitMService> *setsys_srv = new MitMServer<SetSysMitMService>(&setsys_query_srv, "set:sys", 60);
|
|
||||||
server_manager->add_waitable(setsys_srv);
|
|
||||||
server_manager->add_waitable(setsys_query_srv);
|
|
||||||
|
|
||||||
svcExitThread();
|
svcExitThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
Thread worker_thread = {0};
|
|
||||||
Thread sd_initializer_thread = {0};
|
Thread sd_initializer_thread = {0};
|
||||||
Thread hid_initializer_thread = {0};
|
Thread hid_initializer_thread = {0};
|
||||||
Thread set_mitm_setup_thread = {0};
|
Thread set_mitm_setup_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))) {
|
if (R_FAILED(threadCreate(&sd_initializer_thread, &Utils::InitializeSdThreadFunc, NULL, 0x4000, 0x15, 0))) {
|
||||||
/* TODO: Panic. */
|
/* TODO: Panic. */
|
||||||
}
|
}
|
||||||
|
@ -134,24 +125,21 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: What's a good timeout value to use here? */
|
/* TODO: What's a good timeout value to use here? */
|
||||||
MultiThreadedWaitableManager *server_manager = new MultiThreadedWaitableManager(5, U64_MAX, 0x20000);
|
auto server_manager = new FsMitmManager(1);
|
||||||
|
|
||||||
/* Create fsp-srv mitm. */
|
/* Create fsp-srv mitm. */
|
||||||
ISession<MitMQueryService<FsMitMService>> *fs_query_srv = NULL;
|
AddMitmServerToManager<FsMitmService>(server_manager, "fsp-srv", 61);
|
||||||
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);
|
|
||||||
|
|
||||||
/* Create set:sys mitm server, delayed until set:sys is available. */
|
/* Create set:sys mitm server, delayed until set:sys is available. */
|
||||||
if (R_FAILED(threadCreate(&set_mitm_setup_thread, &CreateSettingsMitMServer, server_manager, 0x4000, 0x15, 0))) {
|
//if (R_FAILED(threadCreate(&set_mitm_setup_thread, &CreateSettingsMitMServer, server_manager, 0x4000, 0x15, 0))) {
|
||||||
/* TODO: Panic. */
|
/* TODO: Panic. */
|
||||||
}
|
//}
|
||||||
if (R_FAILED(threadStart(&set_mitm_setup_thread))) {
|
//if (R_FAILED(threadStart(&set_mitm_setup_thread))) {
|
||||||
/* TODO: Panic. */
|
/* TODO: Panic. */
|
||||||
}
|
//}
|
||||||
|
|
||||||
/* Loop forever, servicing our services. */
|
/* Loop forever, servicing our services. */
|
||||||
server_manager->process();
|
server_manager->Process();
|
||||||
|
|
||||||
delete server_manager;
|
delete server_manager;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
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. */
|
/* For debugging, uncomment this to get a log of the generated metadata tables. */
|
||||||
/*
|
|
||||||
{
|
{
|
||||||
FsFileSystem sd_fs;
|
FsFileSystem sd_fs;
|
||||||
if (R_SUCCEEDED(fsMountSdcard(&sd_fs))) {
|
if (R_SUCCEEDED(fsMountSdcard(&sd_fs))) {
|
||||||
|
@ -415,7 +415,7 @@ void RomFSBuildContext::Build(std::vector<RomFSSourceInfo> *out_infos) {
|
||||||
fsFsClose(&sd_fs);
|
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);
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,10 +35,6 @@ class RomFileStorage : public IROStorage {
|
||||||
fsFileClose(base_file);
|
fsFileClose(base_file);
|
||||||
delete base_file;
|
delete base_file;
|
||||||
};
|
};
|
||||||
|
|
||||||
RomFileStorage *Clone() override {
|
|
||||||
return new RomFileStorage(this->base_file);
|
|
||||||
};
|
|
||||||
public:
|
public:
|
||||||
Result Read(void *buffer, size_t size, u64 offset) override {
|
Result Read(void *buffer, size_t size, u64 offset) override {
|
||||||
size_t out_sz = 0;
|
size_t out_sz = 0;
|
||||||
|
@ -72,10 +68,6 @@ class RomInterfaceStorage : public IROStorage {
|
||||||
fsStorageClose(base_storage);
|
fsStorageClose(base_storage);
|
||||||
delete base_storage;
|
delete base_storage;
|
||||||
};
|
};
|
||||||
|
|
||||||
RomInterfaceStorage *Clone() override {
|
|
||||||
return new RomInterfaceStorage(this->base_storage);
|
|
||||||
};
|
|
||||||
public:
|
public:
|
||||||
Result Read(void *buffer, size_t size, u64 offset) override {
|
Result Read(void *buffer, size_t size, u64 offset) override {
|
||||||
return fsStorageRead(this->base_storage, offset, buffer, size);
|
return fsStorageRead(this->base_storage, offset, buffer, size);
|
||||||
|
|
|
@ -18,81 +18,41 @@
|
||||||
#include "fsmitm_service.hpp"
|
#include "fsmitm_service.hpp"
|
||||||
#include "fs_shim.h"
|
#include "fs_shim.h"
|
||||||
|
|
||||||
#include "fsmitm_worker.hpp"
|
|
||||||
#include "fsmitm_utils.hpp"
|
#include "fsmitm_utils.hpp"
|
||||||
#include "fsmitm_romstorage.hpp"
|
#include "fsmitm_romstorage.hpp"
|
||||||
#include "fsmitm_layeredrom.hpp"
|
#include "fsmitm_layeredrom.hpp"
|
||||||
|
|
||||||
#include "mitm_query_service.hpp"
|
|
||||||
#include "debug.hpp"
|
#include "debug.hpp"
|
||||||
|
|
||||||
Result FsMitMService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) {
|
void FsMitmService::PostProcess(IMitmServiceObject *obj, IpcResponseContext *ctx) {
|
||||||
Result rc = 0xF601;
|
auto this_ptr = static_cast<FsMitmService *>(obj);
|
||||||
if (this->has_initialized) {
|
switch ((FspSrvCmd)ctx->cmd_id) {
|
||||||
switch (static_cast<FspSrvCmd>(cmd_id)) {
|
case FspSrvCmd_SetCurrentProcess:
|
||||||
case FspSrvCmd::OpenDataStorageByCurrentProcess:
|
if (R_SUCCEEDED(ctx->rc)) {
|
||||||
rc = WrapIpcCommandImpl<&FsMitMService::open_data_storage_by_current_process>(this, r, out_c, pointer_buffer, pointer_buffer_size);
|
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;
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
resp->result = rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result FsMitMService::handle_deferred() {
|
|
||||||
/* This service is never deferrable. */
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add redirection for RomFS to the SD card. */
|
/* Add redirection for RomFS to the SD card. */
|
||||||
std::tuple<Result, OutSession<IStorageInterface>> FsMitMService::open_data_storage_by_current_process() {
|
Result FsMitmService::OpenDataStorageByCurrentProcess(Out<std::shared_ptr<IStorageInterface>> out_storage) {
|
||||||
IPCSession<IStorageInterface> *out_session = NULL;
|
std::shared_ptr<IStorageInterface> storage = nullptr;
|
||||||
std::shared_ptr<IStorageInterface> out_storage = nullptr;
|
|
||||||
u32 out_domain_id = 0;
|
u32 out_domain_id = 0;
|
||||||
Result rc;
|
Result rc = 0;
|
||||||
|
|
||||||
if (this->romfs_storage != nullptr) {
|
if (this->romfs_storage != nullptr) {
|
||||||
if (this->get_owner() != NULL) {
|
if (out_storage.IsDomain()) {
|
||||||
FsStorage s = {0};
|
FsStorage s = {0};
|
||||||
rc = fsOpenDataStorageByCurrentProcessFwd(this->forward_service, &s);
|
rc = fsOpenDataStorageByCurrentProcessFwd(this->forward_service.get(), &s);
|
||||||
if (R_SUCCEEDED(rc)) {
|
if (R_SUCCEEDED(rc)) {
|
||||||
out_domain_id = s.s.object_id;
|
out_domain_id = s.s.object_id;
|
||||||
}
|
}
|
||||||
|
@ -100,64 +60,78 @@ std::tuple<Result, OutSession<IStorageInterface>> FsMitMService::open_data_stora
|
||||||
rc = 0;
|
rc = 0;
|
||||||
}
|
}
|
||||||
if (R_SUCCEEDED(rc)) {
|
if (R_SUCCEEDED(rc)) {
|
||||||
out_storage = this->romfs_storage;
|
storage = this->romfs_storage;
|
||||||
out_session = new IPCSession<IStorageInterface>(out_storage);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
FsStorage data_storage;
|
FsStorage data_storage;
|
||||||
FsFile data_file;
|
FsFile data_file;
|
||||||
|
|
||||||
rc = fsOpenDataStorageByCurrentProcessFwd(this->forward_service, &data_storage);
|
rc = fsOpenDataStorageByCurrentProcessFwd(this->forward_service.get(), &data_storage);
|
||||||
|
|
||||||
Log(armGetTls(), 0x100);
|
Log(armGetTls(), 0x100);
|
||||||
if (R_SUCCEEDED(rc)) {
|
if (R_SUCCEEDED(rc)) {
|
||||||
/* TODO: Is there a sensible path that ends in ".romfs" we can use?" */
|
/* 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))) {
|
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 {
|
} 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;
|
this->romfs_storage = storage;
|
||||||
out_session = new IPCSession<IStorageInterface>(out_storage);
|
if (out_storage.IsDomain()) {
|
||||||
if (this->get_owner() == NULL) {
|
|
||||||
FsMitMWorker::AddWaitable(out_session);
|
|
||||||
} else {
|
|
||||||
out_domain_id = data_storage.s.object_id;
|
out_domain_id = data_storage.s.object_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OutSession out_s = OutSession(out_session);
|
if (R_SUCCEEDED(rc)) {
|
||||||
out_s.domain_id = out_domain_id;
|
out_storage.SetValue(std::move(storage));
|
||||||
return {rc, out_s};
|
if (out_storage.IsDomain()) {
|
||||||
|
out_storage.ChangeObjectId(out_domain_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add redirection for System Data Archives to the SD card. */
|
/* 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 sid, u64 data_id) {
|
||||||
FsStorageId storage_id = (FsStorageId)sid;
|
FsStorageId storage_id = (FsStorageId)sid;
|
||||||
IPCSession<IStorageInterface> *out_session = NULL;
|
|
||||||
FsStorage data_storage;
|
FsStorage data_storage;
|
||||||
FsFile data_file;
|
FsFile data_file;
|
||||||
u32 out_domain_id = 0;
|
|
||||||
Result rc;
|
|
||||||
|
|
||||||
rc = fsOpenDataStorageByDataIdFwd(this->forward_service, storage_id, data_id, &data_storage);
|
std::shared_ptr<IStorageInterface> storage = nullptr;
|
||||||
|
u32 out_domain_id = 0;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
rc = fsOpenDataStorageByDataIdFwd(this->forward_service.get(), storage_id, data_id, &data_storage);
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
if (R_SUCCEEDED(rc)) {
|
||||||
/* TODO: Is there a sensible path that ends in ".romfs" we can use?" */
|
/* 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))) {
|
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 {
|
} 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) {
|
if (out_storage.IsDomain()) {
|
||||||
FsMitMWorker::AddWaitable(out_session);
|
|
||||||
} else {
|
|
||||||
out_domain_id = data_storage.s.object_id;
|
out_domain_id = data_storage.s.object_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OutSession out_s = OutSession(out_session);
|
if (R_SUCCEEDED(rc)) {
|
||||||
out_s.domain_id = out_domain_id;
|
out_storage.SetValue(std::move(storage));
|
||||||
return {rc, out_s};
|
if (out_storage.IsDomain()) {
|
||||||
|
out_storage.ChangeObjectId(out_domain_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
|
@ -16,52 +16,41 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <stratosphere/iserviceobject.hpp>
|
#include <stratosphere.hpp>
|
||||||
#include "imitmserviceobject.hpp"
|
|
||||||
#include "fs_istorage.hpp"
|
#include "fs_istorage.hpp"
|
||||||
#include "fsmitm_utils.hpp"
|
#include "fsmitm_utils.hpp"
|
||||||
|
|
||||||
enum class FspSrvCmd {
|
enum FspSrvCmd : u32 {
|
||||||
SetCurrentProcess = 1,
|
FspSrvCmd_SetCurrentProcess = 1,
|
||||||
OpenDataStorageByCurrentProcess = 200,
|
FspSrvCmd_OpenDataStorageByCurrentProcess = 200,
|
||||||
OpenDataStorageByDataId = 202,
|
FspSrvCmd_OpenDataStorageByDataId = 202,
|
||||||
};
|
};
|
||||||
|
|
||||||
class FsMitMService : public IMitMServiceObject {
|
class FsMitmService : public IMitmServiceObject {
|
||||||
private:
|
private:
|
||||||
bool has_initialized = false;
|
bool has_initialized = false;
|
||||||
u64 init_pid = 0;
|
|
||||||
std::shared_ptr<IStorageInterface> romfs_storage;
|
std::shared_ptr<IStorageInterface> romfs_storage;
|
||||||
public:
|
public:
|
||||||
FsMitMService(Service *s) : IMitMServiceObject(s) {
|
FsMitmService(std::shared_ptr<Service> s) : IMitmServiceObject(s) {
|
||||||
/* ... */
|
/* ... */
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool should_mitm(u64 pid, u64 tid) {
|
static bool ShouldMitm(u64 pid, u64 tid) {
|
||||||
if (Utils::HasSdDisableMitMFlag(tid)) {
|
if (Utils::HasSdDisableMitMFlag(tid)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return (tid >= 0x0100000000010000ULL || Utils::HasSdMitMFlag(tid)) && Utils::HasOverrideButton(tid);
|
return (tid >= 0x0100000000010000ULL || Utils::HasSdMitMFlag(tid)) && Utils::HasOverrideButton(tid);
|
||||||
}
|
}
|
||||||
|
|
||||||
FsMitMService *clone() override {
|
static void PostProcess(IMitmServiceObject *obj, IpcResponseContext *ctx);
|
||||||
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();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/* Overridden commands. */
|
/* Overridden commands. */
|
||||||
std::tuple<Result, OutSession<IStorageInterface>> open_data_storage_by_current_process();
|
Result OpenDataStorageByCurrentProcess(Out<std::shared_ptr<IStorageInterface>> out);
|
||||||
std::tuple<Result, OutSession<IStorageInterface>> open_data_storage_by_data_id(u64 storage_id, u64 data_id);
|
Result OpenDataStorageByDataId(Out<std::shared_ptr<IStorageInterface>> out, u64 storage_id, u64 data_id);
|
||||||
|
public:
|
||||||
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
|
MakeServiceCommandMeta<FspSrvCmd_OpenDataStorageByCurrentProcess, &FsMitmService::OpenDataStorageByCurrentProcess>(),
|
||||||
|
MakeServiceCommandMeta<FspSrvCmd_OpenDataStorageByDataId, &FsMitmService::OpenDataStorageByDataId>(),
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
|
|
||||||
#include "sm_mitm.h"
|
|
||||||
#include "debug.hpp"
|
#include "debug.hpp"
|
||||||
#include "fsmitm_utils.hpp"
|
#include "fsmitm_utils.hpp"
|
||||||
#include "ini.h"
|
#include "ini.h"
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
};
|
|
|
@ -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;
|
|
||||||
};
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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};
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
|
@ -1,246 +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.IsDomainRequest) {
|
|
||||||
obj = this->domain->get_domain_object(r.InThisObjectId);
|
|
||||||
if (obj != nullptr && r.InMessageType == DomainMessageType_Close) {
|
|
||||||
if (r.InThisObjectId == this->mitm_domain_id) {
|
|
||||||
Reboot();
|
|
||||||
}
|
|
||||||
this->domain->delete_object(r.InThisObjectId);
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 result;
|
|
||||||
} *o_resp;
|
|
||||||
|
|
||||||
o_resp = (decltype(o_resp)) ipcPrepareHeaderForDomain(&c, sizeof(*o_resp), 0);
|
|
||||||
*(DomainResponseHeader *)((uintptr_t)o_resp - sizeof(DomainResponseHeader)) = {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.IsDomainRequest) {
|
|
||||||
/* We never work with out object ids, so this should be fine. */
|
|
||||||
ipcParseDomainResponse(&cur_out_r, 0);
|
|
||||||
} 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.IsDomainRequest) {
|
|
||||||
/* We never work with out object ids, so this should be fine. */
|
|
||||||
ipcParseDomainResponse(&cur_out_r, 0);
|
|
||||||
} 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]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -18,7 +18,6 @@
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include "setsys_mitm_service.hpp"
|
#include "setsys_mitm_service.hpp"
|
||||||
|
|
||||||
#include "mitm_query_service.hpp"
|
|
||||||
#include "debug.hpp"
|
#include "debug.hpp"
|
||||||
|
|
||||||
static HosMutex g_version_mutex;
|
static HosMutex g_version_mutex;
|
||||||
|
@ -51,54 +50,20 @@ static Result _GetFirmwareVersion(SetSysFirmwareVersion *out) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SetSysMitMService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) {
|
void SetSysMitmService::PostProcess(IMitmServiceObject *obj, IpcResponseContext *ctx) {
|
||||||
Result rc = 0xF601;
|
|
||||||
|
|
||||||
switch (static_cast<SetSysCmd>(cmd_id)) {
|
|
||||||
case SetSysCmd::GetFirmwareVersion:
|
|
||||||
rc = WrapIpcCommandImpl<&SetSysMitMService::get_firmware_version>(this, r, out_c, pointer_buffer, pointer_buffer_size);
|
|
||||||
break;
|
|
||||||
case SetSysCmd::GetFirmwareVersion2:
|
|
||||||
if (kernelAbove300()) {
|
|
||||||
rc = WrapIpcCommandImpl<&SetSysMitMService::get_firmware_version2>(this, r, out_c, pointer_buffer, pointer_buffer_size);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetSysMitMService::postprocess(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) {
|
|
||||||
/* No commands need postprocessing. */
|
/* No commands need postprocessing. */
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SetSysMitMService::handle_deferred() {
|
Result SetSysMitmService::GetFirmwareVersion(OutPointerWithServerSize<SetSysFirmwareVersion, 0x1> out) {
|
||||||
/* This service is never deferrable. */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::tuple<Result> SetSysMitMService::get_firmware_version(OutPointerWithServerSize<SetSysFirmwareVersion, 0x1> out) {
|
|
||||||
if (out.num_elements != 1) {
|
|
||||||
return {0xF601};
|
|
||||||
}
|
|
||||||
|
|
||||||
Result rc = _GetFirmwareVersion(out.pointer);
|
Result rc = _GetFirmwareVersion(out.pointer);
|
||||||
|
|
||||||
/* GetFirmwareVersion sanitizes these fields. */
|
/* GetFirmwareVersion sanitizes these fields. */
|
||||||
out.pointer->revision_major = 0;
|
out.pointer->revision_major = 0;
|
||||||
out.pointer->revision_minor = 0;
|
out.pointer->revision_minor = 0;
|
||||||
|
|
||||||
return {rc};
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<Result> SetSysMitMService::get_firmware_version2(OutPointerWithServerSize<SetSysFirmwareVersion, 0x1> out) {
|
Result SetSysMitmService::GetFirmwareVersion2(OutPointerWithServerSize<SetSysFirmwareVersion, 0x1> out) {
|
||||||
if (out.num_elements != 1) {
|
return _GetFirmwareVersion(out.pointer);
|
||||||
return {0xF601};
|
|
||||||
}
|
|
||||||
|
|
||||||
Result rc = _GetFirmwareVersion(out.pointer);
|
|
||||||
|
|
||||||
return {rc};
|
|
||||||
}
|
}
|
|
@ -16,43 +16,34 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <stratosphere/iserviceobject.hpp>
|
#include <stratosphere.hpp>
|
||||||
#include "imitmserviceobject.hpp"
|
|
||||||
#include "fsmitm_utils.hpp"
|
#include "fsmitm_utils.hpp"
|
||||||
|
|
||||||
enum class SetSysCmd {
|
enum SetSysCmd : u32 {
|
||||||
GetFirmwareVersion = 3,
|
SetSysCmd_GetFirmwareVersion = 3,
|
||||||
GetFirmwareVersion2 = 4,
|
SetSysCmd_GetFirmwareVersion2 = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetSysMitMService : public IMitMServiceObject {
|
class SetSysMitmService : public IMitmServiceObject {
|
||||||
private:
|
|
||||||
public:
|
public:
|
||||||
SetSysMitMService(Service *s) : IMitMServiceObject(s) {
|
SetSysMitmService(std::shared_ptr<Service> s) : IMitmServiceObject(s) {
|
||||||
/* ... */
|
/* ... */
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool should_mitm(u64 pid, u64 tid) {
|
static bool ShouldMitm(u64 pid, u64 tid) {
|
||||||
/* Only MitM qlaunch, maintenance. */
|
/* Only MitM qlaunch, maintenance. */
|
||||||
return tid == 0x0100000000001000ULL || tid == 0x0100000000001015ULL;
|
return tid == 0x0100000000001000ULL || tid == 0x0100000000001015ULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetSysMitMService *clone() override {
|
static void PostProcess(IMitmServiceObject *obj, IpcResponseContext *ctx);
|
||||||
auto new_srv = new SetSysMitMService((Service *)&this->forward_service);
|
|
||||||
this->clone_to(new_srv);
|
|
||||||
return new_srv;
|
|
||||||
}
|
|
||||||
|
|
||||||
void clone_to(void *o) override {
|
|
||||||
/* ... */
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/* Overridden commands. */
|
/* Overridden commands. */
|
||||||
std::tuple<Result> get_firmware_version(OutPointerWithServerSize<SetSysFirmwareVersion, 0x1> out);
|
Result GetFirmwareVersion(OutPointerWithServerSize<SetSysFirmwareVersion, 0x1> out);
|
||||||
std::tuple<Result> get_firmware_version2(OutPointerWithServerSize<SetSysFirmwareVersion, 0x1> out);
|
Result GetFirmwareVersion2(OutPointerWithServerSize<SetSysFirmwareVersion, 0x1> out);
|
||||||
|
public:
|
||||||
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
|
MakeServiceCommandMeta<SetSysCmd_GetFirmwareVersion, &SetSysMitmService::GetFirmwareVersion>(),
|
||||||
|
MakeServiceCommandMeta<SetSysCmd_GetFirmwareVersion2, &SetSysMitmService::GetFirmwareVersion2>(),
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -1,24 +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);
|
|
||||||
|
|
||||||
Result smMitMIsRegistered(const char *name);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
Loading…
Reference in a new issue