From c0fe4f7af71f035537ac85a1781321c63892469c Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 24 Oct 2018 14:05:07 -0700 Subject: [PATCH] fs.mitm: Intercept qlaunch sysver request --- stratosphere/fs_mitm/source/fsmitm_main.cpp | 36 +++++- .../fs_mitm/source/setsys_mitm_service.cpp | 104 ++++++++++++++++++ .../fs_mitm/source/setsys_mitm_service.hpp | 58 ++++++++++ .../include/stratosphere/isession.hpp | 2 +- 4 files changed, 194 insertions(+), 6 deletions(-) create mode 100644 stratosphere/fs_mitm/source/setsys_mitm_service.cpp create mode 100644 stratosphere/fs_mitm/source/setsys_mitm_service.hpp diff --git a/stratosphere/fs_mitm/source/fsmitm_main.cpp b/stratosphere/fs_mitm/source/fsmitm_main.cpp index ef351c94d..12b2e75c3 100644 --- a/stratosphere/fs_mitm/source/fsmitm_main.cpp +++ b/stratosphere/fs_mitm/source/fsmitm_main.cpp @@ -32,6 +32,8 @@ #include "fsmitm_utils.hpp" +#include "setsys_mitm_service.hpp" + extern "C" { extern u32 __start__; @@ -86,15 +88,30 @@ void __appExit(void) { smExit(); } +void CreateSettingsMitMServer(void *arg) { + MultiThreadedWaitableManager *server_manager = (MultiThreadedWaitableManager *)arg; + + Result rc; + if (R_FAILED((rc = setsysInitialize()))) { + fatalSimple(rc); + } + + ISession> *setsys_query_srv = NULL; + MitMServer *setsys_srv = new MitMServer(&setsys_query_srv, "set:sys", 60); + server_manager->add_waitable(setsys_srv); + server_manager->add_waitable(setsys_query_srv); + + svcExitThread(); +} + int main(int argc, char **argv) { Thread worker_thread = {0}; Thread sd_initializer_thread = {0}; Thread hid_initializer_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. */ } @@ -117,17 +134,26 @@ int main(int argc, char **argv) } /* TODO: What's a good timeout value to use here? */ - auto server_manager = std::make_unique(5, U64_MAX, 0x20000); - //auto server_manager = std::make_unique(U64_MAX); + MultiThreadedWaitableManager *server_manager = new MultiThreadedWaitableManager(5, U64_MAX, 0x20000); /* Create fsp-srv mitm. */ ISession> *fs_query_srv = NULL; MitMServer *fs_srv = new MitMServer(&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. */ + if (R_FAILED(threadCreate(&set_mitm_setup_thread, &CreateSettingsMitMServer, server_manager, 0x4000, 0x15, 0))) { + /* TODO: Panic. */ + } + if (R_FAILED(threadStart(&set_mitm_setup_thread))) { + /* TODO: Panic. */ + } /* Loop forever, servicing our services. */ server_manager->process(); + + delete server_manager; return 0; } diff --git a/stratosphere/fs_mitm/source/setsys_mitm_service.cpp b/stratosphere/fs_mitm/source/setsys_mitm_service.cpp new file mode 100644 index 000000000..2d702f93c --- /dev/null +++ b/stratosphere/fs_mitm/source/setsys_mitm_service.cpp @@ -0,0 +1,104 @@ +/* + * 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 . + */ + +#include +#include +#include "setsys_mitm_service.hpp" + +#include "mitm_query_service.hpp" +#include "debug.hpp" + +static HosMutex g_version_mutex; +static bool g_got_version = false; +static SetSysFirmwareVersion g_fw_version = {0}; + +static Result _GetFirmwareVersion(SetSysFirmwareVersion *out) { + std::lock_guard lock(g_version_mutex); + if (!g_got_version) { + Result rc = setsysGetFirmwareVersion(&g_fw_version); + if (R_FAILED(rc)) { + return rc; + } + + /* Modify the output firmware version. */ + { + u32 major, minor, micro; + char display_version[sizeof(g_fw_version.display_version)] = {0}; + + GetAtmosphereApiVersion(&major, &minor, µ, nullptr, nullptr); + snprintf(display_version, sizeof(display_version), "%s (AMS %u.%u.%u)", g_fw_version.display_version, major, minor, micro); + + memcpy(g_fw_version.display_version, display_version, sizeof(g_fw_version.display_version)); + } + + g_got_version = true; + } + + *out = g_fw_version; + return 0; +} + +Result SetSysMitMService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) { + Result rc = 0xF601; + + switch (static_cast(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. */ +} + +Result SetSysMitMService::handle_deferred() { + /* This service is never deferrable. */ + return 0; +} + +std::tuple SetSysMitMService::get_firmware_version(OutPointerWithServerSize out) { + if (out.num_elements != 1) { + return {0xF601}; + } + + Result rc = _GetFirmwareVersion(out.pointer); + + /* GetFirmwareVersion sanitizes these fields. */ + out.pointer->revision_major = 0; + out.pointer->revision_minor = 0; + + return {rc}; +} + +std::tuple SetSysMitMService::get_firmware_version2(OutPointerWithServerSize out) { + if (out.num_elements != 1) { + return {0xF601}; + } + + Result rc = _GetFirmwareVersion(out.pointer); + + return {rc}; +} \ No newline at end of file diff --git a/stratosphere/fs_mitm/source/setsys_mitm_service.hpp b/stratosphere/fs_mitm/source/setsys_mitm_service.hpp new file mode 100644 index 000000000..8c8877881 --- /dev/null +++ b/stratosphere/fs_mitm/source/setsys_mitm_service.hpp @@ -0,0 +1,58 @@ +/* + * 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 . + */ + +#pragma once +#include +#include +#include "imitmserviceobject.hpp" +#include "fsmitm_utils.hpp" + +enum class SetSysCmd { + GetFirmwareVersion = 3, + GetFirmwareVersion2 = 4, +}; + +class SetSysMitMService : public IMitMServiceObject { + private: + public: + SetSysMitMService(Service *s) : IMitMServiceObject(s) { + /* ... */ + } + + static bool should_mitm(u64 pid, u64 tid) { + /* Only MitM qlaunch, maintenance. */ + return tid == 0x0100000000001000ULL || tid == 0x0100000000001015ULL; + } + + SetSysMitMService *clone() override { + 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: + /* Overridden commands. */ + std::tuple get_firmware_version(OutPointerWithServerSize out); + std::tuple get_firmware_version2(OutPointerWithServerSize out); +}; diff --git a/stratosphere/libstratosphere/include/stratosphere/isession.hpp b/stratosphere/libstratosphere/include/stratosphere/isession.hpp index 12fc6650b..a5371deeb 100644 --- a/stratosphere/libstratosphere/include/stratosphere/isession.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/isession.hpp @@ -196,7 +196,7 @@ class ISession : public IWaitable { /* TODO: Panic? */ } IpcParsedCommand r; - u64 cmd_id; + u64 cmd_id = 0; Result retval = ipcParse(&r);