From 61f9e0dfb9bdb9b18d2f908f272f740f37822e6f Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 20 Apr 2020 19:21:17 -0700 Subject: [PATCH] ams.mitm: Implement revamped blanking/write policy --- .../source/amsmitm_initialization.cpp | 20 +- .../source/amsmitm_initialization.hpp | 3 +- stratosphere/ams_mitm/source/amsmitm_main.cpp | 3 - .../source/amsmitm_prodinfo_utils.cpp | 176 ++++++++++++------ .../source/amsmitm_prodinfo_utils.hpp | 16 +- .../source/fs_mitm/fs_mitm_service.cpp | 14 +- .../source/fs_mitm/fs_mitm_service.hpp | 5 + .../fsmitm_calibration_binary_storage.cpp | 135 ++++++++++++++ .../fsmitm_calibration_binary_storage.hpp | 53 ++++++ .../source/set_mitm/settings_sd_kvs.cpp | 4 - 10 files changed, 347 insertions(+), 82 deletions(-) create mode 100644 stratosphere/ams_mitm/source/fs_mitm/fsmitm_calibration_binary_storage.cpp create mode 100644 stratosphere/ams_mitm/source/fs_mitm/fsmitm_calibration_binary_storage.hpp diff --git a/stratosphere/ams_mitm/source/amsmitm_initialization.cpp b/stratosphere/ams_mitm/source/amsmitm_initialization.cpp index 0ba71cb3a..7fa891f6c 100644 --- a/stratosphere/ams_mitm/source/amsmitm_initialization.cpp +++ b/stratosphere/ams_mitm/source/amsmitm_initialization.cpp @@ -58,6 +58,9 @@ namespace ams::mitm { os::ThreadType g_initialize_thread; alignas(os::ThreadStackAlignment) u8 g_initialize_thread_stack[InitializeThreadStackSize]; + os::Mutex g_prodinfo_init_lock(false); + bool g_initialized_prodinfo; + /* Console-unique data backup and protection. */ FsFile g_bis_key_file; @@ -90,7 +93,7 @@ namespace ams::mitm { /* Initialize PRODINFO and get a reference for the device. */ char device_reference[0x40] = {}; ON_SCOPE_EXIT { std::memset(device_reference, 0, sizeof(device_reference)); }; - mitm::InitializeProdInfoManagement(device_reference, sizeof(device_reference)); + mitm::SaveProdInfoBackupsAndWipeMemory(device_reference, sizeof(device_reference)); /* Backup BIS keys. */ { @@ -172,10 +175,17 @@ namespace ams::mitm { } - void StartInitialize() { - R_ABORT_UNLESS(os::CreateThread(std::addressof(g_initialize_thread), InitializeThreadFunc, nullptr, g_initialize_thread_stack, sizeof(g_initialize_thread_stack), AMS_GET_SYSTEM_THREAD_PRIORITY(mitm, InitializeThread))); - os::SetThreadNamePointer(std::addressof(g_initialize_thread), AMS_GET_SYSTEM_THREAD_NAME(mitm, InitializeThread)); - os::StartThread(std::addressof(g_initialize_thread)); + void EnsureProdInfoInitializedAndKickOffInit() { + std::scoped_lock lk(g_prodinfo_init_lock); + if (!g_initialized_prodinfo) { + mitm::InitializeProdInfoManagement(); + + R_ABORT_UNLESS(os::CreateThread(std::addressof(g_initialize_thread), InitializeThreadFunc, nullptr, g_initialize_thread_stack, sizeof(g_initialize_thread_stack), AMS_GET_SYSTEM_THREAD_PRIORITY(mitm, InitializeThread))); + os::SetThreadNamePointer(std::addressof(g_initialize_thread), AMS_GET_SYSTEM_THREAD_NAME(mitm, InitializeThread)); + os::StartThread(std::addressof(g_initialize_thread)); + + g_initialized_prodinfo = true; + } } bool IsInitialized() { diff --git a/stratosphere/ams_mitm/source/amsmitm_initialization.hpp b/stratosphere/ams_mitm/source/amsmitm_initialization.hpp index 1c6723a3b..3cec344d1 100644 --- a/stratosphere/ams_mitm/source/amsmitm_initialization.hpp +++ b/stratosphere/ams_mitm/source/amsmitm_initialization.hpp @@ -18,7 +18,8 @@ namespace ams::mitm { - void StartInitialize(); + void EnsureProdInfoInitializedAndKickOffInit(); + bool IsInitialized(); void WaitInitialized(); diff --git a/stratosphere/ams_mitm/source/amsmitm_main.cpp b/stratosphere/ams_mitm/source/amsmitm_main.cpp index 6f5994280..154166eb9 100644 --- a/stratosphere/ams_mitm/source/amsmitm_main.cpp +++ b/stratosphere/ams_mitm/source/amsmitm_main.cpp @@ -95,9 +95,6 @@ void __appExit(void) { } int main(int argc, char **argv) { - /* Start initialization (sd card init, automatic backups, etc) */ - mitm::StartInitialize(); - /* Launch all mitm modules in sequence. */ mitm::LaunchAllModules(); diff --git a/stratosphere/ams_mitm/source/amsmitm_prodinfo_utils.cpp b/stratosphere/ams_mitm/source/amsmitm_prodinfo_utils.cpp index 86f629605..0931110b9 100644 --- a/stratosphere/ams_mitm/source/amsmitm_prodinfo_utils.cpp +++ b/stratosphere/ams_mitm/source/amsmitm_prodinfo_utils.cpp @@ -79,7 +79,7 @@ namespace ams::mitm { }; static_assert(sizeof(CalibrationInfoHeader) == 0x40); - constexpr inline size_t CalibrationInfoBodySizeMax = 0x8000 - sizeof(CalibrationInfoHeader); + constexpr inline size_t CalibrationInfoBodySizeMax = CalibrationBinarySize - sizeof(CalibrationInfoHeader); struct CalibrationInfo { CalibrationInfoHeader header; @@ -101,14 +101,14 @@ namespace ams::mitm { return *static_cast(static_cast(std::addressof(this->body[Block::Offset - sizeof(this->header)]))); } }; - static_assert(sizeof(CalibrationInfo) == 0x8000); + static_assert(sizeof(CalibrationInfo) == CalibrationBinarySize); struct SecureCalibrationInfoBackup { CalibrationInfo info; Sha256Hash hash; - u8 pad[0xC000 - sizeof(info) - sizeof(hash)]; + u8 pad[SecureCalibrationBinaryBackupSize - sizeof(info) - sizeof(hash)]; }; - static_assert(sizeof(SecureCalibrationInfoBackup) == 0xC000); + static_assert(sizeof(SecureCalibrationInfoBackup) == SecureCalibrationBinaryBackupSize); bool IsValidSha256Hash(const Sha256Hash &hash, const void *data, size_t data_size) { Sha256Hash calc_hash; @@ -175,7 +175,7 @@ namespace ams::mitm { std::memcpy(block.serial_number.str, BlankSerialNumberString, sizeof(BlankSerialNumberString)); block.crc = GetCrc16(std::addressof(block), Block::Size - sizeof(block.crc)); } else if constexpr (std::is_same::value) { - std::memset(std::addressof(block), 0, Block::Size); + std::memset(std::addressof(block), 0, sizeof(block.ssl_certificate)); } else if constexpr (Block::IsCrcBlock) { std::memset(std::addressof(block), 0, Block::Size - sizeof(block.crc)); block.crc = GetCrc16(std::addressof(block), Block::Size - sizeof(block.crc)); @@ -186,27 +186,6 @@ namespace ams::mitm { } } - void Blank(CalibrationInfo &info) { - /* Set header. */ - info.header.magic = CalibrationMagic; - info.header.body_size = sizeof(info.body); - info.header.crc = GetCrc16(std::addressof(info.header), OFFSETOF(CalibrationInfoHeader, crc)); - - /* Set blocks. */ - Blank(info.GetBlock()); - Blank(info.GetBlock()); - Blank(info.GetBlock()); - Blank(info.GetBlock()); - Blank(info.GetBlock()); - Blank(info.GetBlock()); - Blank(info.GetBlock()); - Blank(info.GetBlock()); - Blank(info.GetBlock()); - - /* Set header hash. */ - crypto::GenerateSha256Hash(std::addressof(info.header.body_hash), sizeof(info.header.body_hash), std::addressof(info.body), sizeof(info.body)); - } - template bool IsBlank(const Block &block) { if constexpr (std::is_same::value) { @@ -229,6 +208,27 @@ namespace ams::mitm { } } + + void Blank(CalibrationInfo &info) { + /* Set header. */ + info.header.magic = CalibrationMagic; + info.header.body_size = sizeof(info.body); + info.header.crc = GetCrc16(std::addressof(info.header), OFFSETOF(CalibrationInfoHeader, crc)); + + /* Set blocks. */ + Blank(info.GetBlock()); + Blank(info.GetBlock()); + Blank(info.GetBlock()); + Blank(info.GetBlock()); + Blank(info.GetBlock()); + Blank(info.GetBlock()); + if (IsValid(info.GetBlock()) && !IsBlank(info.GetBlock())) Blank(info.GetBlock()); + if (IsValid(info.GetBlock()) && !IsBlank(info.GetBlock())) Blank(info.GetBlock()); + + /* Set header hash. */ + crypto::GenerateSha256Hash(std::addressof(info.header.body_hash), sizeof(info.header.body_hash), std::addressof(info.body), sizeof(info.body)); + } + bool IsValidHeader(const CalibrationInfo &cal) { return IsValid(cal.header) && cal.header.body_size <= CalibrationInfoBodySizeMax && IsValid(cal.header, cal.body); } @@ -256,25 +256,28 @@ namespace ams::mitm { } bool IsValid(const CalibrationInfo &cal) { - return IsValidHeader(cal) && - IsValid(cal.GetBlock()) && - IsValid(cal.GetBlock()) && - IsValid(cal.GetBlock()) && - IsValid(cal.GetBlock()) && - IsValid(cal.GetBlock()) && - IsValid(cal.GetBlock()) && - IsValid(cal.GetBlock()) && - IsValid(cal.GetBlock()) && + return IsValidHeader(cal) && + IsValid(cal.GetBlock()) && + IsValid(cal.GetBlock()) && + IsValid(cal.GetBlock()) && + IsValid(cal.GetBlock()) && + cal.GetBlock().ssl_certificate_size <= sizeof(cal.GetBlock().ssl_certificate) && + IsValid(cal.GetBlock(), cal.GetBlock().ssl_certificate_size) && + IsValid(cal.GetBlock()) && + IsValid(cal.GetBlock()) && + IsValid(cal.GetBlock()) && IsValidSerialNumber(cal); } bool ContainsCorrectDeviceId(const EccB233DeviceCertificateBlock &block, u64 device_id) { - static constexpr size_t DeviceIdOffset = 0xB4; - char expected_device_id[sizeof("NX0011223344556677")] = {}; - ON_SCOPE_EXIT { std::memset(expected_device_id, 0, sizeof(expected_device_id)); }; + static constexpr size_t DeviceIdOffset = 0xC6; + char found_device_id_str[sizeof("0011223344556677")] = {}; + ON_SCOPE_EXIT { std::memset(found_device_id_str, 0, sizeof(found_device_id_str)); }; + std::memcpy(found_device_id_str, std::addressof(block.device_certificate.data[DeviceIdOffset]), sizeof(found_device_id_str) - 1); - std::snprintf(expected_device_id, sizeof(expected_device_id), "NX%016lX", device_id); - return std::memcmp(expected_device_id, std::addressof(block.device_certificate.data[DeviceIdOffset]), sizeof(expected_device_id) - 1) == 0; + static constexpr u64 DeviceIdLowMask = 0x00FFFFFFFFFFFFFFul; + + return (std::strtoul(found_device_id_str, nullptr, 16) & DeviceIdLowMask) == (device_id & DeviceIdLowMask); } bool ContainsCorrectDeviceId(const CalibrationInfo &cal) { @@ -287,8 +290,6 @@ namespace ams::mitm { bool IsBlank(const CalibrationInfo &cal) { return IsBlank(cal.GetBlock()) || - IsBlank(cal.GetBlock()) || - IsBlank(cal.GetBlock()) || IsBlank(cal.GetBlock()) || IsBlank(cal.GetBlock()) || IsBlank(cal.GetBlock()) || @@ -304,8 +305,6 @@ namespace ams::mitm { R_ABORT_UNLESS(fsStorageRead(&calibration_binary_storage, 0, out, sizeof(*out))); } - constexpr inline s64 SecureCalibrationInfoBackupOffset = 3_MB; - constexpr inline const u8 SecureCalibrationBinaryBackupIv[crypto::Aes128CtrDecryptor::IvSize] = {}; void ReadStorageEncryptedSecureCalibrationBinaryBackupUnsafe(SecureCalibrationInfoBackup *out) { @@ -505,26 +504,32 @@ namespace ams::mitm { } alignas(os::MemoryPageSize) CalibrationInfo g_calibration_info = {}; + alignas(os::MemoryPageSize) CalibrationInfo g_blank_calibration_info = {}; alignas(os::MemoryPageSize) SecureCalibrationInfoBackup g_secure_calibration_info_backup = {}; - std::optional g_blank_prodinfo_file; std::optional g_prodinfo_backup_file; + std::optional g_blank_prodinfo_storage; std::optional g_fake_secure_backup_storage; + bool g_allow_writes = false; + bool g_has_secure_backup = false; + + os::Mutex g_prodinfo_management_lock(false); + } - void InitializeProdInfoManagement(char *out_name, size_t out_name_size) { + void InitializeProdInfoManagement() { + std::scoped_lock lk(g_prodinfo_management_lock); + /* First, get our options. */ const bool should_blank = exosphere::ShouldBlankProdInfo(); bool allow_writes = exosphere::ShouldAllowWritesToProdInfo(); /* Next, read our prodinfo. */ ReadStorageCalibrationBinary(std::addressof(g_calibration_info)); - ON_SCOPE_EXIT { FillWithGarbage(std::addressof(g_calibration_info), sizeof(g_calibration_info)); }; /* Next, check if we have a secure backup. */ bool has_secure_backup = ReadStorageSecureCalibrationBinaryBackup(std::addressof(g_secure_calibration_info_backup)); - ON_SCOPE_EXIT { FillWithGarbage(std::addressof(g_secure_calibration_info_backup), sizeof(g_secure_calibration_info_backup)); }; /* Only allow writes if we have a secure backup. */ if (allow_writes && !has_secure_backup) { @@ -543,8 +548,31 @@ namespace ams::mitm { /* Ensure our preconditions are met. */ AMS_ABORT_UNLESS(!allow_writes || has_secure_backup); + /* Set globals. */ + g_allow_writes = allow_writes; + g_has_secure_backup = has_secure_backup; + + /* If we should blank, do so. */ + if (should_blank) { + g_blank_calibration_info = g_calibration_info; + Blank(g_blank_calibration_info); + g_blank_prodinfo_storage.emplace(std::addressof(g_blank_calibration_info), sizeof(g_blank_calibration_info)); + } + + /* Ensure that we have a blank file only if we need one. */ + AMS_ABORT_UNLESS(should_blank == static_cast(g_blank_prodinfo_storage)); + } + + void SaveProdInfoBackupsAndWipeMemory(char *out_name, size_t out_name_size) { + std::scoped_lock lk(g_prodinfo_management_lock); + + ON_SCOPE_EXIT { + FillWithGarbage(std::addressof(g_calibration_info), sizeof(g_calibration_info)); + FillWithGarbage(std::addressof(g_secure_calibration_info_backup), sizeof(g_secure_calibration_info_backup)); + }; + /* Save our backup. We always prefer to save a secure copy of data over a non-secure one. */ - if (has_secure_backup) { + if (g_has_secure_backup) { GetSerialNumber(out_name, g_secure_calibration_info_backup.info); SaveProdInfoBackup(std::addressof(g_prodinfo_backup_file), g_secure_calibration_info_backup.info); } else { @@ -563,17 +591,49 @@ namespace ams::mitm { /* Ensure we made our backup. */ AMS_ABORT_UNLESS(g_prodinfo_backup_file); - /* If we should blank our prodinfo, do so. */ - if (should_blank) { - Blank(g_calibration_info); - SaveProdInfoBackup(std::addressof(g_blank_prodinfo_file), g_calibration_info); - } - - /* Ensure that we have a blank file if we need one. */ - AMS_ABORT_UNLESS(!should_blank || g_blank_prodinfo_file); - /* Setup our memory storage. */ g_fake_secure_backup_storage.emplace(std::addressof(g_secure_calibration_info_backup), sizeof(g_secure_calibration_info_backup)); + + /* Ensure that we have a fake storage. */ + AMS_ABORT_UNLESS(static_cast(g_fake_secure_backup_storage)); + } + + bool ShouldReadBlankCalibrationBinary() { + std::scoped_lock lk(g_prodinfo_management_lock); + return static_cast(g_blank_prodinfo_storage); + } + + bool IsWriteToCalibrationBinaryAllowed() { + std::scoped_lock lk(g_prodinfo_management_lock); + return g_allow_writes; + } + + void ReadFromBlankCalibrationBinary(s64 offset, void *dst, size_t size) { + AMS_ABORT_UNLESS(ShouldReadBlankCalibrationBinary()); + + std::scoped_lock lk(g_prodinfo_management_lock); + R_ABORT_UNLESS(g_blank_prodinfo_storage->Read(offset, dst, size)); + } + + void WriteToBlankCalibrationBinary(s64 offset, const void *src, size_t size) { + AMS_ABORT_UNLESS(ShouldReadBlankCalibrationBinary()); + + std::scoped_lock lk(g_prodinfo_management_lock); + R_ABORT_UNLESS(g_blank_prodinfo_storage->Write(offset, src, size)); + } + + void ReadFromFakeSecureBackupStorage(s64 offset, void *dst, size_t size) { + AMS_ABORT_UNLESS(IsWriteToCalibrationBinaryAllowed()); + + std::scoped_lock lk(g_prodinfo_management_lock); + R_ABORT_UNLESS(g_fake_secure_backup_storage->Read(offset, dst, size)); + } + + void WriteToFakeSecureBackupStorage(s64 offset, const void *src, size_t size) { + AMS_ABORT_UNLESS(IsWriteToCalibrationBinaryAllowed()); + + std::scoped_lock lk(g_prodinfo_management_lock); + R_ABORT_UNLESS(g_fake_secure_backup_storage->Write(offset, src, size)); } } diff --git a/stratosphere/ams_mitm/source/amsmitm_prodinfo_utils.hpp b/stratosphere/ams_mitm/source/amsmitm_prodinfo_utils.hpp index d37290601..eae748272 100644 --- a/stratosphere/ams_mitm/source/amsmitm_prodinfo_utils.hpp +++ b/stratosphere/ams_mitm/source/amsmitm_prodinfo_utils.hpp @@ -18,8 +18,22 @@ namespace ams::mitm { - void InitializeProdInfoManagement(char *out_name, size_t out_name_size); + constexpr inline size_t CalibrationBinarySize = 0x8000; + constexpr inline s64 SecureCalibrationInfoBackupOffset = 3_MB; + constexpr inline size_t SecureCalibrationBinaryBackupSize = 0xC000; + void InitializeProdInfoManagement(); + + void SaveProdInfoBackupsAndWipeMemory(char *out_name, size_t out_name_size); + + bool ShouldReadBlankCalibrationBinary(); + bool IsWriteToCalibrationBinaryAllowed(); + + void ReadFromBlankCalibrationBinary(s64 offset, void *dst, size_t size); + void WriteToBlankCalibrationBinary(s64 offset, const void *src, size_t size); + + void ReadFromFakeSecureBackupStorage(s64 offset, void *dst, size_t size); + void WriteToFakeSecureBackupStorage(s64 offset, const void *src, size_t size); } diff --git a/stratosphere/ams_mitm/source/fs_mitm/fs_mitm_service.cpp b/stratosphere/ams_mitm/source/fs_mitm/fs_mitm_service.cpp index 8c13c3f70..f897fb064 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fs_mitm_service.cpp +++ b/stratosphere/ams_mitm/source/fs_mitm/fs_mitm_service.cpp @@ -14,9 +14,11 @@ * along with this program. If not, see . */ #include "../amsmitm_fs_utils.hpp" +#include "../amsmitm_initialization.hpp" #include "fs_shim.h" #include "fs_mitm_service.hpp" #include "fsmitm_boot0storage.hpp" +#include "fsmitm_calibration_binary_storage.hpp" #include "fsmitm_layered_romfs_storage.hpp" #include "fsmitm_save_utils.hpp" #include "fsmitm_readonly_layered_filesystem.hpp" @@ -252,7 +254,6 @@ namespace ams::mitm::fs { const bool is_sysmodule = ncm::IsSystemProgramId(this->client_info.program_id); const bool is_hbl = this->client_info.override_status.IsHbl(); const bool can_write_bis = is_sysmodule || (is_hbl && GetSettingsItemBooleanValue("atmosphere", "enable_hbl_bis_write")); - const bool can_read_cal = is_sysmodule || (is_hbl && GetSettingsItemBooleanValue("atmosphere", "enable_hbl_cal_read")); /* Allow HBL to write to boot1 (safe firm) + package2. */ /* This is needed to not break compatibility with ChoiDujourNX, which does not check for write access before beginning an update. */ @@ -265,15 +266,8 @@ namespace ams::mitm::fs { if (bis_partition_id == FsBisPartitionId_BootPartition1Root) { out.SetValue(std::make_shared(new Boot0Storage(bis_storage, this->client_info)), target_object_id); } else if (bis_partition_id == FsBisPartitionId_CalibrationBinary) { - /* PRODINFO should *never* be writable. */ - /* If we have permissions, create a read only storage. */ - if (can_read_cal) { - out.SetValue(std::make_shared(new ReadOnlyStorageAdapter(new RemoteStorage(bis_storage))), target_object_id); - } else { - /* If we can't read cal, return permission denied. */ - fsStorageClose(&bis_storage); - return fs::ResultPermissionDenied(); - } + mitm::EnsureProdInfoInitializedAndKickOffInit(); + out.SetValue(std::make_shared(new CalibrationBinaryStorage(bis_storage, this->client_info)), target_object_id); } else { if (can_write_bis || can_write_bis_for_choi_support) { /* We can write, so create a writable storage. */ diff --git a/stratosphere/ams_mitm/source/fs_mitm/fs_mitm_service.hpp b/stratosphere/ams_mitm/source/fs_mitm/fs_mitm_service.hpp index 68749facb..6ac10a225 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fs_mitm_service.hpp +++ b/stratosphere/ams_mitm/source/fs_mitm/fs_mitm_service.hpp @@ -54,6 +54,11 @@ namespace ams::mitm::fs { return true; } + /* We want to mitm settings, to intercept CAL0. */ + if (program_id == ncm::SystemProgramId::Settings) { + return true; + } + /* We want to mitm sdb, to support sd-romfs redirection of common system archives (like system font, etc). */ if (program_id == ncm::SystemProgramId::Sdb) { return true; diff --git a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_calibration_binary_storage.cpp b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_calibration_binary_storage.cpp new file mode 100644 index 000000000..0f1bee112 --- /dev/null +++ b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_calibration_binary_storage.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2018-2020 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 "fsmitm_calibration_binary_storage.hpp" + +namespace ams::mitm::fs { + + using namespace ams::fs; + + namespace { + + os::Mutex g_cal0_access_mutex(false); + + } + Result CalibrationBinaryStorage::Read(s64 offset, void *_buffer, size_t size) { + /* Acquire exclusive calibration binary access. */ + std::scoped_lock lk(g_cal0_access_mutex); + + /* Get u8 buffer. */ + u8 *buffer = static_cast(_buffer); + + /* Succeed on zero-size. */ + R_SUCCEED_IF(size == 0); + + /* Handle the blank region. */ + if (this->read_blank) { + if (BlankStartOffset <= offset && offset < BlankEndOffset) { + const size_t blank_size = std::min(size, static_cast(BlankEndOffset - offset)); + mitm::ReadFromBlankCalibrationBinary(offset, buffer, blank_size); + size -= blank_size; + buffer += blank_size; + offset += blank_size; + } + } + + /* Succeed if we're done. */ + R_SUCCEED_IF(size == 0); + + /* Handle any in-between data. */ + if (BlankEndOffset <= offset && offset < FakeSecureStartOffset) { + const size_t mid_size = std::min(size, static_cast(FakeSecureStartOffset - offset)); + R_TRY(Base::Read(offset, buffer, mid_size)); + size -= mid_size; + buffer += mid_size; + offset += mid_size; + } + + /* Succeed if we're done. */ + R_SUCCEED_IF(size == 0); + + /* Handle the secure region. */ + if (FakeSecureStartOffset <= offset && offset < FakeSecureEndOffset) { + const size_t fake_size = std::min(size, static_cast(FakeSecureEndOffset - offset)); + mitm::ReadFromFakeSecureBackupStorage(offset, buffer, fake_size); + size -= fake_size; + buffer += fake_size; + offset += fake_size; + } + + /* Succeed if we're done. */ + R_SUCCEED_IF(size == 0); + + /* Handle any remaining data. */ + return Base::Read(offset, buffer, size); + } + + Result CalibrationBinaryStorage::Write(s64 offset, const void *_buffer, size_t size) { + /* Acquire exclusive calibration binary access. */ + std::scoped_lock lk(g_cal0_access_mutex); + + /* Get const u8 buffer. */ + const u8 *buffer = static_cast(_buffer); + + /* Succeed on zero-size. */ + R_SUCCEED_IF(size == 0); + + /* Only allow writes if we should. */ + R_UNLESS(this->allow_writes, fs::ResultUnsupportedOperation()); + + /* Handle the blank region. */ + if (this->read_blank) { + if (BlankStartOffset <= offset && offset < BlankEndOffset) { + const size_t blank_size = std::min(size, static_cast(BlankEndOffset - offset)); + mitm::WriteToBlankCalibrationBinary(offset, buffer, blank_size); + size -= blank_size; + buffer += blank_size; + offset += blank_size; + } + } + + /* Succeed if we're done. */ + R_SUCCEED_IF(size == 0); + + /* Handle any in-between data. */ + if (BlankEndOffset <= offset && offset < FakeSecureStartOffset) { + const size_t mid_size = std::min(size, static_cast(FakeSecureStartOffset - offset)); + R_TRY(Base::Write(offset, buffer, mid_size)); + size -= mid_size; + buffer += mid_size; + offset += mid_size; + } + + /* Succeed if we're done. */ + R_SUCCEED_IF(size == 0); + + /* Handle the secure region. */ + if (FakeSecureStartOffset <= offset && offset < FakeSecureEndOffset) { + const size_t fake_size = std::min(size, static_cast(FakeSecureEndOffset - offset)); + mitm::WriteToFakeSecureBackupStorage(offset, buffer, fake_size); + size -= fake_size; + buffer += fake_size; + offset += fake_size; + } + + /* Succeed if we're done. */ + R_SUCCEED_IF(size == 0); + + /* Handle any remaining data. */ + return Base::Write(offset, buffer, size); + } + +} diff --git a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_calibration_binary_storage.hpp b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_calibration_binary_storage.hpp new file mode 100644 index 000000000..215e159a7 --- /dev/null +++ b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_calibration_binary_storage.hpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2018-2020 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 "fsmitm_boot0storage.hpp" +#include "../amsmitm_prodinfo_utils.hpp" + +namespace ams::mitm::fs { + + /* Represents a protected calibration binary partition. */ + class CalibrationBinaryStorage : public SectoredStorageAdapter { + public: + using Base = SectoredStorageAdapter; + + static constexpr s64 BlankStartOffset = 0x0; + static constexpr s64 BlankSize = static_cast(CalibrationBinarySize); + static constexpr s64 BlankEndOffset = BlankStartOffset + BlankSize; + + static constexpr s64 FakeSecureStartOffset = SecureCalibrationInfoBackupOffset; + static constexpr s64 FakeSecureSize = static_cast(SecureCalibrationBinaryBackupSize); + static constexpr s64 FakeSecureEndOffset = FakeSecureStartOffset + FakeSecureSize; + private: + sm::MitmProcessInfo client_info; + bool read_blank; + bool allow_writes; + public: + CalibrationBinaryStorage(FsStorage &s, const sm::MitmProcessInfo &c) + : Base(s), client_info(c), + read_blank(mitm::ShouldReadBlankCalibrationBinary()), + allow_writes(mitm::IsWriteToCalibrationBinaryAllowed()) + { + /* ... */ + } + public: + virtual Result Read(s64 offset, void *_buffer, size_t size) override; + virtual Result Write(s64 offset, const void *_buffer, size_t size) override; + }; + +} diff --git a/stratosphere/ams_mitm/source/set_mitm/settings_sd_kvs.cpp b/stratosphere/ams_mitm/source/set_mitm/settings_sd_kvs.cpp index 7e211a945..d52e582d5 100644 --- a/stratosphere/ams_mitm/source/set_mitm/settings_sd_kvs.cpp +++ b/stratosphere/ams_mitm/source/set_mitm/settings_sd_kvs.cpp @@ -328,10 +328,6 @@ namespace ams::settings::fwdbg { /* This is probably undesirable for normal usage. */ R_ABORT_UNLESS(ParseSettingsItemValue("atmosphere", "enable_hbl_bis_write", "u8!0x0")); - /* Enable HBL to read the CAL0 partition. */ - /* This is probably undesirable for normal usage. */ - R_ABORT_UNLESS(ParseSettingsItemValue("atmosphere", "enable_hbl_cal_read", "u8!0x0")); - /* Controls whether dmnt cheats should be toggled on or off by */ /* default. 1 = toggled on by default, 0 = toggled off by default. */ R_ABORT_UNLESS(ParseSettingsItemValue("atmosphere", "dmnt_cheats_enabled_by_default", "u8!0x1"));