From 16c638756c19d7308a46666ad3a0b0fb9ac51b41 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Fri, 6 Dec 2019 03:00:38 -0800 Subject: [PATCH] ams_mitm: implement automatic backups of biskeys/cal0 --- .../ams_mitm/source/amsmitm_fs_utils.cpp | 40 +++-- .../ams_mitm/source/amsmitm_fs_utils.hpp | 4 + .../source/amsmitm_initialization.cpp | 153 +++++++++++++++++- .../include/stratosphere/fs/fs_filesystem.hpp | 1 + 4 files changed, 188 insertions(+), 10 deletions(-) diff --git a/stratosphere/ams_mitm/source/amsmitm_fs_utils.cpp b/stratosphere/ams_mitm/source/amsmitm_fs_utils.cpp index 369241707..73ce9d665 100644 --- a/stratosphere/ams_mitm/source/amsmitm_fs_utils.cpp +++ b/stratosphere/ams_mitm/source/amsmitm_fs_utils.cpp @@ -66,60 +66,82 @@ namespace ams::mitm::fs { R_ASSERT(fsOpenSdCardFileSystem(&g_sd_filesystem)); } + Result CreateSdFile(const char *path, s64 size, s32 option) { + R_TRY(EnsureSdInitialized()); + return fsFsCreateFile(&g_sd_filesystem, path, size, option); + } + + Result CreateAtmosphereSdFile(const char *path, s64 size, s32 option) { + char fixed_path[ams::fs::EntryNameLengthMax + 1]; + FormatAtmosphereSdPath(fixed_path, sizeof(fixed_path), path); + return CreateSdFile(fixed_path, size, option); + } + Result OpenSdFile(FsFile *out, const char *path, u32 mode) { R_TRY(EnsureSdInitialized()); return fsFsOpenFile(&g_sd_filesystem, path, mode, out); } Result OpenAtmosphereSdFile(FsFile *out, const char *path, u32 mode) { - char fixed_path[FS_MAX_PATH]; + char fixed_path[ams::fs::EntryNameLengthMax + 1]; FormatAtmosphereSdPath(fixed_path, sizeof(fixed_path), path); return OpenSdFile(out, fixed_path, mode); } Result OpenAtmosphereSdFile(FsFile *out, ncm::ProgramId program_id, const char *path, u32 mode) { - char fixed_path[FS_MAX_PATH]; + char fixed_path[ams::fs::EntryNameLengthMax + 1]; FormatAtmosphereSdPath(fixed_path, sizeof(fixed_path), program_id, path); return OpenSdFile(out, fixed_path, mode); } Result OpenAtmosphereSdRomfsFile(FsFile *out, ncm::ProgramId program_id, const char *path, u32 mode) { - char fixed_path[FS_MAX_PATH]; + char fixed_path[ams::fs::EntryNameLengthMax + 1]; FormatAtmosphereRomfsPath(fixed_path, sizeof(fixed_path), program_id, path); return OpenSdFile(out, fixed_path, mode); } Result OpenAtmosphereRomfsFile(FsFile *out, ncm::ProgramId program_id, const char *path, u32 mode, FsFileSystem *fs) { - char fixed_path[FS_MAX_PATH]; + char fixed_path[ams::fs::EntryNameLengthMax + 1]; FormatAtmosphereRomfsPath(fixed_path, sizeof(fixed_path), program_id, path); return fsFsOpenFile(fs, fixed_path, mode, out); } + Result CreateSdDirectory(const char *path) { + R_TRY(EnsureSdInitialized()); + return fsFsCreateDirectory(&g_sd_filesystem, path); + } + + Result CreateAtmosphereSdDirectory(const char *path) { + char fixed_path[ams::fs::EntryNameLengthMax + 1]; + FormatAtmosphereSdPath(fixed_path, sizeof(fixed_path), path); + return CreateSdDirectory(fixed_path); + } + Result OpenSdDirectory(FsDir *out, const char *path, u32 mode) { R_TRY(EnsureSdInitialized()); return fsFsOpenDirectory(&g_sd_filesystem, path, mode, out); } Result OpenAtmosphereSdDirectory(FsDir *out, const char *path, u32 mode) { - char fixed_path[FS_MAX_PATH]; + char fixed_path[ams::fs::EntryNameLengthMax + 1]; FormatAtmosphereSdPath(fixed_path, sizeof(fixed_path), path); return OpenSdDirectory(out, fixed_path, mode); } Result OpenAtmosphereSdDirectory(FsDir *out, ncm::ProgramId program_id, const char *path, u32 mode) { - char fixed_path[FS_MAX_PATH]; + char fixed_path[ams::fs::EntryNameLengthMax + 1]; FormatAtmosphereSdPath(fixed_path, sizeof(fixed_path), program_id, path); return OpenSdDirectory(out, fixed_path, mode); } Result OpenAtmosphereSdRomfsDirectory(FsDir *out, ncm::ProgramId program_id, const char *path, u32 mode) { - char fixed_path[FS_MAX_PATH]; + char fixed_path[ams::fs::EntryNameLengthMax + 1]; FormatAtmosphereRomfsPath(fixed_path, sizeof(fixed_path), program_id, path); return OpenSdDirectory(out, fixed_path, mode); } Result OpenAtmosphereRomfsDirectory(FsDir *out, ncm::ProgramId program_id, const char *path, u32 mode, FsFileSystem *fs) { - char fixed_path[FS_MAX_PATH]; + char fixed_path[ams::fs::EntryNameLengthMax + 1]; FormatAtmosphereRomfsPath(fixed_path, sizeof(fixed_path), program_id, path); return fsFsOpenDirectory(fs, fixed_path, mode, out); } @@ -150,7 +172,7 @@ namespace ams::mitm::fs { Result SaveAtmosphereSdFile(FsFile *out, ncm::ProgramId program_id, const char *path, void *data, size_t size) { R_TRY(EnsureSdInitialized()); - char fixed_path[FS_MAX_PATH]; + char fixed_path[ams::fs::EntryNameLengthMax + 1]; FormatAtmosphereSdPath(fixed_path, sizeof(fixed_path), program_id, path); /* Unconditionally create. */ diff --git a/stratosphere/ams_mitm/source/amsmitm_fs_utils.hpp b/stratosphere/ams_mitm/source/amsmitm_fs_utils.hpp index 26d9b4a1b..dcbd0b90c 100644 --- a/stratosphere/ams_mitm/source/amsmitm_fs_utils.hpp +++ b/stratosphere/ams_mitm/source/amsmitm_fs_utils.hpp @@ -22,12 +22,16 @@ namespace ams::mitm::fs { void OpenGlobalSdCardFileSystem(); /* Utilities. */ + Result CreateSdFile(const char *path, s64 size, s32 option); + Result CreateAtmosphereSdFile(const char *path, s64 size, s32 option); Result OpenSdFile(FsFile *out, const char *path, u32 mode); Result OpenAtmosphereSdFile(FsFile *out, const char *path, u32 mode); Result OpenAtmosphereSdFile(FsFile *out, ncm::ProgramId program_id, const char *path, u32 mode); Result OpenAtmosphereSdRomfsFile(FsFile *out, ncm::ProgramId program_id, const char *path, u32 mode); Result OpenAtmosphereRomfsFile(FsFile *out, ncm::ProgramId program_id, const char *path, u32 mode, FsFileSystem *fs); + Result CreateSdDirectory(const char *path); + Result CreateAtmosphereSdDirectory(const char *path); Result OpenSdDirectory(FsDir *out, const char *path, u32 mode); Result OpenAtmosphereSdDirectory(FsDir *out, const char *path, u32 mode); Result OpenAtmosphereSdDirectory(FsDir *out, ncm::ProgramId program_id, const char *path, u32 mode); diff --git a/stratosphere/ams_mitm/source/amsmitm_initialization.cpp b/stratosphere/ams_mitm/source/amsmitm_initialization.cpp index fe3e2a80b..0ee9aaeb6 100644 --- a/stratosphere/ams_mitm/source/amsmitm_initialization.cpp +++ b/stratosphere/ams_mitm/source/amsmitm_initialization.cpp @@ -22,6 +22,30 @@ namespace ams::mitm { namespace { + /* BIS key sources. */ + constexpr u8 BisKeySources[4][2][0x10] = { + { + {0xF8, 0x3F, 0x38, 0x6E, 0x2C, 0xD2, 0xCA, 0x32, 0xA8, 0x9A, 0xB9, 0xAA, 0x29, 0xBF, 0xC7, 0x48}, + {0x7D, 0x92, 0xB0, 0x3A, 0xA8, 0xBF, 0xDE, 0xE1, 0xA7, 0x4C, 0x3B, 0x6E, 0x35, 0xCB, 0x71, 0x06} + }, + { + {0x41, 0x00, 0x30, 0x49, 0xDD, 0xCC, 0xC0, 0x65, 0x64, 0x7A, 0x7E, 0xB4, 0x1E, 0xED, 0x9C, 0x5F}, + {0x44, 0x42, 0x4E, 0xDA, 0xB4, 0x9D, 0xFC, 0xD9, 0x87, 0x77, 0x24, 0x9A, 0xDC, 0x9F, 0x7C, 0xA4} + }, + { + {0x52, 0xC2, 0xE9, 0xEB, 0x09, 0xE3, 0xEE, 0x29, 0x32, 0xA1, 0x0C, 0x1F, 0xB6, 0xA0, 0x92, 0x6C}, + {0x4D, 0x12, 0xE1, 0x4B, 0x2A, 0x47, 0x4C, 0x1C, 0x09, 0xCB, 0x03, 0x59, 0xF0, 0x15, 0xF4, 0xE4} + }, + { + {0x52, 0xC2, 0xE9, 0xEB, 0x09, 0xE3, 0xEE, 0x29, 0x32, 0xA1, 0x0C, 0x1F, 0xB6, 0xA0, 0x92, 0x6C}, + {0x4D, 0x12, 0xE1, 0x4B, 0x2A, 0x47, 0x4C, 0x1C, 0x09, 0xCB, 0x03, 0x59, 0xF0, 0x15, 0xF4, 0xE4} + } + }; + + constexpr u8 BisKekSource[0x10] = { + 0x34, 0xC1, 0xA0, 0xC4, 0x82, 0x58, 0xF8, 0xB4, 0xFA, 0x9E, 0x5E, 0x6A, 0xDA, 0xFC, 0x7E, 0x4F, + }; + void InitializeThreadFunc(void *arg); constexpr size_t InitializeThreadStackSize = 0x4000; @@ -31,6 +55,118 @@ namespace ams::mitm { /* Globals. */ os::Event g_init_event(false); + /* Console-unique data backup and protection. */ + constexpr size_t CalibrationBinarySize = 0x8000; + u8 g_calibration_binary_storage_backup[CalibrationBinarySize]; + u8 g_calibration_binary_file_backup[CalibrationBinarySize]; + FsFile g_calibration_binary_file; + FsFile g_bis_key_file; + + /* Emummc file protection. */ + FsFile g_emummc_file; + + void GetBackupFileName(char *dst, size_t dst_size, const char *serial_number, const char *fn) { + if (strlen(serial_number) > 0) { + std::snprintf(dst, dst_size, "automatic_backups/%s_%s", serial_number, fn); + } else { + std::snprintf(dst, dst_size, "automatic_backups/%s", fn); + } + } + + void CreateAutomaticBackups() { + /* Create a backup directory, if one doesn't exist. */ + mitm::fs::CreateAtmosphereSdDirectory("/automatic_backups"); + + /* Read the calibration binary. */ + { + FsStorage calibration_binary_storage; + R_ASSERT(fsOpenBisStorage(&calibration_binary_storage, FsBisPartitionId_CalibrationBinary)); + ON_SCOPE_EXIT { fsStorageClose(&calibration_binary_storage); }; + + R_ASSERT(fsStorageRead(&calibration_binary_storage, 0, g_calibration_binary_storage_backup, CalibrationBinarySize)); + } + + /* Copy serial number from partition. */ + /* TODO: Define the magic numbers? Structs? */ + char serial_number[0x40] = {}; + std::memcpy(serial_number, g_calibration_binary_storage_backup + 0x250, 0x18); + + /* Backup the calibration binary. */ + { + char calibration_binary_backup_name[ams::fs::EntryNameLengthMax + 1]; + GetBackupFileName(calibration_binary_backup_name, sizeof(calibration_binary_backup_name), serial_number, "PRODINFO.bin"); + + mitm::fs::CreateAtmosphereSdFile(calibration_binary_backup_name, CalibrationBinarySize, ams::fs::CreateOption_None); + R_ASSERT(mitm::fs::OpenAtmosphereSdFile(&g_calibration_binary_file, calibration_binary_backup_name, ams::fs::OpenMode_ReadWrite)); + + s64 file_size = 0; + R_ASSERT(fsFileGetSize(&g_calibration_binary_file, &file_size)); + + bool is_file_backup_valid = file_size == CalibrationBinarySize; + if (is_file_backup_valid) { + u64 read_size = 0; + R_ASSERT(fsFileRead(&g_calibration_binary_file, 0, g_calibration_binary_file_backup, CalibrationBinarySize, FsReadOption_None, &read_size)); + AMS_ASSERT(read_size == CalibrationBinarySize); + is_file_backup_valid &= std::memcmp(g_calibration_binary_file_backup, "CAL0", 4) == 0; + is_file_backup_valid &= std::memcmp(g_calibration_binary_file_backup + 0x250, serial_number, 0x18) == 0; + const u32 cal_bin_size = *reinterpret_cast(g_calibration_binary_file_backup + 0x8); + is_file_backup_valid &= cal_bin_size + 0x40 <= CalibrationBinarySize; + if (is_file_backup_valid) { + u8 calc_hash[SHA256_HASH_SIZE]; + /* TODO: ams::crypto? */ + sha256CalculateHash(calc_hash, g_calibration_binary_file_backup + 0x40, cal_bin_size); + is_file_backup_valid &= std::memcmp(calc_hash, g_calibration_binary_file_backup + 0x20, sizeof(calc_hash)) == 0; + } + } + + if (!is_file_backup_valid) { + R_ASSERT(fsFileSetSize(&g_calibration_binary_file, CalibrationBinarySize)); + R_ASSERT(fsFileWrite(&g_calibration_binary_file, 0, g_calibration_binary_storage_backup, CalibrationBinarySize, FsWriteOption_Flush)); + } + + /* Note: g_calibration_binary_file is intentionally not closed here. This prevents any other process from opening it. */ + std::memset(g_calibration_binary_file_backup, 0, CalibrationBinarySize); + std::memset(g_calibration_binary_storage_backup, 0, CalibrationBinarySize); + } + + /* Backup BIS keys. */ + { + u64 key_generation = 0; + if (hos::GetVersion() >= hos::Version_500) { + R_ASSERT(splGetConfig(SplConfigItem_NewKeyGeneration, &key_generation)); + } + + u8 bis_keys[4][2][0x10]; + std::memset(bis_keys, 0xCC, sizeof(bis_keys)); + + /* TODO: Clean this up. */ + for (size_t partition = 0; partition < 4; partition++) { + if (partition == 0) { + for (size_t i = 0; i < 2; i++) { + R_ASSERT(splFsGenerateSpecificAesKey(BisKeySources[partition][i], key_generation, i, bis_keys[partition][i])); + } + } else { + const u32 option = (partition == 3 && spl::IsRecoveryBoot()) ? 0x4 : 0x1; + + u8 access_key[0x10]; + R_ASSERT(splCryptoGenerateAesKek(BisKekSource, key_generation, option, access_key)); + for (size_t i = 0; i < 2; i++) { + R_ASSERT(splCryptoGenerateAesKey(access_key, BisKeySources[partition][i], bis_keys[partition][i])); + } + } + } + + char bis_keys_backup_name[ams::fs::EntryNameLengthMax + 1]; + GetBackupFileName(bis_keys_backup_name, sizeof(bis_keys_backup_name), serial_number, "BISKEYS.bin"); + + mitm::fs::CreateAtmosphereSdFile(bis_keys_backup_name, sizeof(bis_keys), ams::fs::CreateOption_None); + R_ASSERT(mitm::fs::OpenAtmosphereSdFile(&g_bis_key_file, bis_keys_backup_name, ams::fs::OpenMode_ReadWrite)); + R_ASSERT(fsFileSetSize(&g_bis_key_file, sizeof(bis_keys))); + R_ASSERT(fsFileWrite(&g_bis_key_file, 0, bis_keys, sizeof(bis_keys), FsWriteOption_Flush)); + /* NOTE: g_bis_key_file is intentionally not closed here. This prevents any other process from opening it. */ + } + } + /* Initialization implementation */ void InitializeThreadFunc(void *arg) { /* Wait for the SD card to be ready. */ @@ -43,7 +179,22 @@ namespace ams::mitm { /* Discard result, since it doesn't need to succeed. */ mitm::bpc::LoadRebootPayload(); - /* TODO: Other initialization tasks. */ + /* Backup Calibration Binary and BIS keys. */ + CreateAutomaticBackups(); + + /* If we're emummc, persist a write-handle to prevent other processes from touching the image. */ + if (emummc::IsActive()) { + if (const char *emummc_file_path = emummc::GetFilePath(); emummc_file_path != nullptr) { + char emummc_path[ams::fs::EntryNameLengthMax + 1]; + std::snprintf(emummc_path, sizeof(emummc_path), "%s/eMMC", emummc_file_path); + mitm::fs::OpenSdFile(&g_emummc_file, emummc_path, ams::fs::OpenMode_Read); + } + } + + /* Connect to set:sys. */ + sm::DoWithSession([]() { + R_ASSERT(setsysInitialize()); + }); /* Signal to waiters that we are ready. */ g_init_event.Signal(); diff --git a/stratosphere/libstratosphere/include/stratosphere/fs/fs_filesystem.hpp b/stratosphere/libstratosphere/include/stratosphere/fs/fs_filesystem.hpp index 86581f3d3..e905d3743 100644 --- a/stratosphere/libstratosphere/include/stratosphere/fs/fs_filesystem.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/fs/fs_filesystem.hpp @@ -43,6 +43,7 @@ namespace ams::fs { }; enum CreateOption { + CreateOption_None = 0, CreateOption_BigFile = ::FsCreateOption_BigFile, };