From 66da896347dedb97bfd5112553c2cba39a1e6368 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 14 Nov 2018 18:39:11 -0800 Subject: [PATCH 01/21] sm: Disable smhax, it interferes with functionality. --- stratosphere/sm/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stratosphere/sm/Makefile b/stratosphere/sm/Makefile index dae1cae4a..a73c7e7f4 100644 --- a/stratosphere/sm/Makefile +++ b/stratosphere/sm/Makefile @@ -34,7 +34,7 @@ ARCH := -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE CFLAGS := -g -Wall -O2 -ffunction-sections \ $(ARCH) $(DEFINES) -CFLAGS += $(INCLUDE) -D__SWITCH__ -DSM_ENABLE_SMHAX -DSM_ENABLE_MITM -DSM_ENABLE_INIT_DEFERS -DSM_MINIMUM_SESSION_LIMIT=8 +CFLAGS += $(INCLUDE) -D__SWITCH__ -DSM_ENABLE_MITM -DSM_ENABLE_INIT_DEFERS -DSM_MINIMUM_SESSION_LIMIT=8 CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++17 From d95fc102dbddf7861e0c515e307024f8bb809e23 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 14 Nov 2018 18:39:48 -0800 Subject: [PATCH 02/21] fs.mitm: Intercept OpenBisStorage calls. --- stratosphere/fs_mitm/source/fs_istorage.hpp | 62 +++++++++++++++++++ stratosphere/fs_mitm/source/fs_shim.c | 38 ++++++++++++ stratosphere/fs_mitm/source/fs_shim.h | 1 + .../fs_mitm/source/fsmitm_romstorage.hpp | 28 +-------- .../fs_mitm/source/fsmitm_service.cpp | 34 ++++++++++ .../fs_mitm/source/fsmitm_service.hpp | 30 ++++++++- 6 files changed, 165 insertions(+), 28 deletions(-) diff --git a/stratosphere/fs_mitm/source/fs_istorage.hpp b/stratosphere/fs_mitm/source/fs_istorage.hpp index 2f21b6b7e..23233e27f 100644 --- a/stratosphere/fs_mitm/source/fs_istorage.hpp +++ b/stratosphere/fs_mitm/source/fs_istorage.hpp @@ -108,3 +108,65 @@ class IROStorage : public IStorage { virtual Result GetSize(u64 *out_size) = 0; virtual Result OperateRange(u32 operation_type, u64 offset, u64 size, FsRangeInfo *out_range_info) = 0; }; + + +class ProxyStorage : public IStorage { + private: + FsStorage *base_storage; + public: + ProxyStorage(FsStorage *s) : base_storage(s) { + /* ... */ + }; + ProxyStorage(FsStorage s) { + this->base_storage = new FsStorage(s); + }; + ~ProxyStorage() { + fsStorageClose(base_storage); + delete base_storage; + }; + public: + virtual Result Read(void *buffer, size_t size, u64 offset) override { + return fsStorageRead(this->base_storage, offset, buffer, size); + }; + virtual Result Write(void *buffer, size_t size, u64 offset) override { + return fsStorageWrite(this->base_storage, offset, buffer, size); + }; + virtual Result Flush() override { + return fsStorageFlush(this->base_storage); + }; + virtual Result GetSize(u64 *out_size) override { + return fsStorageGetSize(this->base_storage, out_size); + }; + virtual Result SetSize(u64 size) override { + return fsStorageSetSize(this->base_storage, size); + }; + virtual Result OperateRange(u32 operation_type, u64 offset, u64 size, FsRangeInfo *out_range_info) override { + return fsStorageOperateRange(this->base_storage, operation_type, offset, size, out_range_info); + }; +}; + +class ROProxyStorage : public IROStorage { + private: + FsStorage *base_storage; + public: + ROProxyStorage(FsStorage *s) : base_storage(s) { + /* ... */ + }; + ROProxyStorage(FsStorage s) { + this->base_storage = new FsStorage(s); + }; + ~ROProxyStorage() { + fsStorageClose(base_storage); + delete base_storage; + }; + public: + virtual Result Read(void *buffer, size_t size, u64 offset) override { + return fsStorageRead(this->base_storage, offset, buffer, size); + }; + virtual Result GetSize(u64 *out_size) override { + return fsStorageGetSize(this->base_storage, out_size); + }; + virtual Result OperateRange(u32 operation_type, u64 offset, u64 size, FsRangeInfo *out_range_info) override { + return fsStorageOperateRange(this->base_storage, operation_type, offset, size, out_range_info); + }; +}; \ No newline at end of file diff --git a/stratosphere/fs_mitm/source/fs_shim.c b/stratosphere/fs_mitm/source/fs_shim.c index 134d83498..915366bb8 100644 --- a/stratosphere/fs_mitm/source/fs_shim.c +++ b/stratosphere/fs_mitm/source/fs_shim.c @@ -18,6 +18,44 @@ #include "fs_shim.h" /* Missing fsp-srv commands. */ +Result fsOpenBisStorageFwd(Service* s, FsStorage* out, u32 PartitionId) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u32 PartitionId; + } *raw; + + raw = serviceIpcPrepareHeader(s, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 12; + raw->PartitionId = PartitionId; + + Result rc = serviceIpcDispatch(s); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(s, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) { + serviceCreateSubservice(&out->s, s, &r, 0); + } + } + + return rc; +} + Result fsOpenDataStorageByCurrentProcessFwd(Service* s, FsStorage* out) { IpcCommand c; ipcInitialize(&c); diff --git a/stratosphere/fs_mitm/source/fs_shim.h b/stratosphere/fs_mitm/source/fs_shim.h index d73c2595b..730a2bfb5 100644 --- a/stratosphere/fs_mitm/source/fs_shim.h +++ b/stratosphere/fs_mitm/source/fs_shim.h @@ -17,6 +17,7 @@ typedef struct { } FsRangeInfo; /* Missing fsp-srv commands. */ +Result fsOpenBisStorageFwd(Service* s, FsStorage* out, u32 PartitionId); Result fsOpenDataStorageByCurrentProcessFwd(Service* s, FsStorage* out); Result fsOpenDataStorageByDataIdFwd(Service* s, FsStorageId storage_id, u64 data_id, FsStorage* out); diff --git a/stratosphere/fs_mitm/source/fsmitm_romstorage.hpp b/stratosphere/fs_mitm/source/fsmitm_romstorage.hpp index c421a2147..04d0cf8d6 100644 --- a/stratosphere/fs_mitm/source/fsmitm_romstorage.hpp +++ b/stratosphere/fs_mitm/source/fsmitm_romstorage.hpp @@ -54,30 +54,4 @@ class RomFileStorage : public IROStorage { }; /* Represents a RomFS accessed via some IStorage. */ -class RomInterfaceStorage : public IROStorage { - private: - FsStorage *base_storage; - public: - RomInterfaceStorage(FsStorage *s) : base_storage(s) { - /* ... */ - }; - RomInterfaceStorage(FsStorage s) { - this->base_storage = new FsStorage(s); - }; - ~RomInterfaceStorage() { - fsStorageClose(base_storage); - delete base_storage; - }; - public: - Result Read(void *buffer, size_t size, u64 offset) override { - return fsStorageRead(this->base_storage, offset, buffer, size); - }; - Result GetSize(u64 *out_size) override { - /* TODO: Merge into libnx? */ - return fsStorageGetSize(this->base_storage, out_size); - }; - Result OperateRange(u32 operation_type, u64 offset, u64 size, FsRangeInfo *out_range_info) override { - /* TODO: Merge into libnx? */ - return fsStorageOperateRange(this->base_storage, operation_type, offset, size, out_range_info); - }; -}; +using RomInterfaceStorage = ROProxyStorage; diff --git a/stratosphere/fs_mitm/source/fsmitm_service.cpp b/stratosphere/fs_mitm/source/fsmitm_service.cpp index 91364ae19..505af638b 100644 --- a/stratosphere/fs_mitm/source/fsmitm_service.cpp +++ b/stratosphere/fs_mitm/source/fsmitm_service.cpp @@ -79,6 +79,40 @@ void FsMitmService::PostProcess(IMitmServiceObject *obj, IpcResponseContext *ctx } } +/* Gate access to the BIS partitions. */ +Result FsMitmService::OpenBisStorage(Out> out_storage, u32 bis_partition_id) { + std::shared_ptr 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); + } + } + }; + + { + FsStorage bis_storage; + rc = fsOpenBisStorageFwd(this->forward_service.get(), &bis_storage, bis_partition_id); + if (R_SUCCEEDED(rc)) { + if (this->title_id >= 0x0100000000001000) { + storage = std::make_shared(new ROProxyStorage(bis_storage)); + } else { + /* Sysmodules should still be allowed to read and write. */ + storage = std::make_shared(new ProxyStorage(bis_storage)); + } + if (out_storage.IsDomain()) { + out_domain_id = bis_storage.s.object_id; + } + } + } + + return rc; +} + /* Add redirection for RomFS to the SD card. */ Result FsMitmService::OpenDataStorageByCurrentProcess(Out> out_storage) { std::shared_ptr storage = nullptr; diff --git a/stratosphere/fs_mitm/source/fsmitm_service.hpp b/stratosphere/fs_mitm/source/fsmitm_service.hpp index 2fffacfa9..07fb38398 100644 --- a/stratosphere/fs_mitm/source/fsmitm_service.hpp +++ b/stratosphere/fs_mitm/source/fsmitm_service.hpp @@ -22,11 +22,31 @@ enum FspSrvCmd : u32 { FspSrvCmd_SetCurrentProcess = 1, + FspSrvCmd_OpenBisStorage = 12, FspSrvCmd_OpenDataStorageByCurrentProcess = 200, FspSrvCmd_OpenDataStorageByDataId = 202, }; -class FsMitmService : public IMitmServiceObject { +enum BisStorageId : u32 { + BisStorageId_Boot0 = 0, + BisStorageId_Boot1 = 10, + BisStorageId_RawNand = 20, + BisStorageId_BcPkg2_1 = 21, + BisStorageId_BcPkg2_2 = 22, + BisStorageId_BcPkg2_3 = 23, + BisStorageId_BcPkg2_4 = 24, + BisStorageId_BcPkg2_5 = 25, + BisStorageId_BcPkg2_6 = 26, + BisStorageId_Prodinfo = 27, + BisStorageId_ProdinfoF = 28, + BisStorageId_Safe = 29, + BisStorageId_User = 30, + BisStorageId_System = 31, + BisStorageId_SystemProperEncryption = 32, + BisStorageId_SystemProperPartition = 33, +}; + +class FsMitmService : public IMitmServiceObject { private: bool has_initialized = false; public: @@ -35,9 +55,15 @@ class FsMitmService : public IMitmServiceObject { } static bool ShouldMitm(u64 pid, u64 tid) { + /* Always intercept NS, so that we can protect the boot partition. */ + if (tid == 0x010000000000001FULL) { + return true; + } + if (Utils::HasSdDisableMitMFlag(tid)) { return false; } + return (tid >= 0x0100000000010000ULL || Utils::HasSdMitMFlag(tid)) && Utils::HasOverrideButton(tid); } @@ -45,10 +71,12 @@ class FsMitmService : public IMitmServiceObject { protected: /* Overridden commands. */ + Result OpenBisStorage(Out> out, u32 bis_partition_id); Result OpenDataStorageByCurrentProcess(Out> out); Result OpenDataStorageByDataId(Out> out, u64 data_id, u8 storage_id); public: DEFINE_SERVICE_DISPATCH_TABLE { + MakeServiceCommandMeta(), MakeServiceCommandMeta(), MakeServiceCommandMeta(), }; From e1cc1b8d2940d90d4a5f8e509f3da99277f33835 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 14 Nov 2018 19:40:46 -0800 Subject: [PATCH 03/21] fs.mitm: Make accesses to Boot0 sectored --- stratosphere/fs_mitm/source/fs_istorage.hpp | 4 +- .../fs_mitm/source/fsmitm_boot0storage.hpp | 156 ++++++++++++++++++ .../fs_mitm/source/fsmitm_romstorage.hpp | 2 +- .../fs_mitm/source/fsmitm_service.cpp | 14 +- 4 files changed, 169 insertions(+), 7 deletions(-) create mode 100644 stratosphere/fs_mitm/source/fsmitm_boot0storage.hpp diff --git a/stratosphere/fs_mitm/source/fs_istorage.hpp b/stratosphere/fs_mitm/source/fs_istorage.hpp index 23233e27f..8bd44cdd2 100644 --- a/stratosphere/fs_mitm/source/fs_istorage.hpp +++ b/stratosphere/fs_mitm/source/fs_istorage.hpp @@ -120,7 +120,7 @@ class ProxyStorage : public IStorage { ProxyStorage(FsStorage s) { this->base_storage = new FsStorage(s); }; - ~ProxyStorage() { + virtual ~ProxyStorage() { fsStorageClose(base_storage); delete base_storage; }; @@ -155,7 +155,7 @@ class ROProxyStorage : public IROStorage { ROProxyStorage(FsStorage s) { this->base_storage = new FsStorage(s); }; - ~ROProxyStorage() { + virtual ~ROProxyStorage() { fsStorageClose(base_storage); delete base_storage; }; diff --git a/stratosphere/fs_mitm/source/fsmitm_boot0storage.hpp b/stratosphere/fs_mitm/source/fsmitm_boot0storage.hpp new file mode 100644 index 000000000..d06351175 --- /dev/null +++ b/stratosphere/fs_mitm/source/fsmitm_boot0storage.hpp @@ -0,0 +1,156 @@ +/* + * 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 "fs_istorage.hpp" + +/* Represents a sectored storage. */ +template +class SectoredProxyStorage : public ProxyStorage { + private: + u64 cur_seek = 0; + u64 cur_sector = 0; + u64 cur_sector_ofs = 0; + u8 sector_buf[SectorSize]; + private: + void Seek(u64 offset) { + this->cur_sector_ofs = offset % SectorSize; + this->cur_seek = offset - this->cur_sector_ofs; + } + public: + SectoredProxyStorage(FsStorage *s) : ProxyStorage(s) { } + SectoredProxyStorage(FsStorage s) : ProxyStorage(s) { } + public: + virtual Result Read(void *_buffer, size_t size, u64 offset) override { + Result rc = 0; + u8 *buffer = static_cast(_buffer); + this->Seek(offset); + + if (R_FAILED((rc = ProxyStorage::Read(this->sector_buf, SectorSize, this->cur_seek)))) { + return rc; + } + + if (size + this->cur_sector_ofs <= SectorSize) { + memcpy(buffer, sector_buf + this->cur_sector_ofs, size); + } else { + /* Leaving the sector... */ + size_t ofs = SectorSize - this->cur_sector_ofs; + memcpy(buffer, sector_buf + this->cur_sector_ofs, ofs); + size -= ofs; + + /* We're guaranteed alignment, here. */ + const size_t aligned_remaining_size = size - (size % SectorSize); + if (aligned_remaining_size) { + if (R_FAILED((rc = ProxyStorage::Read(buffer + ofs, aligned_remaining_size, offset + ofs)))) { + return rc; + } + ofs += aligned_remaining_size; + size -= aligned_remaining_size; + } + + /* Read any leftover data. */ + if (size) { + if (R_FAILED((rc = ProxyStorage::Read(this->sector_buf, SectorSize, offset + ofs)))) { + return rc; + } + memcpy(buffer + ofs, sector_buf, size); + } + } + + return rc; + }; + virtual Result Write(void *_buffer, size_t size, u64 offset) override { + Result rc = 0; + u8 *buffer = static_cast(_buffer); + this->Seek(offset); + + if (R_FAILED((rc = ProxyStorage::Read(this->sector_buf, SectorSize, this->cur_seek)))) { + return rc; + } + + + if (size + this->cur_sector_ofs <= SectorSize) { + memcpy(this->sector_buf + this->cur_sector_ofs, buffer, size); + rc = ProxyStorage::Write(this->sector_buf, SectorSize, this->cur_seek); + } else { + /* Leaving the sector... */ + size_t ofs = SectorSize - this->cur_sector_ofs; + memcpy(this->sector_buf + this->cur_sector_ofs, buffer, ofs); + if (R_FAILED((rc = ProxyStorage::Write(this->sector_buf, ofs, this->cur_seek)))) { + return rc; + } + size -= ofs; + + /* We're guaranteed alignment, here. */ + const size_t aligned_remaining_size = size - (size % SectorSize); + if (aligned_remaining_size) { + if (R_FAILED((rc = ProxyStorage::Write(buffer + ofs, aligned_remaining_size, offset + ofs)))) { + return rc; + } + ofs += aligned_remaining_size; + size -= aligned_remaining_size; + } + + /* Write any leftover data. */ + if (size) { + if (R_FAILED((rc = ProxyStorage::Read(this->sector_buf, SectorSize, offset + ofs)))) { + return rc; + } + memcpy(this->sector_buf, buffer + ofs, size); + rc = ProxyStorage::Write(this->sector_buf, SectorSize, this->cur_seek); + } + } + + return rc; + }; +}; + +/* Represents an RCM-preserving BOOT0 partition. */ +class Boot0Storage : public SectoredProxyStorage<0x200> { + using Base = SectoredProxyStorage<0x200>; + private: + bool allow_writes; + private: + HosMutex *GetMutex() { + static HosMutex s_boot0_mutex; + return &s_boot0_mutex; + } + public: + Boot0Storage(FsStorage *s, bool w) : Base(s), allow_writes(w) { } + Boot0Storage(FsStorage s, bool w) : Base(s), allow_writes(w) { } + + public: + virtual Result Read(void *_buffer, size_t size, u64 offset) override { + GetMutex()->Lock(); + ON_SCOPE_EXIT { GetMutex()->Unlock(); }; + + return Base::Read(_buffer, size, offset); + } + + virtual Result Write(void *_buffer, size_t size, u64 offset) override { + GetMutex()->Lock(); + ON_SCOPE_EXIT { GetMutex()->Unlock(); }; + + if (!this->allow_writes) { + return 0x313802; + } + + return Base::Write(_buffer, size, offset); + } +}; \ No newline at end of file diff --git a/stratosphere/fs_mitm/source/fsmitm_romstorage.hpp b/stratosphere/fs_mitm/source/fsmitm_romstorage.hpp index 04d0cf8d6..1a186ec4c 100644 --- a/stratosphere/fs_mitm/source/fsmitm_romstorage.hpp +++ b/stratosphere/fs_mitm/source/fsmitm_romstorage.hpp @@ -31,7 +31,7 @@ class RomFileStorage : public IROStorage { RomFileStorage(FsFile f) { this->base_file = new FsFile(f); }; - ~RomFileStorage() { + virtual ~RomFileStorage() { fsFileClose(base_file); delete base_file; }; diff --git a/stratosphere/fs_mitm/source/fsmitm_service.cpp b/stratosphere/fs_mitm/source/fsmitm_service.cpp index 505af638b..ccf29db94 100644 --- a/stratosphere/fs_mitm/source/fsmitm_service.cpp +++ b/stratosphere/fs_mitm/source/fsmitm_service.cpp @@ -24,6 +24,7 @@ #include "fs_shim.h" #include "fsmitm_utils.hpp" +#include "fsmitm_boot0storage.hpp" #include "fsmitm_romstorage.hpp" #include "fsmitm_layeredrom.hpp" @@ -98,11 +99,16 @@ Result FsMitmService::OpenBisStorage(Out> out FsStorage bis_storage; rc = fsOpenBisStorageFwd(this->forward_service.get(), &bis_storage, bis_partition_id); if (R_SUCCEEDED(rc)) { - if (this->title_id >= 0x0100000000001000) { - storage = std::make_shared(new ROProxyStorage(bis_storage)); + const bool allow_writes = this->title_id < 0x0100000000001000; + if (bis_partition_id == BisStorageId_Boot0) { + storage = std::make_shared(new Boot0Storage(bis_storage, allow_writes)); } else { - /* Sysmodules should still be allowed to read and write. */ - storage = std::make_shared(new ProxyStorage(bis_storage)); + if (allow_writes) { + storage = std::make_shared(new ROProxyStorage(bis_storage)); + } else { + /* Sysmodules should still be allowed to read and write. */ + storage = std::make_shared(new ProxyStorage(bis_storage)); + } } if (out_storage.IsDomain()) { out_domain_id = bis_storage.s.object_id; From 878ac59aae64227ab019d3d57de5cad4396eb61c Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 14 Nov 2018 19:49:12 -0800 Subject: [PATCH 04/21] fs.mitm: skeleton logic for protecting autorcm. --- .../fs_mitm/source/fsmitm_boot0storage.hpp | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/stratosphere/fs_mitm/source/fsmitm_boot0storage.hpp b/stratosphere/fs_mitm/source/fsmitm_boot0storage.hpp index d06351175..a21365ca1 100644 --- a/stratosphere/fs_mitm/source/fsmitm_boot0storage.hpp +++ b/stratosphere/fs_mitm/source/fsmitm_boot0storage.hpp @@ -125,16 +125,21 @@ class SectoredProxyStorage : public ProxyStorage { class Boot0Storage : public SectoredProxyStorage<0x200> { using Base = SectoredProxyStorage<0x200>; private: - bool allow_writes; + u64 title_id; private: HosMutex *GetMutex() { static HosMutex s_boot0_mutex; return &s_boot0_mutex; } + bool AllowWrites() { + return title_id < 0x0100000000001000ULL; + } + bool CanModifyBctPubks() { + return title_id != 0x010000000000001FULL; + } public: - Boot0Storage(FsStorage *s, bool w) : Base(s), allow_writes(w) { } - Boot0Storage(FsStorage s, bool w) : Base(s), allow_writes(w) { } - + Boot0Storage(FsStorage *s, u64 t) : Base(s), title_id(t) { } + Boot0Storage(FsStorage s, u64 t) : Base(s), title_id(t) { } public: virtual Result Read(void *_buffer, size_t size, u64 offset) override { GetMutex()->Lock(); @@ -147,10 +152,16 @@ class Boot0Storage : public SectoredProxyStorage<0x200> { GetMutex()->Lock(); ON_SCOPE_EXIT { GetMutex()->Unlock(); }; - if (!this->allow_writes) { + if (!AllowWrites()) { return 0x313802; } - return Base::Write(_buffer, size, offset); + /* We care about protecting autorcm from NS. */ + if (CanModifyBctPubks()) { + return Base::Write(_buffer, size, offset); + } + + /* TODO */ + return 0x313802; } }; \ No newline at end of file From 05187502b31fb924489055028138ed50a3dd16d3 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 15 Nov 2018 03:57:55 -0800 Subject: [PATCH 05/21] fs.mitm: Implement basic boot0 protection against writes/pubk writes. --- stratosphere/fs_mitm/source/fs_istorage.hpp | 1 - .../fs_mitm/source/fsmitm_boot0storage.cpp | 78 +++++++++++++++++++ .../fs_mitm/source/fsmitm_boot0storage.hpp | 55 ++++++------- .../fs_mitm/source/fsmitm_service.cpp | 2 +- 4 files changed, 101 insertions(+), 35 deletions(-) create mode 100644 stratosphere/fs_mitm/source/fsmitm_boot0storage.cpp diff --git a/stratosphere/fs_mitm/source/fs_istorage.hpp b/stratosphere/fs_mitm/source/fs_istorage.hpp index 8bd44cdd2..82a75619e 100644 --- a/stratosphere/fs_mitm/source/fs_istorage.hpp +++ b/stratosphere/fs_mitm/source/fs_istorage.hpp @@ -61,7 +61,6 @@ class IStorageInterface : public IServiceObject { }; virtual Result Write(InBuffer buffer, u64 offset, u64 size) final { return this->base_storage->Write(buffer.buffer, std::min(buffer.num_elements, size), offset); - }; virtual Result Flush() final { return this->base_storage->Flush(); diff --git a/stratosphere/fs_mitm/source/fsmitm_boot0storage.cpp b/stratosphere/fs_mitm/source/fsmitm_boot0storage.cpp new file mode 100644 index 000000000..e2b25ad40 --- /dev/null +++ b/stratosphere/fs_mitm/source/fsmitm_boot0storage.cpp @@ -0,0 +1,78 @@ +/* + * 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 + +#include "fsmitm_boot0storage.hpp" + +static HosMutex g_boot0_mutex; +static u8 g_boot0_bct_buffer[Boot0Storage::BctEndOffset]; + +bool Boot0Storage::AllowWrites() { + return this->title_id < 0x0100000000001000ULL; +} + +bool Boot0Storage::CanModifyBctPubks() { + return this->title_id != 0x010000000000001FULL; +} + +Result Boot0Storage::Read(void *_buffer, size_t size, u64 offset) { + std::scoped_lock lk{g_boot0_mutex}; + + return Base::Read(_buffer, size, offset); +} + +Result Boot0Storage::Write(void *_buffer, size_t size, u64 offset) { + std::scoped_lock lk{g_boot0_mutex}; + + if (!AllowWrites()) { + return 0x313802; + } + + /* We care about protecting autorcm from NS. */ + if (CanModifyBctPubks() || offset >= BctEndOffset || (offset + BctSize >= BctEndOffset && offset % BctSize >= BctPubkEnd)) { + return Base::Write(_buffer, size, offset); + } + + Result rc = 0; + u8 *buffer = static_cast(_buffer); + + /* First, let's deal with the data past the end. */ + if (offset + size >= BctEndOffset) { + const u64 diff = BctEndOffset - offset; + if (R_FAILED((rc = ProxyStorage::Write(buffer + diff, size - diff, BctEndOffset)))) { + return rc; + } + size -= diff; + } + + /* Read in the current BCT region. */ + if (R_FAILED((rc = ProxyStorage::Read(g_boot0_bct_buffer, BctEndOffset, 0)))) { + return rc; + } + + /* Update the bct buffer. */ + for (u64 cur_ofs = offset; cur_ofs < BctEndOffset && cur_ofs < offset + size; cur_ofs++) { + const u64 cur_bct_rel_ofs = cur_ofs % BctSize; + if (cur_bct_rel_ofs < BctPubkStart || BctPubkEnd <= cur_bct_rel_ofs) { + g_boot0_bct_buffer[cur_ofs] = buffer[cur_ofs - offset]; + } + } + + return ProxyStorage::Write(g_boot0_bct_buffer, BctEndOffset, 0); +} diff --git a/stratosphere/fs_mitm/source/fsmitm_boot0storage.hpp b/stratosphere/fs_mitm/source/fsmitm_boot0storage.hpp index a21365ca1..cf53948f4 100644 --- a/stratosphere/fs_mitm/source/fsmitm_boot0storage.hpp +++ b/stratosphere/fs_mitm/source/fsmitm_boot0storage.hpp @@ -16,6 +16,7 @@ #pragma once #include +#include #include #include "fs_istorage.hpp" @@ -42,6 +43,11 @@ class SectoredProxyStorage : public ProxyStorage { u8 *buffer = static_cast(_buffer); this->Seek(offset); + if (this->cur_sector_ofs == 0 && size % SectorSize == 0) { + /* Fast case. */ + return ProxyStorage::Read(buffer, size, offset); + } + if (R_FAILED((rc = ProxyStorage::Read(this->sector_buf, SectorSize, this->cur_seek)))) { return rc; } @@ -80,6 +86,11 @@ class SectoredProxyStorage : public ProxyStorage { u8 *buffer = static_cast(_buffer); this->Seek(offset); + if (this->cur_sector_ofs == 0 && size % SectorSize == 0) { + /* Fast case. */ + return ProxyStorage::Write(buffer, size, offset); + } + if (R_FAILED((rc = ProxyStorage::Read(this->sector_buf, SectorSize, this->cur_seek)))) { return rc; } @@ -124,44 +135,22 @@ class SectoredProxyStorage : public ProxyStorage { /* Represents an RCM-preserving BOOT0 partition. */ class Boot0Storage : public SectoredProxyStorage<0x200> { using Base = SectoredProxyStorage<0x200>; + + public: + static constexpr u64 BctEndOffset = 0xFC000; + static constexpr u64 BctSize = 0x4000; + static constexpr u64 BctPubkStart = 0x210; + static constexpr u64 BctPubkSize = 0x100; + static constexpr u64 BctPubkEnd = BctPubkStart + BctPubkSize; private: u64 title_id; private: - HosMutex *GetMutex() { - static HosMutex s_boot0_mutex; - return &s_boot0_mutex; - } - bool AllowWrites() { - return title_id < 0x0100000000001000ULL; - } - bool CanModifyBctPubks() { - return title_id != 0x010000000000001FULL; - } + bool AllowWrites(); + bool CanModifyBctPubks(); public: Boot0Storage(FsStorage *s, u64 t) : Base(s), title_id(t) { } Boot0Storage(FsStorage s, u64 t) : Base(s), title_id(t) { } public: - virtual Result Read(void *_buffer, size_t size, u64 offset) override { - GetMutex()->Lock(); - ON_SCOPE_EXIT { GetMutex()->Unlock(); }; - - return Base::Read(_buffer, size, offset); - } - - virtual Result Write(void *_buffer, size_t size, u64 offset) override { - GetMutex()->Lock(); - ON_SCOPE_EXIT { GetMutex()->Unlock(); }; - - if (!AllowWrites()) { - return 0x313802; - } - - /* We care about protecting autorcm from NS. */ - if (CanModifyBctPubks()) { - return Base::Write(_buffer, size, offset); - } - - /* TODO */ - return 0x313802; - } + virtual Result Read(void *_buffer, size_t size, u64 offset) override; + virtual Result Write(void *_buffer, size_t size, u64 offset) override; }; \ No newline at end of file diff --git a/stratosphere/fs_mitm/source/fsmitm_service.cpp b/stratosphere/fs_mitm/source/fsmitm_service.cpp index ccf29db94..6fb27f846 100644 --- a/stratosphere/fs_mitm/source/fsmitm_service.cpp +++ b/stratosphere/fs_mitm/source/fsmitm_service.cpp @@ -101,7 +101,7 @@ Result FsMitmService::OpenBisStorage(Out> out if (R_SUCCEEDED(rc)) { const bool allow_writes = this->title_id < 0x0100000000001000; if (bis_partition_id == BisStorageId_Boot0) { - storage = std::make_shared(new Boot0Storage(bis_storage, allow_writes)); + storage = std::make_shared(new Boot0Storage(bis_storage, this->title_id)); } else { if (allow_writes) { storage = std::make_shared(new ROProxyStorage(bis_storage)); From 420361597ec60c0fc6f584c9ad37ae456555ea0a Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 15 Nov 2018 04:26:40 -0800 Subject: [PATCH 06/21] all: Change flagging location. Support (but deprecate) old location. --- Makefile | 3 +- stratosphere/fs_mitm/source/fsmitm_utils.cpp | 71 +++++++++++++++++++- stratosphere/fs_mitm/source/fsmitm_utils.hpp | 4 ++ stratosphere/pm/source/pm_boot2.cpp | 13 +++- 4 files changed, 86 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 7eeab49b6..dd524d27e 100644 --- a/Makefile +++ b/Makefile @@ -46,7 +46,8 @@ dist: all cp common/defaults/loader.ini atmosphere-$(AMSVER)/atmosphere/loader.ini cp stratosphere/creport/creport.nsp atmosphere-$(AMSVER)/atmosphere/titles/0100000000000036/exefs.nsp cp stratosphere/set_mitm/set_mitm.nsp atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032/exefs.nsp - touch atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032/boot2.flag + mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032/flags + touch atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032/flags/boot2.flag cd atmosphere-$(AMSVER); zip -r ../atmosphere-$(AMSVER).zip ./*; cd ../; rm -r atmosphere-$(AMSVER) mkdir out diff --git a/stratosphere/fs_mitm/source/fsmitm_utils.cpp b/stratosphere/fs_mitm/source/fsmitm_utils.cpp index 32e37fad6..9ebffae0b 100644 --- a/stratosphere/fs_mitm/source/fsmitm_utils.cpp +++ b/stratosphere/fs_mitm/source/fsmitm_utils.cpp @@ -31,6 +31,7 @@ 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 u64 g_override_hbl_tid = 0x010000000000100DULL; static bool g_override_by_default = true; /* Static buffer for loader.ini contents at runtime. */ @@ -76,19 +77,39 @@ void Utils::InitializeSdThreadFunc(void *args) { char title_path[FS_MAX_PATH] = {0}; strcpy(title_path, "/atmosphere/titles/"); strcat(title_path, dir_entry.name); - strcat(title_path, "/fsmitm.flag"); + strcat(title_path, "/flags/fsmitm.flag"); if (R_SUCCEEDED(fsFsOpenFile(&g_sd_filesystem, title_path, FS_OPEN_READ, &f))) { g_mitm_flagged_tids.push_back(title_id); fsFileClose(&f); + } else { + /* TODO: Deprecate. */ + memset(title_path, 0, sizeof(title_path)); + strcpy(title_path, "/atmosphere/titles/"); + strcat(title_path, dir_entry.name); + strcat(title_path, "/fsmitm.flag"); + if (R_SUCCEEDED(fsFsOpenFile(&g_sd_filesystem, title_path, FS_OPEN_READ, &f))) { + 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"); + strcat(title_path, "/flags/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); + } else { + /* TODO: Deprecate. */ + 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); + } } } } @@ -264,7 +285,46 @@ Result Utils::SaveSdFileForAtmosphere(u64 title_id, const char *fn, void *data, return rc; } +bool Utils::HasFlag(u64 tid, const char *flag) { + if (IsSdInitialized()) { + FsFile f; + char flag_path[FS_MAX_PATH]; + + memset(flag_path, 0, sizeof(flag_path)); + snprintf(flag_path, sizeof(flag_path) - 1, "flags/%s.flag", flag); + if (OpenSdFileForAtmosphere(tid, flag_path, FS_OPEN_READ, &f)) { + fsFileClose(&f); + return true; + } + + /* TODO: Deprecate. */ + snprintf(flag_path, sizeof(flag_path) - 1, "%s.flag", flag); + if (OpenSdFileForAtmosphere(tid, flag_path, FS_OPEN_READ, &f)) { + fsFileClose(&f); + return true; + } + } + return false; +} + +bool Utils::HasGlobalFlag(u64 tid, const char *flag) { + if (IsSdInitialized()) { + FsFile f; + char flag_path[FS_MAX_PATH] = {0}; + snprintf(flag_path, sizeof(flag_path), "/atmosphere/flags/%s.flag", flag); + if (fsFsOpenFile(&g_sd_filesystem, flag_path, FS_OPEN_READ, &f)) { + fsFileClose(&f); + return true; + } + } + return false; +} + bool Utils::HasSdMitMFlag(u64 tid) { + if (tid == g_override_hbl_tid) { + return true; + } + if (IsSdInitialized()) { return std::find(g_mitm_flagged_tids.begin(), g_mitm_flagged_tids.end(), tid) != g_mitm_flagged_tids.end(); } @@ -306,7 +366,12 @@ bool Utils::HasOverrideButton(u64 tid) { 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 (strcasecmp(name, "hbl_tid") == 0) { + u64 override_tid = strtoul(value, NULL, 16); + if (override_tid != 0) { + g_override_hbl_tid = override_tid; + } + } else if (strcasecmp(name, "override_key") == 0) { if (value[0] == '!') { g_override_by_default = true; value++; diff --git a/stratosphere/fs_mitm/source/fsmitm_utils.hpp b/stratosphere/fs_mitm/source/fsmitm_utils.hpp index ad8d176b1..a730d44d6 100644 --- a/stratosphere/fs_mitm/source/fsmitm_utils.hpp +++ b/stratosphere/fs_mitm/source/fsmitm_utils.hpp @@ -38,6 +38,10 @@ class Utils { /* SD card Initialization + MitM detection. */ static void InitializeSdThreadFunc(void *args); + + static bool HasFlag(u64 tid, const char *flag); + static bool HasGlobalFlag(const char *flag); + static bool HasSdMitMFlag(u64 tid); static bool HasSdDisableMitMFlag(u64 tid); diff --git a/stratosphere/pm/source/pm_boot2.cpp b/stratosphere/pm/source/pm_boot2.cpp index 3a6844621..78eddd963 100644 --- a/stratosphere/pm/source/pm_boot2.cpp +++ b/stratosphere/pm/source/pm_boot2.cpp @@ -163,11 +163,22 @@ void EmbeddedBoot2::Main() { char title_path[FS_MAX_PATH] = {0}; strcpy(title_path, "sdmc:/atmosphere/titles/"); strcat(title_path, ent->d_name); - strcat(title_path, "/boot2.flag"); + strcat(title_path, "/flags/boot2.flag"); FILE *f_flag = fopen(title_path, "rb"); if (f_flag != NULL) { fclose(f_flag); LaunchTitle((Boot2KnownTitleId)title_id, FsStorageId_None, 0, NULL); + } else { + /* TODO: Deprecate this in the future. */ + memset(title_path, 0, FS_MAX_PATH); + strcpy(title_path, "sdmc:/atmosphere/titles/"); + strcat(title_path, ent->d_name); + strcat(title_path, "/boot2.flag"); + f_flag = fopen(title_path, "rb"); + if (f_flag != NULL) { + fclose(f_flag); + LaunchTitle((Boot2KnownTitleId)title_id, FsStorageId_None, 0, NULL); + } } } } From 83644692fe6e89da5c99d6ddae9671f9cc5035bb Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 15 Nov 2018 04:44:13 -0800 Subject: [PATCH 07/21] fs.mitm: Automatically backup PRODINFO on boot. --- .../fs_mitm/source/fsmitm_service.hpp | 19 ---------- stratosphere/fs_mitm/source/fsmitm_utils.cpp | 38 ++++++++++++++++++- stratosphere/fs_mitm/source/fsmitm_utils.hpp | 19 ++++++++++ 3 files changed, 56 insertions(+), 20 deletions(-) diff --git a/stratosphere/fs_mitm/source/fsmitm_service.hpp b/stratosphere/fs_mitm/source/fsmitm_service.hpp index 07fb38398..33516ccba 100644 --- a/stratosphere/fs_mitm/source/fsmitm_service.hpp +++ b/stratosphere/fs_mitm/source/fsmitm_service.hpp @@ -27,25 +27,6 @@ enum FspSrvCmd : u32 { FspSrvCmd_OpenDataStorageByDataId = 202, }; -enum BisStorageId : u32 { - BisStorageId_Boot0 = 0, - BisStorageId_Boot1 = 10, - BisStorageId_RawNand = 20, - BisStorageId_BcPkg2_1 = 21, - BisStorageId_BcPkg2_2 = 22, - BisStorageId_BcPkg2_3 = 23, - BisStorageId_BcPkg2_4 = 24, - BisStorageId_BcPkg2_5 = 25, - BisStorageId_BcPkg2_6 = 26, - BisStorageId_Prodinfo = 27, - BisStorageId_ProdinfoF = 28, - BisStorageId_Safe = 29, - BisStorageId_User = 30, - BisStorageId_System = 31, - BisStorageId_SystemProperEncryption = 32, - BisStorageId_SystemProperPartition = 33, -}; - class FsMitmService : public IMitmServiceObject { private: bool has_initialized = false; diff --git a/stratosphere/fs_mitm/source/fsmitm_utils.cpp b/stratosphere/fs_mitm/source/fsmitm_utils.cpp index 9ebffae0b..46ed6c39b 100644 --- a/stratosphere/fs_mitm/source/fsmitm_utils.cpp +++ b/stratosphere/fs_mitm/source/fsmitm_utils.cpp @@ -65,6 +65,42 @@ void Utils::InitializeSdThreadFunc(void *args) { svcSleepThread(1000ULL); } + /* Back up CAL0, if it's not backed up already. */ + fsFsCreateDirectory(&g_sd_filesystem, "/atmosphere/automatic_backups"); + { + FsStorage cal0_storage; + FsFile cal0_file; + bool has_auto_backup = false; + + static const char * const PRODINFO_BACKUP_PATH = "/atmosphere/automatic_backups/PRODINFO.bin"; + constexpr size_t PRODINFO_SIZE = 0x4000; + + if (R_SUCCEEDED(fsFsOpenFile(&g_sd_filesystem, PRODINFO_BACKUP_PATH, FS_OPEN_READ, &cal0_file))) { + char magic[4]; + size_t read; + if (R_SUCCEEDED(fsFileRead(&cal0_file, 0, magic, sizeof(magic), &read)) && read == sizeof(magic) && memcmp(magic, "CAL0", sizeof(magic)) == 0) { + has_auto_backup = true; + } + fsFileClose(&cal0_file); + } + + if (!has_auto_backup && R_SUCCEEDED(fsOpenBisStorage(&cal0_storage, BisStorageId_Prodinfo))) { + u8 *cal0 = new u8[PRODINFO_SIZE]; + if (R_SUCCEEDED(fsStorageRead(&cal0_storage, 0, cal0, PRODINFO_SIZE)) ) { + fsFsCreateFile(&g_sd_filesystem, PRODINFO_BACKUP_PATH, PRODINFO_SIZE, 0); + if (R_SUCCEEDED(fsFsOpenFile(&g_sd_filesystem, PRODINFO_BACKUP_PATH, FS_OPEN_READ | FS_OPEN_WRITE, &cal0_file))) { + fsFileSetSize(&cal0_file, PRODINFO_SIZE); + fsFileWrite(&cal0_file, 0, cal0, PRODINFO_SIZE); + fsFileFlush(&cal0_file); + fsFileClose(&cal0_file); + } + } + + delete cal0; + fsStorageClose(&cal0_storage); + } + } + /* Check for MitM flags. */ FsDir titles_dir; if (R_SUCCEEDED(fsFsOpenDirectory(&g_sd_filesystem, "/atmosphere/titles", FS_DIROPEN_DIRECTORY, &titles_dir))) { @@ -307,7 +343,7 @@ bool Utils::HasFlag(u64 tid, const char *flag) { return false; } -bool Utils::HasGlobalFlag(u64 tid, const char *flag) { +bool Utils::HasGlobalFlag(const char *flag) { if (IsSdInitialized()) { FsFile f; char flag_path[FS_MAX_PATH] = {0}; diff --git a/stratosphere/fs_mitm/source/fsmitm_utils.hpp b/stratosphere/fs_mitm/source/fsmitm_utils.hpp index a730d44d6..71efe768b 100644 --- a/stratosphere/fs_mitm/source/fsmitm_utils.hpp +++ b/stratosphere/fs_mitm/source/fsmitm_utils.hpp @@ -18,6 +18,25 @@ #include #include +enum BisStorageId : u32 { + BisStorageId_Boot0 = 0, + BisStorageId_Boot1 = 10, + BisStorageId_RawNand = 20, + BisStorageId_BcPkg2_1 = 21, + BisStorageId_BcPkg2_2 = 22, + BisStorageId_BcPkg2_3 = 23, + BisStorageId_BcPkg2_4 = 24, + BisStorageId_BcPkg2_5 = 25, + BisStorageId_BcPkg2_6 = 26, + BisStorageId_Prodinfo = 27, + BisStorageId_ProdinfoF = 28, + BisStorageId_Safe = 29, + BisStorageId_User = 30, + BisStorageId_System = 31, + BisStorageId_SystemProperEncryption = 32, + BisStorageId_SystemProperPartition = 33, +}; + class Utils { public: static bool IsSdInitialized(); From b4781b8a4faf31153f37677b0f646d6d4ebd4354 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 15 Nov 2018 04:52:55 -0800 Subject: [PATCH 08/21] fs.mitm: improve backup path name --- stratosphere/fs_mitm/source/fsmitm_utils.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/stratosphere/fs_mitm/source/fsmitm_utils.cpp b/stratosphere/fs_mitm/source/fsmitm_utils.cpp index 46ed6c39b..2a425b9e1 100644 --- a/stratosphere/fs_mitm/source/fsmitm_utils.cpp +++ b/stratosphere/fs_mitm/source/fsmitm_utils.cpp @@ -71,11 +71,23 @@ void Utils::InitializeSdThreadFunc(void *args) { FsStorage cal0_storage; FsFile cal0_file; bool has_auto_backup = false; + char serial_number[0x40] = {0}; + + if (R_SUCCEEDED(setsysInitialize())) { + setsysGetSerialNumber(serial_number); + setsysExit(); + } + + char prodinfo_backup_path[FS_MAX_PATH] = {0}; + if (strlen(serial_number) > 0) { + snprintf(prodinfo_backup_path, sizeof(prodinfo_backup_path) - 1, "/atmosphere/automatic_backups/PRODINFO_%s.bin", serial_number); + } else { + snprintf(prodinfo_backup_path, sizeof(prodinfo_backup_path) - 1, "/atmosphere/automatic_backups/PRODINFO.bin"); + } - static const char * const PRODINFO_BACKUP_PATH = "/atmosphere/automatic_backups/PRODINFO.bin"; constexpr size_t PRODINFO_SIZE = 0x4000; - if (R_SUCCEEDED(fsFsOpenFile(&g_sd_filesystem, PRODINFO_BACKUP_PATH, FS_OPEN_READ, &cal0_file))) { + if (R_SUCCEEDED(fsFsOpenFile(&g_sd_filesystem, prodinfo_backup_path, FS_OPEN_READ, &cal0_file))) { char magic[4]; size_t read; if (R_SUCCEEDED(fsFileRead(&cal0_file, 0, magic, sizeof(magic), &read)) && read == sizeof(magic) && memcmp(magic, "CAL0", sizeof(magic)) == 0) { @@ -87,8 +99,8 @@ void Utils::InitializeSdThreadFunc(void *args) { if (!has_auto_backup && R_SUCCEEDED(fsOpenBisStorage(&cal0_storage, BisStorageId_Prodinfo))) { u8 *cal0 = new u8[PRODINFO_SIZE]; if (R_SUCCEEDED(fsStorageRead(&cal0_storage, 0, cal0, PRODINFO_SIZE)) ) { - fsFsCreateFile(&g_sd_filesystem, PRODINFO_BACKUP_PATH, PRODINFO_SIZE, 0); - if (R_SUCCEEDED(fsFsOpenFile(&g_sd_filesystem, PRODINFO_BACKUP_PATH, FS_OPEN_READ | FS_OPEN_WRITE, &cal0_file))) { + fsFsCreateFile(&g_sd_filesystem, prodinfo_backup_path, PRODINFO_SIZE, 0); + if (R_SUCCEEDED(fsFsOpenFile(&g_sd_filesystem, prodinfo_backup_path, FS_OPEN_READ | FS_OPEN_WRITE, &cal0_file))) { fsFileSetSize(&cal0_file, PRODINFO_SIZE); fsFileWrite(&cal0_file, 0, cal0, PRODINFO_SIZE); fsFileFlush(&cal0_file); From 1932662b4ca548d4c1ed16d937db53b81c034680 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 15 Nov 2018 04:54:07 -0800 Subject: [PATCH 09/21] fs.mitm: improve backup path name again --- stratosphere/fs_mitm/source/fsmitm_utils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stratosphere/fs_mitm/source/fsmitm_utils.cpp b/stratosphere/fs_mitm/source/fsmitm_utils.cpp index 2a425b9e1..e2f39bb9c 100644 --- a/stratosphere/fs_mitm/source/fsmitm_utils.cpp +++ b/stratosphere/fs_mitm/source/fsmitm_utils.cpp @@ -80,7 +80,7 @@ void Utils::InitializeSdThreadFunc(void *args) { char prodinfo_backup_path[FS_MAX_PATH] = {0}; if (strlen(serial_number) > 0) { - snprintf(prodinfo_backup_path, sizeof(prodinfo_backup_path) - 1, "/atmosphere/automatic_backups/PRODINFO_%s.bin", serial_number); + snprintf(prodinfo_backup_path, sizeof(prodinfo_backup_path) - 1, "/atmosphere/automatic_backups/%s_PRODINFO.bin", serial_number); } else { snprintf(prodinfo_backup_path, sizeof(prodinfo_backup_path) - 1, "/atmosphere/automatic_backups/PRODINFO.bin"); } From a00e120bf7be1a1407db89d6e184ad35fcf53adf Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 15 Nov 2018 06:23:44 -0800 Subject: [PATCH 10/21] fs.mitm: Make PRODINFO always read-only. --- stratosphere/fs_mitm/source/fsmitm_service.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/stratosphere/fs_mitm/source/fsmitm_service.cpp b/stratosphere/fs_mitm/source/fsmitm_service.cpp index 6fb27f846..b8384d26c 100644 --- a/stratosphere/fs_mitm/source/fsmitm_service.cpp +++ b/stratosphere/fs_mitm/source/fsmitm_service.cpp @@ -102,6 +102,9 @@ Result FsMitmService::OpenBisStorage(Out> out const bool allow_writes = this->title_id < 0x0100000000001000; if (bis_partition_id == BisStorageId_Boot0) { storage = std::make_shared(new Boot0Storage(bis_storage, this->title_id)); + } else if (bis_partition_id == BisStorageId_Prodinfo) { + /* PRODINFO should *never* be writable. */ + storage = std::make_shared(new ROProxyStorage(bis_storage)); } else { if (allow_writes) { storage = std::make_shared(new ROProxyStorage(bis_storage)); From 46cc08160d86eef9a63dc0eb1994871b1f770f62 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 15 Nov 2018 14:19:34 -0800 Subject: [PATCH 11/21] mitm: Improve session acquire semantics. --- stratosphere/libstratosphere | 2 +- stratosphere/sm/source/sm_registration.cpp | 45 ++++++++++++++++++++-- stratosphere/sm/source/sm_registration.hpp | 5 +++ stratosphere/sm/source/sm_user_service.cpp | 14 +++++++ stratosphere/sm/source/sm_user_service.hpp | 5 ++- 5 files changed, 65 insertions(+), 6 deletions(-) diff --git a/stratosphere/libstratosphere b/stratosphere/libstratosphere index bcd80ab44..8fcac73ab 160000 --- a/stratosphere/libstratosphere +++ b/stratosphere/libstratosphere @@ -1 +1 @@ -Subproject commit bcd80ab445258c20d968aad1c083fd8cb0937bee +Subproject commit 8fcac73ab2b91afe184abe48c887ea1cb9bf2076 diff --git a/stratosphere/sm/source/sm_registration.cpp b/stratosphere/sm/source/sm_registration.cpp index 0932db1f7..e5fc77c12 100644 --- a/stratosphere/sm/source/sm_registration.cpp +++ b/stratosphere/sm/source/sm_registration.cpp @@ -221,13 +221,11 @@ bool Registration::HasService(u64 service) { Result Registration::GetServiceHandle(u64 pid, u64 service, Handle *out) { Registration::Service *target_service = GetService(service); - if (target_service == NULL || ShouldInitDefer(service)) { + if (target_service == NULL || ShouldInitDefer(service) || target_service->mitm_waiting_ack) { /* Note: This defers the result until later. */ return RESULT_DEFER_SESSION; } - /* */ - *out = 0; Result rc; if (target_service->mitm_pid == 0 || target_service->mitm_pid == pid) { @@ -255,7 +253,17 @@ Result Registration::GetServiceHandle(u64 pid, u64 service, Handle *out) { rc = resp->result; if (R_SUCCEEDED(rc)) { if (resp->should_mitm) { - rc = svcConnectToPort(out, target_service->mitm_port_h); + rc = svcConnectToPort(&target_service->mitm_fwd_sess_h, target_service->port_h); + if (R_SUCCEEDED(rc)) { + rc = svcConnectToPort(out, target_service->mitm_port_h); + if (R_SUCCEEDED(rc)) { + target_service->mitm_waiting_ack_pid = pid; + target_service->mitm_waiting_ack = true; + } else { + svcCloseHandle(target_service->mitm_fwd_sess_h); + target_service->mitm_fwd_sess_h = 0; + } + } } else { rc = svcConnectToPort(out, target_service->port_h); } @@ -497,6 +505,35 @@ Result Registration::UninstallMitmForPid(u64 pid, u64 service) { return 0; } +Result Registration::AcknowledgeMitmSessionForPid(u64 pid, u64 service, Handle *out, u64 *out_pid) { + if (!service) { + return 0xC15; + } + + u64 service_name_len = GetServiceNameLength(service); + + /* If the service has bytes after a null terminator, that's no good. */ + if (service_name_len != 8 && (service >> (8 * service_name_len))) { + return 0xC15; + } + + Registration::Service *target_service = GetService(service); + if (target_service == NULL) { + return 0xE15; + } + + if ((!IsInitialProcess(pid) && target_service->mitm_pid != pid) || !target_service->mitm_waiting_ack) { + return 0x1015; + } + + *out = target_service->mitm_fwd_sess_h; + *out_pid = target_service->mitm_waiting_ack_pid; + target_service->mitm_fwd_sess_h = 0; + target_service->mitm_waiting_ack_pid = 0; + target_service->mitm_waiting_ack = false; + return 0; +} + Result Registration::AssociatePidTidForMitm(u64 pid, u64 tid) { for (auto &service : g_service_list) { if (service.mitm_pid) { diff --git a/stratosphere/sm/source/sm_registration.hpp b/stratosphere/sm/source/sm_registration.hpp index 9a30652bc..657483822 100644 --- a/stratosphere/sm/source/sm_registration.hpp +++ b/stratosphere/sm/source/sm_registration.hpp @@ -43,6 +43,10 @@ class Registration { u64 mitm_pid; Handle mitm_port_h; Handle mitm_query_h; + + bool mitm_waiting_ack; + u64 mitm_waiting_ack_pid; + Handle mitm_fwd_sess_h; }; /* Utilities. */ @@ -74,5 +78,6 @@ class Registration { /* Extension. */ static Result InstallMitmForPid(u64 pid, u64 service, Handle *out, Handle *query_out); static Result UninstallMitmForPid(u64 pid, u64 service); + static Result AcknowledgeMitmSessionForPid(u64 pid, u64 service, Handle *out, u64 *out_pid); static Result AssociatePidTidForMitm(u64 pid, u64 tid); }; diff --git a/stratosphere/sm/source/sm_user_service.cpp b/stratosphere/sm/source/sm_user_service.cpp index 138ceac8c..02c3b8a61 100644 --- a/stratosphere/sm/source/sm_user_service.cpp +++ b/stratosphere/sm/source/sm_user_service.cpp @@ -98,6 +98,20 @@ Result UserService::AtmosphereUninstallMitm(SmServiceName service) { return rc; } +Result UserService::AtmosphereAcknowledgeMitmSession(Out client_pid, Out fwd_h, SmServiceName service) { + Result rc = 0x415; + Handle out_fwd_h = 0; + if (this->has_initialized) { + rc = Registration::AcknowledgeMitmSessionForPid(this->pid, smEncodeName(service.name), &out_fwd_h, client_pid.GetPointer()); + } + + if (R_SUCCEEDED(rc)) { + fwd_h.SetValue(out_fwd_h); + } + + return rc; +} + Result UserService::AtmosphereAssociatePidTidForMitm(u64 pid, u64 tid) { Result rc = 0x415; if (this->has_initialized) { diff --git a/stratosphere/sm/source/sm_user_service.hpp b/stratosphere/sm/source/sm_user_service.hpp index f99f65bc2..3fedda58c 100644 --- a/stratosphere/sm/source/sm_user_service.hpp +++ b/stratosphere/sm/source/sm_user_service.hpp @@ -27,7 +27,8 @@ enum UserServiceCmd { User_Cmd_AtmosphereInstallMitm = 65000, User_Cmd_AtmosphereUninstallMitm = 65001, - User_Cmd_AtmosphereAssociatePidTidForMitm = 65002 + User_Cmd_AtmosphereAssociatePidTidForMitm = 65002, + User_Cmd_AtmosphereAcknowledgeMitmSession = 65003, }; class UserService final : public IServiceObject { @@ -45,6 +46,7 @@ class UserService final : public IServiceObject { virtual Result AtmosphereInstallMitm(Out srv_h, Out qry_h, SmServiceName service); virtual Result AtmosphereUninstallMitm(SmServiceName service); virtual Result AtmosphereAssociatePidTidForMitm(u64 pid, u64 tid); + virtual Result AtmosphereAcknowledgeMitmSession(Out client_pid, Out fwd_h, SmServiceName service); public: DEFINE_SERVICE_DISPATCH_TABLE { MakeServiceCommandMeta(), @@ -56,6 +58,7 @@ class UserService final : public IServiceObject { MakeServiceCommandMeta(), MakeServiceCommandMeta(), MakeServiceCommandMeta(), + MakeServiceCommandMeta(), #endif }; }; From e0c7bfc93dac643d8e3604c9f221f56ea5c7dc3d Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 15 Nov 2018 14:59:47 -0800 Subject: [PATCH 12/21] fs.mitm: Always mitm non-sysmodules. --- stratosphere/fs_mitm/source/fsmitm_service.cpp | 10 +++++++++- stratosphere/fs_mitm/source/fsmitm_service.hpp | 13 +++++-------- stratosphere/libstratosphere | 2 +- .../set_mitm/source/setsys_mitm_service.hpp | 2 +- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/stratosphere/fs_mitm/source/fsmitm_service.cpp b/stratosphere/fs_mitm/source/fsmitm_service.cpp index b8384d26c..ebb485c88 100644 --- a/stratosphere/fs_mitm/source/fsmitm_service.cpp +++ b/stratosphere/fs_mitm/source/fsmitm_service.cpp @@ -106,7 +106,7 @@ Result FsMitmService::OpenBisStorage(Out> out /* PRODINFO should *never* be writable. */ storage = std::make_shared(new ROProxyStorage(bis_storage)); } else { - if (allow_writes) { + if (!allow_writes) { storage = std::make_shared(new ROProxyStorage(bis_storage)); } else { /* Sysmodules should still be allowed to read and write. */ @@ -128,6 +128,10 @@ Result FsMitmService::OpenDataStorageByCurrentProcess(Outshould_override_contents) { + return RESULT_FORWARD_TO_SESSION; + } + bool has_cache = StorageCacheGetEntry(this->title_id, &storage); ON_SCOPE_EXIT { @@ -191,6 +195,10 @@ Result FsMitmService::OpenDataStorageByDataId(Outshould_override_contents) { + return RESULT_FORWARD_TO_SESSION; + } std::shared_ptr storage = nullptr; u32 out_domain_id = 0; diff --git a/stratosphere/fs_mitm/source/fsmitm_service.hpp b/stratosphere/fs_mitm/source/fsmitm_service.hpp index 33516ccba..3d4c6e3f1 100644 --- a/stratosphere/fs_mitm/source/fsmitm_service.hpp +++ b/stratosphere/fs_mitm/source/fsmitm_service.hpp @@ -30,9 +30,10 @@ enum FspSrvCmd : u32 { class FsMitmService : public IMitmServiceObject { private: bool has_initialized = false; + bool should_override_contents; public: - FsMitmService(std::shared_ptr s) : IMitmServiceObject(s) { - /* ... */ + FsMitmService(std::shared_ptr s, u64 pid) : IMitmServiceObject(s, pid) { + this->should_override_contents = !Utils::HasSdDisableMitMFlag(this->title_id) && Utils::HasOverrideButton(this->title_id); } static bool ShouldMitm(u64 pid, u64 tid) { @@ -40,12 +41,8 @@ class FsMitmService : public IMitmServiceObject { if (tid == 0x010000000000001FULL) { return true; } - - if (Utils::HasSdDisableMitMFlag(tid)) { - return false; - } - - return (tid >= 0x0100000000010000ULL || Utils::HasSdMitMFlag(tid)) && Utils::HasOverrideButton(tid); + + return (tid >= 0x0100000000010000ULL || Utils::HasSdMitMFlag(tid)); } static void PostProcess(IMitmServiceObject *obj, IpcResponseContext *ctx); diff --git a/stratosphere/libstratosphere b/stratosphere/libstratosphere index 8fcac73ab..0bec72ca3 160000 --- a/stratosphere/libstratosphere +++ b/stratosphere/libstratosphere @@ -1 +1 @@ -Subproject commit 8fcac73ab2b91afe184abe48c887ea1cb9bf2076 +Subproject commit 0bec72ca36084e9780a8c28abd4a0b24c03c18af diff --git a/stratosphere/set_mitm/source/setsys_mitm_service.hpp b/stratosphere/set_mitm/source/setsys_mitm_service.hpp index 2e3da205f..65a172175 100644 --- a/stratosphere/set_mitm/source/setsys_mitm_service.hpp +++ b/stratosphere/set_mitm/source/setsys_mitm_service.hpp @@ -25,7 +25,7 @@ enum SetSysCmd : u32 { class SetSysMitmService : public IMitmServiceObject { public: - SetSysMitmService(std::shared_ptr s) : IMitmServiceObject(s) { + SetSysMitmService(std::shared_ptr s, u64 pid) : IMitmServiceObject(s, pid) { /* ... */ } From cff283f77dcf22af95374de6eb4e6a2fe0000240 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 15 Nov 2018 15:27:01 -0800 Subject: [PATCH 13/21] fs.mitm: Protect the CAL0 backup from being read. --- stratosphere/fs_mitm/source/fsmitm_utils.cpp | 58 ++++--- stratosphere/fs_mitm/source/sha256.c | 113 +++++++++++++ stratosphere/fs_mitm/source/sha256.h | 36 ++++ stratosphere/fs_mitm/source/sha256_armv8.s | 163 +++++++++++++++++++ 4 files changed, 346 insertions(+), 24 deletions(-) create mode 100644 stratosphere/fs_mitm/source/sha256.c create mode 100644 stratosphere/fs_mitm/source/sha256.h create mode 100644 stratosphere/fs_mitm/source/sha256_armv8.s diff --git a/stratosphere/fs_mitm/source/fsmitm_utils.cpp b/stratosphere/fs_mitm/source/fsmitm_utils.cpp index e2f39bb9c..c80c8fe9c 100644 --- a/stratosphere/fs_mitm/source/fsmitm_utils.cpp +++ b/stratosphere/fs_mitm/source/fsmitm_utils.cpp @@ -23,6 +23,7 @@ #include "debug.hpp" #include "fsmitm_utils.hpp" #include "ini.h" +#include "sha256.h" static FsFileSystem g_sd_filesystem = {0}; static std::vector g_mitm_flagged_tids; @@ -37,6 +38,11 @@ static bool g_override_by_default = true; /* Static buffer for loader.ini contents at runtime. */ static char g_config_ini_data[0x800]; +/* Backup file for CAL0 partition. */ +static constexpr size_t ProdinfoSize = 0x8000; +static FsFile g_cal0_file; +static u8 g_cal0_backup[ProdinfoSize]; + static bool IsHexadecimal(const char *str) { while (*str) { if (isxdigit(*str)) { @@ -69,8 +75,7 @@ void Utils::InitializeSdThreadFunc(void *args) { fsFsCreateDirectory(&g_sd_filesystem, "/atmosphere/automatic_backups"); { FsStorage cal0_storage; - FsFile cal0_file; - bool has_auto_backup = false; + char serial_number[0x40] = {0}; if (R_SUCCEEDED(setsysInitialize())) { @@ -84,32 +89,37 @@ void Utils::InitializeSdThreadFunc(void *args) { } else { snprintf(prodinfo_backup_path, sizeof(prodinfo_backup_path) - 1, "/atmosphere/automatic_backups/PRODINFO.bin"); } - - constexpr size_t PRODINFO_SIZE = 0x4000; - - if (R_SUCCEEDED(fsFsOpenFile(&g_sd_filesystem, prodinfo_backup_path, FS_OPEN_READ, &cal0_file))) { - char magic[4]; - size_t read; - if (R_SUCCEEDED(fsFileRead(&cal0_file, 0, magic, sizeof(magic), &read)) && read == sizeof(magic) && memcmp(magic, "CAL0", sizeof(magic)) == 0) { - has_auto_backup = true; + + if (R_SUCCEEDED(fsFsOpenFile(&g_sd_filesystem, prodinfo_backup_path, FS_OPEN_READ | FS_OPEN_WRITE, &g_cal0_file))) { + bool has_auto_backup = false; + size_t read = 0; + if (R_SUCCEEDED(fsFileRead(&g_cal0_file, 0, g_cal0_backup, sizeof(g_cal0_backup), &read)) && read == sizeof(g_cal0_backup)) { + bool is_cal0_valid = true; + is_cal0_valid &= memcmp(g_cal0_backup, "CAL0", 4) == 0; + is_cal0_valid &= memcmp(g_cal0_backup + 0x250, serial_number, 0x18) == 0; + u32 cal0_size = ((u32 *)g_cal0_backup)[2]; + is_cal0_valid &= cal0_size + 0x40 <= ProdinfoSize; + if (is_cal0_valid) { + struct sha256_state sha_ctx; + u8 calc_hash[0x20]; + sha256_init(&sha_ctx); + sha256_update(&sha_ctx, g_cal0_backup + 0x40, cal0_size); + sha256_finalize(&sha_ctx); + sha256_finish(&sha_ctx, calc_hash); + is_cal0_valid &= memcmp(calc_hash, g_cal0_backup + 0x20, sizeof(calc_hash)) == 0; + } + has_auto_backup = is_cal0_valid; } - fsFileClose(&cal0_file); - } - - if (!has_auto_backup && R_SUCCEEDED(fsOpenBisStorage(&cal0_storage, BisStorageId_Prodinfo))) { - u8 *cal0 = new u8[PRODINFO_SIZE]; - if (R_SUCCEEDED(fsStorageRead(&cal0_storage, 0, cal0, PRODINFO_SIZE)) ) { - fsFsCreateFile(&g_sd_filesystem, prodinfo_backup_path, PRODINFO_SIZE, 0); - if (R_SUCCEEDED(fsFsOpenFile(&g_sd_filesystem, prodinfo_backup_path, FS_OPEN_READ | FS_OPEN_WRITE, &cal0_file))) { - fsFileSetSize(&cal0_file, PRODINFO_SIZE); - fsFileWrite(&cal0_file, 0, cal0, PRODINFO_SIZE); - fsFileFlush(&cal0_file); - fsFileClose(&cal0_file); + + if (!has_auto_backup && R_SUCCEEDED(fsOpenBisStorage(&cal0_storage, BisStorageId_Prodinfo))) { + if (R_SUCCEEDED(fsStorageRead(&cal0_storage, 0, g_cal0_backup, ProdinfoSize)) ) { + fsFileSetSize(&g_cal0_file, ProdinfoSize); + fsFileWrite(&g_cal0_file, 0, g_cal0_backup, ProdinfoSize); + fsFileFlush(&g_cal0_file); } } - delete cal0; - fsStorageClose(&cal0_storage); + /* NOTE: g_cal0_file is intentionally not closed here. This prevents any other process from opening it. */ } } diff --git a/stratosphere/fs_mitm/source/sha256.c b/stratosphere/fs_mitm/source/sha256.c new file mode 100644 index 000000000..02d40a758 --- /dev/null +++ b/stratosphere/fs_mitm/source/sha256.c @@ -0,0 +1,113 @@ +/* Based on linux source code */ +/* + * sha256_base.h - core logic for SHA-256 implementations + * + * Copyright (C) 2015 Linaro Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "sha256.h" + +#define unlikely(x) __builtin_expect(!!(x), 0) + +void sha256_block_data_order (uint32_t *ctx, const void *in, size_t num); + +int sha256_init(struct sha256_state *sctx) +{ + sctx->state[0] = SHA256_H0; + sctx->state[1] = SHA256_H1; + sctx->state[2] = SHA256_H2; + sctx->state[3] = SHA256_H3; + sctx->state[4] = SHA256_H4; + sctx->state[5] = SHA256_H5; + sctx->state[6] = SHA256_H6; + sctx->state[7] = SHA256_H7; + sctx->count = 0; + + return 0; +} + +int sha256_update(struct sha256_state *sctx, + const void *data, + size_t len) +{ + const u8 *data8 = (const u8 *)data; + unsigned int len32 = (unsigned int)len; + unsigned int partial = sctx->count % SHA256_BLOCK_SIZE; + + sctx->count += len32; + + if (unlikely((partial + len32) >= SHA256_BLOCK_SIZE)) { + int blocks; + + if (partial) { + int p = SHA256_BLOCK_SIZE - partial; + + memcpy(sctx->buf + partial, data8, p); + data8 += p; + len32 -= p; + + sha256_block_data_order(sctx->state, sctx->buf, 1); + } + + blocks = len32 / SHA256_BLOCK_SIZE; + len32 %= SHA256_BLOCK_SIZE; + + if (blocks) { + sha256_block_data_order(sctx->state, data8, blocks); + data8 += blocks * SHA256_BLOCK_SIZE; + } + partial = 0; + } + if (len32) + memcpy(sctx->buf + partial, data8, len32); + + return 0; +} + +int sha256_finalize(struct sha256_state *sctx) +{ + const int bit_offset = SHA256_BLOCK_SIZE - sizeof(u64); + u64 *bits = (u64 *)(sctx->buf + bit_offset); + unsigned int partial = sctx->count % SHA256_BLOCK_SIZE; + + sctx->buf[partial++] = 0x80; + if (partial > bit_offset) { + memset(sctx->buf + partial, 0x0, SHA256_BLOCK_SIZE - partial); + partial = 0; + + sha256_block_data_order(sctx->state, sctx->buf, 1); + } + + memset(sctx->buf + partial, 0x0, bit_offset - partial); + *bits = __builtin_bswap64(sctx->count << 3); + sha256_block_data_order(sctx->state, sctx->buf, 1); + + return 0; +} + +int sha256_finish(struct sha256_state *sctx, void *out) +{ + unsigned int digest_size = 32; + u32 *digest = (u32 *)out; + int i; + + // Switch: misalignment shouldn't be a problem here... + for (i = 0; digest_size > 0; i++, digest_size -= sizeof(u32)) + *digest++ = __builtin_bswap32(sctx->state[i]); + + *sctx = (struct sha256_state){}; + return 0; +} + +#ifdef __cplusplus +} +#endif diff --git a/stratosphere/fs_mitm/source/sha256.h b/stratosphere/fs_mitm/source/sha256.h new file mode 100644 index 000000000..cfb09f89c --- /dev/null +++ b/stratosphere/fs_mitm/source/sha256.h @@ -0,0 +1,36 @@ +#pragma once + +/* Based on linux source code */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define SHA256_DIGEST_SIZE 32 +#define SHA256_BLOCK_SIZE 64 + +#define SHA256_H0 0x6a09e667UL +#define SHA256_H1 0xbb67ae85UL +#define SHA256_H2 0x3c6ef372UL +#define SHA256_H3 0xa54ff53aUL +#define SHA256_H4 0x510e527fUL +#define SHA256_H5 0x9b05688cUL +#define SHA256_H6 0x1f83d9abUL +#define SHA256_H7 0x5be0cd19UL + +struct sha256_state { + u32 state[SHA256_DIGEST_SIZE / 4]; + u64 count; + u8 buf[SHA256_BLOCK_SIZE]; +}; + +int sha256_init(struct sha256_state *sctx); +int sha256_update(struct sha256_state *sctx, const void *data, size_t len); +int sha256_finalize(struct sha256_state *sctx); +int sha256_finish(struct sha256_state *sctx, void *out); + +#ifdef __cplusplus +} +#endif diff --git a/stratosphere/fs_mitm/source/sha256_armv8.s b/stratosphere/fs_mitm/source/sha256_armv8.s new file mode 100644 index 000000000..0420d38be --- /dev/null +++ b/stratosphere/fs_mitm/source/sha256_armv8.s @@ -0,0 +1,163 @@ +.section .text.sha256_armv8, "ax", %progbits +.align 5 +.arch armv8-a+crypto + +# SHA256 assembly implementation for ARMv8 AArch64 (based on linux source code) + +.global sha256_block_data_order +.type sha256_block_data_order,%function +sha256_block_data_order: + +.Lsha256prolog: + + stp x29, x30, [sp,#-64]! + mov x29, sp + adr x3, .LKConstant256 + str q8, [sp, #16] + ld1 {v16.4s-v19.4s}, [x3], #64 + ld1 {v0.4s}, [x0], #16 + ld1 {v20.4s-v23.4s}, [x3], #64 + add x2, x1, x2, lsl #6 + ld1 {v1.4s}, [x0] + ld1 {v24.4s-v27.4s}, [x3], #64 + sub x0, x0, #16 + str q9, [sp, #32] + str q10, [sp, #48] + ld1 {v28.4s-v31.4s}, [x3], #64 + +.Lsha256loop: + + ld1 {v5.16b-v8.16b}, [x1], #64 + mov v2.16b, v0.16b + mov v3.16b, v1.16b + + rev32 v5.16b, v5.16b + rev32 v6.16b, v6.16b + add v9.4s, v5.4s, v16.4s + rev32 v7.16b, v7.16b + add v10.4s, v6.4s, v17.4s + mov v4.16b, v2.16b + sha256h q2, q3, v9.4s + sha256h2 q3, q4, v9.4s + sha256su0 v5.4s, v6.4s + rev32 v8.16b, v8.16b + add v9.4s, v7.4s, v18.4s + mov v4.16b, v2.16b + sha256h q2, q3, v10.4s + sha256h2 q3, q4, v10.4s + sha256su0 v6.4s, v7.4s + sha256su1 v5.4s, v7.4s, v8.4s + add v10.4s, v8.4s, v19.4s + mov v4.16b, v2.16b + sha256h q2, q3, v9.4s + sha256h2 q3, q4, v9.4s + sha256su0 v7.4s, v8.4s + sha256su1 v6.4s, v8.4s, v5.4s + add v9.4s, v5.4s, v20.4s + mov v4.16b, v2.16b + sha256h q2, q3, v10.4s + sha256h2 q3, q4, v10.4s + sha256su0 v8.4s, v5.4s + sha256su1 v7.4s, v5.4s, v6.4s + add v10.4s, v6.4s, v21.4s + mov v4.16b, v2.16b + sha256h q2, q3, v9.4s + sha256h2 q3, q4, v9.4s + sha256su0 v5.4s, v6.4s + sha256su1 v8.4s, v6.4s, v7.4s + add v9.4s, v7.4s, v22.4s + mov v4.16b, v2.16b + sha256h q2, q3, v10.4s + sha256h2 q3, q4, v10.4s + sha256su0 v6.4s, v7.4s + sha256su1 v5.4s, v7.4s, v8.4s + add v10.4s, v8.4s, v23.4s + mov v4.16b, v2.16b + sha256h q2, q3, v9.4s + sha256h2 q3, q4, v9.4s + sha256su0 v7.4s, v8.4s + sha256su1 v6.4s, v8.4s, v5.4s + add v9.4s, v5.4s, v24.4s + mov v4.16b, v2.16b + sha256h q2, q3, v10.4s + sha256h2 q3, q4, v10.4s + sha256su0 v8.4s, v5.4s + sha256su1 v7.4s, v5.4s, v6.4s + add v10.4s, v6.4s, v25.4s + mov v4.16b, v2.16b + sha256h q2, q3, v9.4s + sha256h2 q3, q4, v9.4s + sha256su0 v5.4s, v6.4s + sha256su1 v8.4s, v6.4s, v7.4s + add v9.4s, v7.4s, v26.4s + mov v4.16b, v2.16b + sha256h q2, q3, v10.4s + sha256h2 q3, q4, v10.4s + sha256su0 v6.4s, v7.4s + sha256su1 v5.4s, v7.4s, v8.4s + add v10.4s, v8.4s, v27.4s + mov v4.16b, v2.16b + sha256h q2, q3, v9.4s + sha256h2 q3, q4, v9.4s + sha256su0 v7.4s, v8.4s + sha256su1 v6.4s, v8.4s, v5.4s + add v9.4s, v5.4s, v28.4s + mov v4.16b, v2.16b + sha256h q2, q3, v10.4s + sha256h2 q3, q4, v10.4s + sha256su0 v8.4s, v5.4s + sha256su1 v7.4s, v5.4s, v6.4s + add v10.4s, v6.4s, v29.4s + mov v4.16b, v2.16b + sha256h q2, q3, v9.4s + sha256h2 q3, q4, v9.4s + sha256su1 v8.4s, v6.4s, v7.4s + add v9.4s, v7.4s, v30.4s + mov v4.16b, v2.16b + sha256h q2, q3, v10.4s + sha256h2 q3, q4, v10.4s + add v10.4s, v8.4s, v31.4s + mov v4.16b, v2.16b + sha256h q2, q3, v9.4s + sha256h2 q3, q4, v9.4s + mov v4.16b, v2.16b + sha256h q2, q3, v10.4s + sha256h2 q3, q4, v10.4s + cmp x1, x2 + add v1.4s, v1.4s, v3.4s + add v0.4s, v0.4s, v2.4s + b.ne .Lsha256loop + +.Lsha256epilog: + + st1 {v0.4s,v1.4s}, [x0] + ldr q10, [sp, #48] + ldr q9, [sp, #32] + ldr q8, [sp, #16] + ldr x29, [sp], #64 + ret + +.align 5 +.LKConstant256: +.word 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5 +.word 0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5 +.word 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3 +.word 0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174 +.word 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc +.word 0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da +.word 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7 +.word 0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967 +.word 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13 +.word 0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85 +.word 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3 +.word 0xd192e819,0xd6990624,0xf40e3585,0x106aa070 +.word 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5 +.word 0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3 +.word 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208 +.word 0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 + +.size sha256_block_data_order,.-sha256_block_data_order +.align 2 + + + From ff09efb1bf07fc8e00e48cd02e96e939808fa69a Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 15 Nov 2018 15:29:02 -0800 Subject: [PATCH 14/21] fs.mitm: Prevent non-sysmodules from reading CAL0. --- stratosphere/fs_mitm/source/fsmitm_service.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/stratosphere/fs_mitm/source/fsmitm_service.cpp b/stratosphere/fs_mitm/source/fsmitm_service.cpp index ebb485c88..9897edf6f 100644 --- a/stratosphere/fs_mitm/source/fsmitm_service.cpp +++ b/stratosphere/fs_mitm/source/fsmitm_service.cpp @@ -99,14 +99,21 @@ Result FsMitmService::OpenBisStorage(Out> out FsStorage bis_storage; rc = fsOpenBisStorageFwd(this->forward_service.get(), &bis_storage, bis_partition_id); if (R_SUCCEEDED(rc)) { - const bool allow_writes = this->title_id < 0x0100000000001000; + const bool is_sysmodule = this->title_id < 0x0100000000001000; if (bis_partition_id == BisStorageId_Boot0) { storage = std::make_shared(new Boot0Storage(bis_storage, this->title_id)); } else if (bis_partition_id == BisStorageId_Prodinfo) { /* PRODINFO should *never* be writable. */ - storage = std::make_shared(new ROProxyStorage(bis_storage)); + if (is_sysmodule) { + storage = std::make_shared(new ROProxyStorage(bis_storage)); + } else { + /* Do not allow non-sysmodules to read *or* write CAL0. */ + fsStorageClose(&bis_storage); + return 0x320002; + } } else { - if (!allow_writes) { + if (!is_sysmodule) { + /* Non-sysmodules should be allowed to read. */ storage = std::make_shared(new ROProxyStorage(bis_storage)); } else { /* Sysmodules should still be allowed to read and write. */ From 2b4e6bf25d08b95f652cec789c0c8970121371ae Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 15 Nov 2018 15:46:05 -0800 Subject: [PATCH 15/21] fs.mitm: just intercept literally everything --- stratosphere/fs_mitm/source/fsmitm_main.cpp | 2 +- stratosphere/fs_mitm/source/fsmitm_service.hpp | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/stratosphere/fs_mitm/source/fsmitm_main.cpp b/stratosphere/fs_mitm/source/fsmitm_main.cpp index 95f627d7a..d7dcf136b 100644 --- a/stratosphere/fs_mitm/source/fsmitm_main.cpp +++ b/stratosphere/fs_mitm/source/fsmitm_main.cpp @@ -78,7 +78,7 @@ void __appExit(void) { struct FsMitmManagerOptions { static const size_t PointerBufferSize = 0x800; - static const size_t MaxDomains = 0x10; + static const size_t MaxDomains = 0x40; static const size_t MaxDomainObjects = 0x4000; }; using FsMitmManager = WaitableManager; diff --git a/stratosphere/fs_mitm/source/fsmitm_service.hpp b/stratosphere/fs_mitm/source/fsmitm_service.hpp index 3d4c6e3f1..777782b46 100644 --- a/stratosphere/fs_mitm/source/fsmitm_service.hpp +++ b/stratosphere/fs_mitm/source/fsmitm_service.hpp @@ -33,16 +33,16 @@ class FsMitmService : public IMitmServiceObject { bool should_override_contents; public: FsMitmService(std::shared_ptr s, u64 pid) : IMitmServiceObject(s, pid) { - this->should_override_contents = !Utils::HasSdDisableMitMFlag(this->title_id) && Utils::HasOverrideButton(this->title_id); + if (Utils::HasSdDisableMitMFlag(this->title_id)) { + this->should_override_contents = false; + } else { + this->should_override_contents = (this->title_id >= 0x0100000000010000ULL || Utils::HasSdMitMFlag(this->title_id)) && Utils::HasOverrideButton(this->title_id); + } } static bool ShouldMitm(u64 pid, u64 tid) { - /* Always intercept NS, so that we can protect the boot partition. */ - if (tid == 0x010000000000001FULL) { - return true; - } - - return (tid >= 0x0100000000010000ULL || Utils::HasSdMitMFlag(tid)); + /* fs.mitm should always mitm everything. */ + return true; } static void PostProcess(IMitmServiceObject *obj, IpcResponseContext *ctx); From abde50f16205f8c24a59530c310a845421f14ca9 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 15 Nov 2018 15:58:31 -0800 Subject: [PATCH 16/21] fs.mitm: wipe CAL0 backup from memory when done. --- stratosphere/fs_mitm/source/fsmitm_utils.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/stratosphere/fs_mitm/source/fsmitm_utils.cpp b/stratosphere/fs_mitm/source/fsmitm_utils.cpp index c80c8fe9c..7e47f0d60 100644 --- a/stratosphere/fs_mitm/source/fsmitm_utils.cpp +++ b/stratosphere/fs_mitm/source/fsmitm_utils.cpp @@ -120,6 +120,7 @@ void Utils::InitializeSdThreadFunc(void *args) { } /* NOTE: g_cal0_file is intentionally not closed here. This prevents any other process from opening it. */ + memset(g_cal0_backup, 0, sizeof(g_cal0_backup)); } } From d88fd04c73a83f42a3b49b0c41b6b7ad7ee64928 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 15 Nov 2018 17:23:05 -0800 Subject: [PATCH 17/21] fs.mitm: fix set:sys race condition. --- stratosphere/fs_mitm/source/fsmitm_main.cpp | 2 +- stratosphere/fs_mitm/source/fsmitm_utils.cpp | 26 +++++++++++--------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/stratosphere/fs_mitm/source/fsmitm_main.cpp b/stratosphere/fs_mitm/source/fsmitm_main.cpp index d7dcf136b..9d477261d 100644 --- a/stratosphere/fs_mitm/source/fsmitm_main.cpp +++ b/stratosphere/fs_mitm/source/fsmitm_main.cpp @@ -88,7 +88,7 @@ int main(int argc, char **argv) Thread sd_initializer_thread = {0}; Thread hid_initializer_thread = {0}; consoleDebugInit(debugDevice_SVC); - + if (R_FAILED(threadCreate(&sd_initializer_thread, &Utils::InitializeSdThreadFunc, NULL, 0x4000, 0x15, 0))) { /* TODO: Panic. */ } diff --git a/stratosphere/fs_mitm/source/fsmitm_utils.cpp b/stratosphere/fs_mitm/source/fsmitm_utils.cpp index 7e47f0d60..e692bdc5b 100644 --- a/stratosphere/fs_mitm/source/fsmitm_utils.cpp +++ b/stratosphere/fs_mitm/source/fsmitm_utils.cpp @@ -40,7 +40,8 @@ static char g_config_ini_data[0x800]; /* Backup file for CAL0 partition. */ static constexpr size_t ProdinfoSize = 0x8000; -static FsFile g_cal0_file; +static FsFile g_cal0_file = {0}; +static u8 g_cal0_storage_backup[ProdinfoSize]; static u8 g_cal0_backup[ProdinfoSize]; static bool IsHexadecimal(const char *str) { @@ -75,13 +76,14 @@ void Utils::InitializeSdThreadFunc(void *args) { fsFsCreateDirectory(&g_sd_filesystem, "/atmosphere/automatic_backups"); { FsStorage cal0_storage; + if (R_FAILED(fsOpenBisStorage(&cal0_storage, BisStorageId_Prodinfo)) || R_FAILED(fsStorageRead(&cal0_storage, 0, g_cal0_storage_backup, ProdinfoSize))) { + std::abort(); + } + fsStorageClose(&cal0_storage); char serial_number[0x40] = {0}; + memcpy(serial_number, g_cal0_storage_backup + 0x250, 0x18); - if (R_SUCCEEDED(setsysInitialize())) { - setsysGetSerialNumber(serial_number); - setsysExit(); - } char prodinfo_backup_path[FS_MAX_PATH] = {0}; if (strlen(serial_number) > 0) { @@ -89,7 +91,8 @@ void Utils::InitializeSdThreadFunc(void *args) { } else { snprintf(prodinfo_backup_path, sizeof(prodinfo_backup_path) - 1, "/atmosphere/automatic_backups/PRODINFO.bin"); } - + + fsFsCreateFile(&g_sd_filesystem, prodinfo_backup_path, ProdinfoSize, 0); if (R_SUCCEEDED(fsFsOpenFile(&g_sd_filesystem, prodinfo_backup_path, FS_OPEN_READ | FS_OPEN_WRITE, &g_cal0_file))) { bool has_auto_backup = false; size_t read = 0; @@ -111,15 +114,14 @@ void Utils::InitializeSdThreadFunc(void *args) { has_auto_backup = is_cal0_valid; } - if (!has_auto_backup && R_SUCCEEDED(fsOpenBisStorage(&cal0_storage, BisStorageId_Prodinfo))) { - if (R_SUCCEEDED(fsStorageRead(&cal0_storage, 0, g_cal0_backup, ProdinfoSize)) ) { - fsFileSetSize(&g_cal0_file, ProdinfoSize); - fsFileWrite(&g_cal0_file, 0, g_cal0_backup, ProdinfoSize); - fsFileFlush(&g_cal0_file); - } + if (!has_auto_backup) { + fsFileSetSize(&g_cal0_file, ProdinfoSize); + fsFileWrite(&g_cal0_file, 0, g_cal0_backup, ProdinfoSize); + fsFileFlush(&g_cal0_file); } /* NOTE: g_cal0_file is intentionally not closed here. This prevents any other process from opening it. */ + memset(g_cal0_storage_backup, 0, sizeof(g_cal0_storage_backup)); memset(g_cal0_backup, 0, sizeof(g_cal0_backup)); } } From a07e37121dafd1c2027e7bda1db03bba1d059927 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 15 Nov 2018 18:25:11 -0800 Subject: [PATCH 18/21] fs.mitm: loosen boot0 write restrictions, protect keyblobs. --- .../fs_mitm/source/fsmitm_boot0storage.cpp | 50 +++++++++++++++---- .../fs_mitm/source/fsmitm_boot0storage.hpp | 5 +- .../fs_mitm/source/fsmitm_service.hpp | 4 +- 3 files changed, 46 insertions(+), 13 deletions(-) diff --git a/stratosphere/fs_mitm/source/fsmitm_boot0storage.cpp b/stratosphere/fs_mitm/source/fsmitm_boot0storage.cpp index e2b25ad40..1554496bd 100644 --- a/stratosphere/fs_mitm/source/fsmitm_boot0storage.cpp +++ b/stratosphere/fs_mitm/source/fsmitm_boot0storage.cpp @@ -23,10 +23,6 @@ static HosMutex g_boot0_mutex; static u8 g_boot0_bct_buffer[Boot0Storage::BctEndOffset]; -bool Boot0Storage::AllowWrites() { - return this->title_id < 0x0100000000001000ULL; -} - bool Boot0Storage::CanModifyBctPubks() { return this->title_id != 0x010000000000001FULL; } @@ -40,18 +36,52 @@ Result Boot0Storage::Read(void *_buffer, size_t size, u64 offset) { Result Boot0Storage::Write(void *_buffer, size_t size, u64 offset) { std::scoped_lock lk{g_boot0_mutex}; - if (!AllowWrites()) { - return 0x313802; + Result rc = 0; + u8 *buffer = static_cast(_buffer); + + /* Protect the keyblob region from writes. */ + if (offset <= EksStart) { + if (offset + size < EksStart) { + /* Fall through, no need to do anything here. */ + } else { + if (offset + size < EksEnd) { + /* Adjust size to avoid writing end of data. */ + size = EksStart - offset; + } else { + /* Perform portion of write falling past end of keyblobs. */ + const u64 diff = EksEnd - offset; + if (R_FAILED((rc = Base::Write(buffer + diff, size - diff, EksEnd)))) { + return rc; + } + /* Adjust size to avoid writing end of data. */ + size = EksStart - offset; + } + } + } else { + if (offset < EksEnd) { + if (offset + size < EksEnd) { + /* Ignore writes falling strictly within the region. */ + return 0; + } else { + /* Only write past the end of the keyblob region. */ + buffer = buffer + (EksEnd - offset); + size -= (EksEnd - offset); + offset = EksEnd; + } + } else { + /* Fall through, no need to do anything here. */ + } + } + + if (size == 0) { + return 0; } /* We care about protecting autorcm from NS. */ if (CanModifyBctPubks() || offset >= BctEndOffset || (offset + BctSize >= BctEndOffset && offset % BctSize >= BctPubkEnd)) { - return Base::Write(_buffer, size, offset); + return Base::Write(buffer, size, offset); } - Result rc = 0; - u8 *buffer = static_cast(_buffer); - /* First, let's deal with the data past the end. */ if (offset + size >= BctEndOffset) { const u64 diff = BctEndOffset - offset; diff --git a/stratosphere/fs_mitm/source/fsmitm_boot0storage.hpp b/stratosphere/fs_mitm/source/fsmitm_boot0storage.hpp index cf53948f4..b86791ff8 100644 --- a/stratosphere/fs_mitm/source/fsmitm_boot0storage.hpp +++ b/stratosphere/fs_mitm/source/fsmitm_boot0storage.hpp @@ -142,10 +142,13 @@ class Boot0Storage : public SectoredProxyStorage<0x200> { static constexpr u64 BctPubkStart = 0x210; static constexpr u64 BctPubkSize = 0x100; static constexpr u64 BctPubkEnd = BctPubkStart + BctPubkSize; + + static constexpr u64 EksStart = 0x180000; + static constexpr u64 EksSize = 0x4000; + static constexpr u64 EksEnd = EksStart + EksSize; private: u64 title_id; private: - bool AllowWrites(); bool CanModifyBctPubks(); public: Boot0Storage(FsStorage *s, u64 t) : Base(s), title_id(t) { } diff --git a/stratosphere/fs_mitm/source/fsmitm_service.hpp b/stratosphere/fs_mitm/source/fsmitm_service.hpp index 777782b46..fd69bc85a 100644 --- a/stratosphere/fs_mitm/source/fsmitm_service.hpp +++ b/stratosphere/fs_mitm/source/fsmitm_service.hpp @@ -41,8 +41,8 @@ class FsMitmService : public IMitmServiceObject { } static bool ShouldMitm(u64 pid, u64 tid) { - /* fs.mitm should always mitm everything. */ - return true; + /* fs.mitm should always mitm everything that's not a kip. */ + return pid >= 0x50; } static void PostProcess(IMitmServiceObject *obj, IpcResponseContext *ctx); From dd255df90db53de991407e8b9019c696b1ee9832 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 29 Nov 2018 12:13:57 -0800 Subject: [PATCH 19/21] Change mitm conditions due to sleep mode issue --- stratosphere/fs_mitm/source/fsmitm_service.hpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/stratosphere/fs_mitm/source/fsmitm_service.hpp b/stratosphere/fs_mitm/source/fsmitm_service.hpp index fd69bc85a..483bf8c33 100644 --- a/stratosphere/fs_mitm/source/fsmitm_service.hpp +++ b/stratosphere/fs_mitm/source/fsmitm_service.hpp @@ -41,8 +41,15 @@ class FsMitmService : public IMitmServiceObject { } static bool ShouldMitm(u64 pid, u64 tid) { - /* fs.mitm should always mitm everything that's not a kip. */ - return pid >= 0x50; + static std::atomic_bool has_launched_qlaunch = false; + + /* TODO: intercepting everything seems to cause issues with sleep mode, for some reason. */ + /* Figure out why, and address it. */ + if (tid == 0x0100000000001000ULL) { + has_launched_qlaunch = true; + } + + return has_launched_qlaunch || tid == 0x010000000000001FULL || tid >= 0x0100000000010000ULL || Utils::HasSdMitMFlag(tid); } static void PostProcess(IMitmServiceObject *obj, IpcResponseContext *ctx); From 67ff4fe913eaa469f78e151cccb8b240298263b7 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 29 Nov 2018 12:20:08 -0800 Subject: [PATCH 20/21] fs.mitm: tweak conditions a little more. --- stratosphere/fs_mitm/source/fsmitm_service.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/stratosphere/fs_mitm/source/fsmitm_service.hpp b/stratosphere/fs_mitm/source/fsmitm_service.hpp index 483bf8c33..e7d2ad571 100644 --- a/stratosphere/fs_mitm/source/fsmitm_service.hpp +++ b/stratosphere/fs_mitm/source/fsmitm_service.hpp @@ -41,6 +41,11 @@ class FsMitmService : public IMitmServiceObject { } static bool ShouldMitm(u64 pid, u64 tid) { + /* Don't Mitm KIPs */ + if (pid < 0x50) { + return false; + } + static std::atomic_bool has_launched_qlaunch = false; /* TODO: intercepting everything seems to cause issues with sleep mode, for some reason. */ From ae4d29a49ffbec767609fe8e1cc10a38e952fa27 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 29 Nov 2018 12:30:32 -0800 Subject: [PATCH 21/21] fs.mitm: add flag support for writing bis/reading cal0 --- stratosphere/fs_mitm/source/fsmitm_service.cpp | 12 +++++++----- stratosphere/fs_mitm/source/fsmitm_utils.cpp | 12 +++++++++++- stratosphere/fs_mitm/source/fsmitm_utils.hpp | 4 +++- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/stratosphere/fs_mitm/source/fsmitm_service.cpp b/stratosphere/fs_mitm/source/fsmitm_service.cpp index 9897edf6f..0b1e1cf18 100644 --- a/stratosphere/fs_mitm/source/fsmitm_service.cpp +++ b/stratosphere/fs_mitm/source/fsmitm_service.cpp @@ -100,11 +100,13 @@ Result FsMitmService::OpenBisStorage(Out> out rc = fsOpenBisStorageFwd(this->forward_service.get(), &bis_storage, bis_partition_id); if (R_SUCCEEDED(rc)) { const bool is_sysmodule = this->title_id < 0x0100000000001000; + const bool has_bis_write_flag = Utils::HasFlag(this->title_id, "bis_write"); + const bool has_cal0_read_flag = Utils::HasFlag(this->title_id, "cal_read"); if (bis_partition_id == BisStorageId_Boot0) { storage = std::make_shared(new Boot0Storage(bis_storage, this->title_id)); } else if (bis_partition_id == BisStorageId_Prodinfo) { /* PRODINFO should *never* be writable. */ - if (is_sysmodule) { + if (is_sysmodule || has_cal0_read_flag) { storage = std::make_shared(new ROProxyStorage(bis_storage)); } else { /* Do not allow non-sysmodules to read *or* write CAL0. */ @@ -112,12 +114,12 @@ Result FsMitmService::OpenBisStorage(Out> out return 0x320002; } } else { - if (!is_sysmodule) { - /* Non-sysmodules should be allowed to read. */ - storage = std::make_shared(new ROProxyStorage(bis_storage)); - } else { + if (is_sysmodule || has_bis_write_flag) { /* Sysmodules should still be allowed to read and write. */ storage = std::make_shared(new ProxyStorage(bis_storage)); + } else { + /* Non-sysmodules should be allowed to read. */ + storage = std::make_shared(new ROProxyStorage(bis_storage)); } } if (out_storage.IsDomain()) { diff --git a/stratosphere/fs_mitm/source/fsmitm_utils.cpp b/stratosphere/fs_mitm/source/fsmitm_utils.cpp index e692bdc5b..c1683eda9 100644 --- a/stratosphere/fs_mitm/source/fsmitm_utils.cpp +++ b/stratosphere/fs_mitm/source/fsmitm_utils.cpp @@ -346,7 +346,7 @@ Result Utils::SaveSdFileForAtmosphere(u64 title_id, const char *fn, void *data, return rc; } -bool Utils::HasFlag(u64 tid, const char *flag) { +bool Utils::HasTitleFlag(u64 tid, const char *flag) { if (IsSdInitialized()) { FsFile f; char flag_path[FS_MAX_PATH]; @@ -381,6 +381,16 @@ bool Utils::HasGlobalFlag(const char *flag) { return false; } +bool Utils::HasHblFlag(const char *flag) { + char hbl_flag[FS_MAX_PATH] = {0}; + snprintf(hbl_flag, sizeof(hbl_flag), "hbl_%s", flag); + return HasGlobalFlag(hbl_flag); +} + +bool Utils::HasFlag(u64 tid, const char *flag) { + return HasTitleFlag(tid, flag) || (tid == g_override_hbl_tid && HasHblFlag(flag)); +} + bool Utils::HasSdMitMFlag(u64 tid) { if (tid == g_override_hbl_tid) { return true; diff --git a/stratosphere/fs_mitm/source/fsmitm_utils.hpp b/stratosphere/fs_mitm/source/fsmitm_utils.hpp index 71efe768b..0811c1f7e 100644 --- a/stratosphere/fs_mitm/source/fsmitm_utils.hpp +++ b/stratosphere/fs_mitm/source/fsmitm_utils.hpp @@ -58,8 +58,10 @@ class Utils { /* SD card Initialization + MitM detection. */ static void InitializeSdThreadFunc(void *args); - static bool HasFlag(u64 tid, const char *flag); + static bool HasTitleFlag(u64 tid, const char *flag); + static bool HasHblFlag(const char *flag); static bool HasGlobalFlag(const char *flag); + static bool HasFlag(u64 tid, const char *flag); static bool HasSdMitMFlag(u64 tid); static bool HasSdDisableMitMFlag(u64 tid);