libs: add ongoing work to facilitate hactool rewrite

This commit is contained in:
Michael Scire
2022-03-08 10:05:32 -08:00
parent a4895a1e79
commit 100bead52b
34 changed files with 1829 additions and 216 deletions

View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#include "../spl/impl/spl_ctr_drbg.hpp"
#include <sys/random.h>
namespace ams::crypto {
namespace {
using Drbg = ::ams::spl::impl::CtrDrbg<crypto::AesEncryptor128, crypto::AesEncryptor128::KeySize, false>;
constinit util::TypedStorage<Drbg> g_drbg = {};
bool InitializeCsrng() {
u8 seed[Drbg::SeedSize];
AMS_ABORT_UNLESS(::getentropy(seed, sizeof(seed)) == 0);
util::ConstructAt(g_drbg);
util::GetReference(g_drbg).Initialize(seed, sizeof(seed), nullptr, 0, nullptr, 0);
return true;
}
}
void GenerateCryptographicallyRandomBytes(void *dst, size_t dst_size) {
AMS_FUNCTION_LOCAL_STATIC(bool, s_initialized, InitializeCsrng());
AMS_ABORT_UNLESS(s_initialized);
AMS_ASSERT(dst_size <= Drbg::RequestSizeMax);
if (!util::GetReference(g_drbg).Generate(dst, dst_size, nullptr, 0)) {
/* Reseed, if needed. */
{
u8 seed[Drbg::SeedSize];
AMS_ABORT_UNLESS(::getentropy(seed, sizeof(seed)) == 0);
util::GetReference(g_drbg).Reseed(seed, sizeof(seed), nullptr, 0);
}
util::GetReference(g_drbg).Generate(dst, dst_size, nullptr, 0);
}
}
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#include <ntstatus.h>
#include <bcrypt.h>
namespace ams::crypto {
void GenerateCryptographicallyRandomBytes(void *dst, size_t dst_size) {
const auto status = ::BCryptGenRandom(nullptr, static_cast<PUCHAR>(dst), dst_size, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
AMS_ABORT_UNLESS(status == STATUS_SUCCESS);
}
}

View File

@@ -84,6 +84,8 @@ namespace ams::fs {
namespace ams::fs::impl {
#define ADD_ENUM_CASE(v) case v: return #v
const char *IdString::ToValueString(int id) {
const int len = util::SNPrintf(m_buffer, sizeof(m_buffer), "%d", id);
AMS_ASSERT(static_cast<size_t>(len) < sizeof(m_buffer));
@@ -112,20 +114,22 @@ namespace ams::fs::impl {
template<> const char *IdString::ToString<fs::ContentStorageId>(fs::ContentStorageId id) {
switch (id) {
case fs::ContentStorageId::User: return "User";
case fs::ContentStorageId::System: return "System";
case fs::ContentStorageId::SdCard: return "SdCard";
default: return ToValueString(static_cast<int>(id));
using enum fs::ContentStorageId;
ADD_ENUM_CASE(User);
ADD_ENUM_CASE(System);
ADD_ENUM_CASE(SdCard);
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<fs::SaveDataSpaceId>(fs::SaveDataSpaceId id) {
switch (id) {
case fs::SaveDataSpaceId::System: return "System";
case fs::SaveDataSpaceId::User: return "User";
case fs::SaveDataSpaceId::SdSystem: return "SdSystem";
case fs::SaveDataSpaceId::ProperSystem: return "ProperSystem";
default: return ToValueString(static_cast<int>(id));
using enum fs::SaveDataSpaceId;
ADD_ENUM_CASE(System);
ADD_ENUM_CASE(User);
ADD_ENUM_CASE(SdSystem);
ADD_ENUM_CASE(ProperSystem);
default: return ToValueString(static_cast<int>(id));
}
}
@@ -142,23 +146,24 @@ namespace ams::fs::impl {
template<> const char *IdString::ToString<fs::BisPartitionId>(fs::BisPartitionId id) {
switch (id) {
case fs::BisPartitionId::BootPartition1Root: return "BootPartition1Root";
case fs::BisPartitionId::BootPartition2Root: return "BootPartition2Root";
case fs::BisPartitionId::UserDataRoot: return "UserDataRoot";
case fs::BisPartitionId::BootConfigAndPackage2Part1: return "BootConfigAndPackage2Part1";
case fs::BisPartitionId::BootConfigAndPackage2Part2: return "BootConfigAndPackage2Part2";
case fs::BisPartitionId::BootConfigAndPackage2Part3: return "BootConfigAndPackage2Part3";
case fs::BisPartitionId::BootConfigAndPackage2Part4: return "BootConfigAndPackage2Part4";
case fs::BisPartitionId::BootConfigAndPackage2Part5: return "BootConfigAndPackage2Part5";
case fs::BisPartitionId::BootConfigAndPackage2Part6: return "BootConfigAndPackage2Part6";
case fs::BisPartitionId::CalibrationBinary: return "CalibrationBinary";
case fs::BisPartitionId::CalibrationFile: return "CalibrationFile";
case fs::BisPartitionId::SafeMode: return "SafeMode";
case fs::BisPartitionId::User: return "User";
case fs::BisPartitionId::System: return "System";
case fs::BisPartitionId::SystemProperEncryption: return "SystemProperEncryption";
case fs::BisPartitionId::SystemProperPartition: return "SystemProperPartition";
default: return ToValueString(static_cast<int>(id));
using enum fs::BisPartitionId;
ADD_ENUM_CASE(BootPartition1Root);
ADD_ENUM_CASE(BootPartition2Root);
ADD_ENUM_CASE(UserDataRoot);
ADD_ENUM_CASE(BootConfigAndPackage2Part1);
ADD_ENUM_CASE(BootConfigAndPackage2Part2);
ADD_ENUM_CASE(BootConfigAndPackage2Part3);
ADD_ENUM_CASE(BootConfigAndPackage2Part4);
ADD_ENUM_CASE(BootConfigAndPackage2Part5);
ADD_ENUM_CASE(BootConfigAndPackage2Part6);
ADD_ENUM_CASE(CalibrationBinary);
ADD_ENUM_CASE(CalibrationFile);
ADD_ENUM_CASE(SafeMode);
ADD_ENUM_CASE(User);
ADD_ENUM_CASE(System);
ADD_ENUM_CASE(SystemProperEncryption);
ADD_ENUM_CASE(SystemProperPartition);
default: return ToValueString(static_cast<int>(id));
}
}
@@ -172,10 +177,267 @@ namespace ams::fs::impl {
template<> const char *IdString::ToString<fs::GameCardPartition>(fs::GameCardPartition id) {
switch (id) {
case fs::GameCardPartition::Update: return "Update";
case fs::GameCardPartition::Normal: return "Normal";
case fs::GameCardPartition::Secure: return "Secure";
default: return ToValueString(static_cast<int>(id));
using enum fs::GameCardPartition;
ADD_ENUM_CASE(Update);
ADD_ENUM_CASE(Normal);
ADD_ENUM_CASE(Secure);
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<fssystem::NcaHeader::ContentType>(fssystem::NcaHeader::ContentType id) {
switch (id) {
using enum fssystem::NcaHeader::ContentType;
ADD_ENUM_CASE(Program);
ADD_ENUM_CASE(Meta);
ADD_ENUM_CASE(Control);
ADD_ENUM_CASE(Manual);
ADD_ENUM_CASE(Data);
ADD_ENUM_CASE(PublicData);
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<fssystem::NcaHeader::DistributionType>(fssystem::NcaHeader::DistributionType id) {
switch (id) {
using enum fssystem::NcaHeader::DistributionType;
ADD_ENUM_CASE(Download);
ADD_ENUM_CASE(GameCard);
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<fssystem::NcaHeader::EncryptionType>(fssystem::NcaHeader::EncryptionType id) {
switch (id) {
using enum fssystem::NcaHeader::EncryptionType;
ADD_ENUM_CASE(Auto);
ADD_ENUM_CASE(None);
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<fssystem::NcaHeader::DecryptionKey>(fssystem::NcaHeader::DecryptionKey id) {
switch (id) {
using enum fssystem::NcaHeader::DecryptionKey;
case DecryptionKey_AesXts1: return "AesXts1";
case DecryptionKey_AesXts2: return "AesXts2";
case DecryptionKey_AesCtr: return "AesCtr";
case DecryptionKey_AesCtrEx: return "AesCtrEx";
case DecryptionKey_AesCtrHw: return "AesCtrHw";
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<fssystem::NcaFsHeader::FsType>(fssystem::NcaFsHeader::FsType id) {
switch (id) {
using enum fssystem::NcaFsHeader::FsType;
ADD_ENUM_CASE(RomFs);
ADD_ENUM_CASE(PartitionFs);
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<fssystem::NcaFsHeader::EncryptionType>(fssystem::NcaFsHeader::EncryptionType id) {
switch (id) {
using enum fssystem::NcaFsHeader::EncryptionType;
ADD_ENUM_CASE(Auto);
ADD_ENUM_CASE(None);
ADD_ENUM_CASE(AesXts);
ADD_ENUM_CASE(AesCtr);
ADD_ENUM_CASE(AesCtrEx);
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<fssystem::NcaFsHeader::HashType>(fssystem::NcaFsHeader::HashType id) {
switch (id) {
using enum fssystem::NcaFsHeader::HashType;
ADD_ENUM_CASE(Auto);
ADD_ENUM_CASE(None);
ADD_ENUM_CASE(HierarchicalSha256Hash);
ADD_ENUM_CASE(HierarchicalIntegrityHash);
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<fssrv::impl::AccessControlBits::Bits>(fssrv::impl::AccessControlBits::Bits id) {
switch (id) {
using enum fssrv::impl::AccessControlBits::Bits;
ADD_ENUM_CASE(ApplicationInfo);
ADD_ENUM_CASE(BootModeControl);
ADD_ENUM_CASE(Calibration);
ADD_ENUM_CASE(SystemSaveData);
ADD_ENUM_CASE(GameCard);
ADD_ENUM_CASE(SaveDataBackUp);
ADD_ENUM_CASE(SaveDataManagement);
ADD_ENUM_CASE(BisAllRaw);
ADD_ENUM_CASE(GameCardRaw);
ADD_ENUM_CASE(GameCardPrivate);
ADD_ENUM_CASE(SetTime);
ADD_ENUM_CASE(ContentManager);
ADD_ENUM_CASE(ImageManager);
ADD_ENUM_CASE(CreateSaveData);
ADD_ENUM_CASE(SystemSaveDataManagement);
ADD_ENUM_CASE(BisFileSystem);
ADD_ENUM_CASE(SystemUpdate);
ADD_ENUM_CASE(SaveDataMeta);
ADD_ENUM_CASE(DeviceSaveData);
ADD_ENUM_CASE(SettingsControl);
ADD_ENUM_CASE(SystemData);
ADD_ENUM_CASE(SdCard);
ADD_ENUM_CASE(Host);
ADD_ENUM_CASE(FillBis);
ADD_ENUM_CASE(CorruptSaveData);
ADD_ENUM_CASE(SaveDataForDebug);
ADD_ENUM_CASE(FormatSdCard);
ADD_ENUM_CASE(GetRightsId);
ADD_ENUM_CASE(RegisterExternalKey);
ADD_ENUM_CASE(RegisterUpdatePartition);
ADD_ENUM_CASE(SaveDataTransfer);
ADD_ENUM_CASE(DeviceDetection);
ADD_ENUM_CASE(AccessFailureResolution);
ADD_ENUM_CASE(SaveDataTransferVersion2);
ADD_ENUM_CASE(RegisterProgramIndexMapInfo);
ADD_ENUM_CASE(CreateOwnSaveData);
ADD_ENUM_CASE(MoveCacheStorage);
ADD_ENUM_CASE(Debug);
ADD_ENUM_CASE(FullPermission);
default: return ToValueString(util::CountTrailingZeros(util::ToUnderlying(id)));
}
}
template<> const char *IdString::ToString<fssrv::impl::AccessControl::AccessibilityType>(fssrv::impl::AccessControl::AccessibilityType id) {
switch (id) {
using enum fssrv::impl::AccessControl::AccessibilityType;
ADD_ENUM_CASE(MountLogo);
ADD_ENUM_CASE(MountContentMeta);
ADD_ENUM_CASE(MountContentControl);
ADD_ENUM_CASE(MountContentManual);
ADD_ENUM_CASE(MountContentData);
ADD_ENUM_CASE(MountApplicationPackage);
ADD_ENUM_CASE(MountSaveDataStorage);
ADD_ENUM_CASE(MountContentStorage);
ADD_ENUM_CASE(MountImageAndVideoStorage);
ADD_ENUM_CASE(MountCloudBackupWorkStorage);
ADD_ENUM_CASE(MountCustomStorage);
ADD_ENUM_CASE(MountBisCalibrationFile);
ADD_ENUM_CASE(MountBisSafeMode);
ADD_ENUM_CASE(MountBisUser);
ADD_ENUM_CASE(MountBisSystem);
ADD_ENUM_CASE(MountBisSystemProperEncryption);
ADD_ENUM_CASE(MountBisSystemProperPartition);
ADD_ENUM_CASE(MountSdCard);
ADD_ENUM_CASE(MountGameCard);
ADD_ENUM_CASE(MountDeviceSaveData);
ADD_ENUM_CASE(MountSystemSaveData);
ADD_ENUM_CASE(MountOthersSaveData);
ADD_ENUM_CASE(MountOthersSystemSaveData);
ADD_ENUM_CASE(OpenBisPartitionBootPartition1Root);
ADD_ENUM_CASE(OpenBisPartitionBootPartition2Root);
ADD_ENUM_CASE(OpenBisPartitionUserDataRoot);
ADD_ENUM_CASE(OpenBisPartitionBootConfigAndPackage2Part1);
ADD_ENUM_CASE(OpenBisPartitionBootConfigAndPackage2Part2);
ADD_ENUM_CASE(OpenBisPartitionBootConfigAndPackage2Part3);
ADD_ENUM_CASE(OpenBisPartitionBootConfigAndPackage2Part4);
ADD_ENUM_CASE(OpenBisPartitionBootConfigAndPackage2Part5);
ADD_ENUM_CASE(OpenBisPartitionBootConfigAndPackage2Part6);
ADD_ENUM_CASE(OpenBisPartitionCalibrationBinary);
ADD_ENUM_CASE(OpenBisPartitionCalibrationFile);
ADD_ENUM_CASE(OpenBisPartitionSafeMode);
ADD_ENUM_CASE(OpenBisPartitionUser);
ADD_ENUM_CASE(OpenBisPartitionSystem);
ADD_ENUM_CASE(OpenBisPartitionSystemProperEncryption);
ADD_ENUM_CASE(OpenBisPartitionSystemProperPartition);
ADD_ENUM_CASE(OpenSdCardStorage);
ADD_ENUM_CASE(OpenGameCardStorage);
ADD_ENUM_CASE(MountSystemDataPrivate);
ADD_ENUM_CASE(MountHost);
ADD_ENUM_CASE(MountRegisteredUpdatePartition);
ADD_ENUM_CASE(MountSaveDataInternalStorage);
ADD_ENUM_CASE(MountTemporaryDirectory);
ADD_ENUM_CASE(MountAllBaseFileSystem);
ADD_ENUM_CASE(NotMount);
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<fssrv::impl::AccessControl::OperationType>(fssrv::impl::AccessControl::OperationType id) {
switch (id) {
using enum fssrv::impl::AccessControl::OperationType;
ADD_ENUM_CASE(InvalidateBisCache);
ADD_ENUM_CASE(EraseMmc);
ADD_ENUM_CASE(GetGameCardDeviceCertificate);
ADD_ENUM_CASE(GetGameCardIdSet);
ADD_ENUM_CASE(FinalizeGameCardDriver);
ADD_ENUM_CASE(GetGameCardAsicInfo);
ADD_ENUM_CASE(CreateSaveData);
ADD_ENUM_CASE(DeleteSaveData);
ADD_ENUM_CASE(CreateSystemSaveData);
ADD_ENUM_CASE(CreateOthersSystemSaveData);
ADD_ENUM_CASE(DeleteSystemSaveData);
ADD_ENUM_CASE(OpenSaveDataInfoReader);
ADD_ENUM_CASE(OpenSaveDataInfoReaderForSystem);
ADD_ENUM_CASE(OpenSaveDataInfoReaderForInternal);
ADD_ENUM_CASE(OpenSaveDataMetaFile);
ADD_ENUM_CASE(SetCurrentPosixTime);
ADD_ENUM_CASE(ReadSaveDataFileSystemExtraData);
ADD_ENUM_CASE(SetGlobalAccessLogMode);
ADD_ENUM_CASE(SetSpeedEmulationMode);
ADD_ENUM_CASE(Debug);
ADD_ENUM_CASE(FillBis);
ADD_ENUM_CASE(CorruptSaveData);
ADD_ENUM_CASE(CorruptSystemSaveData);
ADD_ENUM_CASE(VerifySaveData);
ADD_ENUM_CASE(DebugSaveData);
ADD_ENUM_CASE(FormatSdCard);
ADD_ENUM_CASE(GetRightsId);
ADD_ENUM_CASE(RegisterExternalKey);
ADD_ENUM_CASE(SetEncryptionSeed);
ADD_ENUM_CASE(WriteSaveDataFileSystemExtraDataTimeStamp);
ADD_ENUM_CASE(WriteSaveDataFileSystemExtraDataFlags);
ADD_ENUM_CASE(WriteSaveDataFileSystemExtraDataCommitId);
ADD_ENUM_CASE(WriteSaveDataFileSystemExtraDataAll);
ADD_ENUM_CASE(ExtendSaveData);
ADD_ENUM_CASE(ExtendSystemSaveData);
ADD_ENUM_CASE(ExtendOthersSystemSaveData);
ADD_ENUM_CASE(RegisterUpdatePartition);
ADD_ENUM_CASE(OpenSaveDataTransferManager);
ADD_ENUM_CASE(OpenSaveDataTransferManagerVersion2);
ADD_ENUM_CASE(OpenSaveDataTransferManagerForSaveDataRepair);
ADD_ENUM_CASE(OpenSaveDataTransferManagerForSaveDataRepairTool);
ADD_ENUM_CASE(OpenSaveDataTransferProhibiter);
ADD_ENUM_CASE(OpenSaveDataMover);
ADD_ENUM_CASE(OpenBisWiper);
ADD_ENUM_CASE(ListAccessibleSaveDataOwnerId);
ADD_ENUM_CASE(ControlMmcPatrol);
ADD_ENUM_CASE(OverrideSaveDataTransferTokenSignVerificationKey);
ADD_ENUM_CASE(OpenSdCardDetectionEventNotifier);
ADD_ENUM_CASE(OpenGameCardDetectionEventNotifier);
ADD_ENUM_CASE(OpenSystemDataUpdateEventNotifier);
ADD_ENUM_CASE(NotifySystemDataUpdateEvent);
ADD_ENUM_CASE(OpenAccessFailureDetectionEventNotifier);
ADD_ENUM_CASE(GetAccessFailureDetectionEvent);
ADD_ENUM_CASE(IsAccessFailureDetected);
ADD_ENUM_CASE(ResolveAccessFailure);
ADD_ENUM_CASE(AbandonAccessFailure);
ADD_ENUM_CASE(QuerySaveDataInternalStorageTotalSize);
ADD_ENUM_CASE(GetSaveDataCommitId);
ADD_ENUM_CASE(SetSdCardAccessibility);
ADD_ENUM_CASE(SimulateDevice);
ADD_ENUM_CASE(CreateSaveDataWithHashSalt);
ADD_ENUM_CASE(RegisterProgramIndexMapInfo);
ADD_ENUM_CASE(ChallengeCardExistence);
ADD_ENUM_CASE(CreateOwnSaveData);
ADD_ENUM_CASE(DeleteOwnSaveData);
ADD_ENUM_CASE(ReadOwnSaveDataFileSystemExtraData);
ADD_ENUM_CASE(ExtendOwnSaveData);
ADD_ENUM_CASE(OpenOwnSaveDataTransferProhibiter);
ADD_ENUM_CASE(FindOwnSaveDataWithFilter);
ADD_ENUM_CASE(OpenSaveDataTransferManagerForRepair);
ADD_ENUM_CASE(SetDebugConfiguration);
ADD_ENUM_CASE(OpenDataStorageByPath);
default: return ToValueString(static_cast<int>(id));
}
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#include <exosphere/pkg1.hpp>
namespace ams::fs::impl {
#define ADD_ENUM_CASE(v) case v: return #v
template<> const char *IdString::ToString<pkg1::KeyGeneration>(pkg1::KeyGeneration id) {
static_assert(pkg1::KeyGeneration_Current == pkg1::KeyGeneration_13_0_0);
switch (id) {
using enum pkg1::KeyGeneration;
case KeyGeneration_1_0_0: return "1.0.0-2.3.0";
case KeyGeneration_3_0_0: return "3.0.0";
case KeyGeneration_3_0_1: return "3.0.1-3.0.2";
case KeyGeneration_4_0_0: return "4.0.0-4.1.0";
case KeyGeneration_5_0_0: return "5.0.0-5.1.0";
case KeyGeneration_6_0_0: return "6.0.0-6.1.0";
case KeyGeneration_6_2_0: return "6.2.0";
case KeyGeneration_7_0_0: return "7.0.0-8.0.1";
case KeyGeneration_8_1_0: return "8.1.0-8.1.1";
case KeyGeneration_9_0_0: return "9.0.0-9.0.1";
case KeyGeneration_9_1_0: return "9.1.0-12.0.3";
case KeyGeneration_12_1_0: return "12.1.0";
case KeyGeneration_13_0_0: return "13.0.0-";
default: return "Unknown";
}
}
}

View File

@@ -39,12 +39,16 @@ namespace ams::fs::impl {
[[maybe_unused]] constexpr size_t BufferPoolSize = 6_MB;
[[maybe_unused]] constexpr size_t DeviceBufferSize = 8_MB;
[[maybe_unused]] constexpr size_t DeviceWorkBufferSize = os::MemoryPageSize;
[[maybe_unused]] constexpr size_t BufferManagerHeapSize = 14_MB;
constexpr size_t DeviceWorkBufferRequiredSize = 0x140;
static_assert(util::IsAligned(BufferManagerHeapSize, os::MemoryBlockUnitSize));
//alignas(os::MemoryPageSize) u8 g_buffer_pool[BufferPoolSize];
//alignas(os::MemoryPageSize) u8 g_device_buffer[DeviceBufferSize];
alignas(os::MemoryPageSize) u8 g_device_buffer[DeviceBufferSize];
alignas(os::MemoryPageSize) u8 g_device_work_buffer[DeviceWorkBufferSize];
//alignas(os::MemoryPageSize) u8 g_buffer_manager_heap[BufferManagerHeapSize];
//
//alignas(os::MemoryPageSize) u8 g_buffer_manager_work_buffer[64_KB];
@@ -69,6 +73,8 @@ namespace ams::fs::impl {
/* TODO: Many things. */
g_system_heap_memory_resource.emplace(std::addressof(GetSystemHeapAllocator()));
fssystem::InitializeBufferPool(reinterpret_cast<char *>(g_device_buffer), DeviceBufferSize, reinterpret_cast<char *>(g_device_work_buffer), DeviceWorkBufferRequiredSize);
/* Setup fscreators/interfaces. */
g_local_fs_creator.emplace(true);
g_subdir_fs_creator.emplace();

View File

@@ -60,4 +60,36 @@ namespace ams::fssrv::fscreator {
return ResultSuccess();
}
#if !defined(ATMOSPHERE_BOARD_NINTENDO_NX)
Result StorageOnNcaCreator::CreateWithContext(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fssystem::IAsynchronousAccessSplitter> *out_splitter, fssystem::NcaFsHeaderReader *out_header_reader, void *ctx, std::shared_ptr<fssystem::NcaReader> nca_reader, s32 index) {
/* Create a fs driver. */
fssystem::NcaFileSystemDriver nca_fs_driver(nca_reader, m_allocator, m_buffer_manager, m_hash_generator_factory_selector);
/* Open the storage. */
std::shared_ptr<fs::IStorage> storage;
std::shared_ptr<fssystem::IAsynchronousAccessSplitter> splitter;
R_TRY(nca_fs_driver.OpenStorageWithContext(std::addressof(storage), std::addressof(splitter), out_header_reader, index, static_cast<fssystem::NcaFileSystemDriver::StorageContext *>(ctx)));
/* Set the out storage. */
*out = std::move(storage);
*out_splitter = std::move(splitter);
return ResultSuccess();
}
Result StorageOnNcaCreator::CreateWithPatchWithContext(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fssystem::IAsynchronousAccessSplitter> *out_splitter, fssystem::NcaFsHeaderReader *out_header_reader, void *ctx, std::shared_ptr<fssystem::NcaReader> original_nca_reader, std::shared_ptr<fssystem::NcaReader> current_nca_reader, s32 index) {
/* Create a fs driver. */
fssystem::NcaFileSystemDriver nca_fs_driver(original_nca_reader, current_nca_reader, m_allocator, m_buffer_manager, m_hash_generator_factory_selector);
/* Open the storage. */
std::shared_ptr<fs::IStorage> storage;
std::shared_ptr<fssystem::IAsynchronousAccessSplitter> splitter;
R_TRY(nca_fs_driver.OpenStorageWithContext(std::addressof(storage), std::addressof(splitter), out_header_reader, index, static_cast<fssystem::NcaFileSystemDriver::StorageContext *>(ctx)));
/* Set the out storage. */
*out = std::move(storage);
*out_splitter = std::move(splitter);
return ResultSuccess();
}
#endif
}

View File

@@ -23,9 +23,385 @@ namespace ams::fssrv {
}
bool IsDebugFlagEnabled() {
return g_is_debug_flag_enabled;
}
void SetDebugFlagEnabled(bool en) {
/* Set global debug flag. */
g_is_debug_flag_enabled = en;
}
namespace impl {
namespace {
constexpr u8 LatestFsAccessControlInfoVersion = 1;
}
AccessControl::AccessControl(const void *data, s64 data_size, const void *desc, s64 desc_size) : AccessControl(data, data_size, desc, desc_size, g_is_debug_flag_enabled ? AllFlagBitsMask : DebugFlagDisableMask) {
/* ... */
}
AccessControl::AccessControl(const void *fac_data, s64 data_size, const void *fac_desc, s64 desc_size, u64 flag_mask) {
/* If either our data or descriptor is null, give no permissions. */
if (fac_data == nullptr || fac_desc == nullptr) {
m_flag_bits.emplace(util::ToUnderlying(AccessControlBits::Bits::None));
return;
}
/* Check that data/desc are big enough. */
AMS_ABORT_UNLESS(data_size >= static_cast<s64>(sizeof(AccessControlDataHeader)));
AMS_ABORT_UNLESS(desc_size >= static_cast<s64>(sizeof(AccessControlDescriptor)));
/* Copy in the data/descriptor. */
AccessControlDataHeader data = {};
AccessControlDescriptor desc = {};
std::memcpy(std::addressof(data), fac_data, sizeof(data));
std::memcpy(std::addressof(desc), fac_desc, sizeof(desc));
/* If we don't know how to parse the descriptors, don't. */
if (data.version != desc.version || data.version < LatestFsAccessControlInfoVersion) {
m_flag_bits.emplace(util::ToUnderlying(AccessControlBits::Bits::None));
return;
}
/* Restrict the descriptor's flag bits. */
desc.flag_bits &= flag_mask;
/* Create our flag bits. */
m_flag_bits.emplace(data.flag_bits & desc.flag_bits);
/* Further check sizes. */
AMS_ABORT_UNLESS(data_size >= data.content_owner_infos_offset + data.content_owner_infos_size);
AMS_ABORT_UNLESS(desc_size >= static_cast<s64>(sizeof(AccessControlDescriptor) + desc.content_owner_id_count * sizeof(u64)));
/* Read out the content data owner infos. */
uintptr_t data_start = reinterpret_cast<uintptr_t>(fac_data);
uintptr_t desc_start = reinterpret_cast<uintptr_t>(fac_desc);
if (data.content_owner_infos_size > 0) {
/* Get the count. */
const u32 num_content_owner_infos = util::LoadLittleEndian<u32>(reinterpret_cast<u32 *>(data_start + data.content_owner_infos_offset));
/* Validate the id range. */
uintptr_t id_start = data_start + data.content_owner_infos_offset + sizeof(u32);
uintptr_t id_end = id_start + sizeof(u64) * num_content_owner_infos;
AMS_ABORT_UNLESS(id_end == data_start + data.content_owner_infos_offset + data.content_owner_infos_size);
for (u32 i = 0; i < num_content_owner_infos; ++i) {
/* Read the id. */
const u64 id = util::LoadLittleEndian<u64>(reinterpret_cast<u64 *>(id_start + i * sizeof(u64)));
/* Check that the descriptor allows it. */
bool allowed = false;
if (desc.content_owner_id_count != 0) {
for (u8 n = 0; n < desc.content_owner_id_count; ++n) {
if (id == util::LoadLittleEndian<u64>(reinterpret_cast<u64 *>(desc_start + sizeof(AccessControlDescriptor) + n * sizeof(u64)))) {
allowed = true;
break;
}
}
} else if ((desc.content_owner_id_min == 0 && desc.content_owner_id_max == 0) || (desc.content_owner_id_min <= id && id <= desc.content_owner_id_max)) {
allowed = true;
}
/* If the id is allowed, create it. */
if (allowed) {
if (auto *info = new ContentOwnerInfo(id); info != nullptr) {
m_content_owner_infos.push_front(*info);
}
}
}
}
/* Read out the save data owner infos. */
AMS_ABORT_UNLESS(data_size >= data.save_data_owner_infos_offset + data.save_data_owner_infos_size);
AMS_ABORT_UNLESS(desc_size >= static_cast<s64>(sizeof(AccessControlDescriptor) + desc.content_owner_id_count * sizeof(u64) + desc.save_data_owner_id_count * sizeof(u64)));
if (data.save_data_owner_infos_size > 0) {
/* Get the count. */
const u32 num_save_data_owner_infos = util::LoadLittleEndian<u32>(reinterpret_cast<u32 *>(data_start + data.save_data_owner_infos_offset));
/* Get accessibility region.*/
uintptr_t accessibility_start = data_start + data.save_data_owner_infos_offset + sizeof(u32);
/* Validate the id range. */
uintptr_t id_start = accessibility_start + util::AlignUp(num_save_data_owner_infos * sizeof(Accessibility), alignof(u32));
uintptr_t id_end = id_start + sizeof(u64) * num_save_data_owner_infos;
AMS_ABORT_UNLESS(id_end == data_start + data.save_data_owner_infos_offset + data.save_data_owner_infos_size);
for (u32 i = 0; i < num_save_data_owner_infos; ++i) {
/* Read the accessibility/id. */
static_assert(sizeof(Accessibility) == 1);
const Accessibility accessibility = *reinterpret_cast<Accessibility *>(accessibility_start + i * sizeof(Accessibility));
const u64 id = util::LoadLittleEndian<u64>(reinterpret_cast<u64 *>(id_start + i * sizeof(u64)));
/* Check that the descriptor allows it. */
bool allowed = false;
if (desc.save_data_owner_id_count != 0) {
for (u8 n = 0; n < desc.save_data_owner_id_count; ++n) {
if (id == util::LoadLittleEndian<u64>(reinterpret_cast<u64 *>(desc_start + sizeof(AccessControlDescriptor) + desc.content_owner_id_count * sizeof(u64) + n * sizeof(u64)))) {
allowed = true;
break;
}
}
} else if ((desc.save_data_owner_id_min == 0 && desc.save_data_owner_id_max == 0) || (desc.save_data_owner_id_min <= id && id <= desc.save_data_owner_id_max)) {
allowed = true;
}
/* If the id is allowed, create it. */
if (allowed) {
if (auto *info = new SaveDataOwnerInfo(id, accessibility); info != nullptr) {
m_save_data_owner_infos.push_front(*info);
}
}
}
}
}
AccessControl::~AccessControl() {
/* Delete all content owner infos. */
while (!m_content_owner_infos.empty()) {
auto *info = std::addressof(*m_content_owner_infos.rbegin());
m_content_owner_infos.erase(m_content_owner_infos.iterator_to(*info));
delete info;
}
/* Delete all save data owner infos. */
while (!m_save_data_owner_infos.empty()) {
auto *info = std::addressof(*m_save_data_owner_infos.rbegin());
m_save_data_owner_infos.erase(m_save_data_owner_infos.iterator_to(*info));
delete info;
}
}
bool AccessControl::HasContentOwnerId(u64 owner_id) const {
/* Check if we have a matching id. */
for (const auto &info : m_content_owner_infos) {
if (info.GetId() == owner_id) {
return true;
}
}
return false;
}
Accessibility AccessControl::GetAccessibilitySaveDataOwnedBy(u64 owner_id) const {
/* Find a matching save data owner. */
for (const auto &info : m_save_data_owner_infos) {
if (info.GetId() == owner_id) {
return info.GetAccessibility();
}
}
/* Default to no accessibility. */
return Accessibility::MakeAccessibility(false, false);
}
void AccessControl::ListContentOwnerId(s32 *out_count, u64 *out_owner_ids, s32 offset, s32 count) const {
/* If we have nothing to read, just give the count. */
if (count == 0) {
*out_count = m_content_owner_infos.size();
return;
}
/* Read out the ids. */
s32 read_offset = 0;
s32 read_count = 0;
if (out_owner_ids != nullptr) {
auto *cur_out = out_owner_ids;
for (const auto &info : m_content_owner_infos) {
/* Skip until we get to the desired offset. */
if (read_offset < offset) {
++read_offset;
continue;
}
/* Set the output value. */
*cur_out = info.GetId();
++cur_out;
++read_count;
/* If we've read as many as we can, finish. */
if (read_count == count) {
break;
}
}
}
/* Set the out value. */
*out_count = read_count;
}
void AccessControl::ListSaveDataOwnedId(s32 *out_count, ncm::ApplicationId *out_owner_ids, s32 offset, s32 count) const {
/* If we have nothing to read, just give the count. */
if (count == 0) {
*out_count = m_save_data_owner_infos.size();
return;
}
/* Read out the ids. */
s32 read_offset = 0;
s32 read_count = 0;
if (out_owner_ids != nullptr) {
auto *cur_out = out_owner_ids;
for (const auto &info : m_save_data_owner_infos) {
/* Skip until we get to the desired offset. */
if (read_offset < offset) {
++read_offset;
continue;
}
/* Set the output value. */
cur_out->value = info.GetId();
++cur_out;
++read_count;
/* If we've read as many as we can, finish. */
if (read_count == count) {
break;
}
}
}
/* Set the out value. */
*out_count = read_count;
}
Accessibility AccessControl::GetAccessibilityFor(AccessibilityType type) const {
switch (type) {
using enum AccessibilityType;
case MountLogo: return Accessibility::MakeAccessibility(m_flag_bits->CanMountLogoRead(), false);
case MountContentMeta: return Accessibility::MakeAccessibility(m_flag_bits->CanMountContentMetaRead(), false);
case MountContentControl: return Accessibility::MakeAccessibility(m_flag_bits->CanMountContentControlRead(), false);
case MountContentManual: return Accessibility::MakeAccessibility(m_flag_bits->CanMountContentManualRead(), false);
case MountContentData: return Accessibility::MakeAccessibility(m_flag_bits->CanMountContentDataRead(), false);
case MountApplicationPackage: return Accessibility::MakeAccessibility(m_flag_bits->CanMountApplicationPackageRead(), false);
case MountSaveDataStorage: return Accessibility::MakeAccessibility(m_flag_bits->CanMountSaveDataStorageRead(), m_flag_bits->CanMountSaveDataStorageWrite());
case MountContentStorage: return Accessibility::MakeAccessibility(m_flag_bits->CanMountContentStorageRead(), m_flag_bits->CanMountContentStorageWrite());
case MountImageAndVideoStorage: return Accessibility::MakeAccessibility(m_flag_bits->CanMountImageAndVideoStorageRead(), m_flag_bits->CanMountImageAndVideoStorageWrite());
case MountCloudBackupWorkStorage: return Accessibility::MakeAccessibility(m_flag_bits->CanMountCloudBackupWorkStorageRead(), m_flag_bits->CanMountCloudBackupWorkStorageWrite());
case MountCustomStorage: return Accessibility::MakeAccessibility(m_flag_bits->CanMountCustomStorage0Read(), m_flag_bits->CanMountCustomStorage0Write());
case MountBisCalibrationFile: return Accessibility::MakeAccessibility(m_flag_bits->CanMountBisCalibrationFileRead(), m_flag_bits->CanMountBisCalibrationFileWrite());
case MountBisSafeMode: return Accessibility::MakeAccessibility(m_flag_bits->CanMountBisSafeModeRead(), m_flag_bits->CanMountBisSafeModeWrite());
case MountBisUser: return Accessibility::MakeAccessibility(m_flag_bits->CanMountBisUserRead(), m_flag_bits->CanMountBisUserWrite());
case MountBisSystem: return Accessibility::MakeAccessibility(m_flag_bits->CanMountBisSystemRead(), m_flag_bits->CanMountBisSystemWrite());
case MountBisSystemProperEncryption: return Accessibility::MakeAccessibility(m_flag_bits->CanMountBisSystemProperEncryptionRead(), m_flag_bits->CanMountBisSystemProperEncryptionWrite());
case MountBisSystemProperPartition: return Accessibility::MakeAccessibility(m_flag_bits->CanMountBisSystemProperPartitionRead(), m_flag_bits->CanMountBisSystemProperPartitionWrite());
case MountSdCard: return Accessibility::MakeAccessibility(m_flag_bits->CanMountSdCardRead(), m_flag_bits->CanMountSdCardWrite());
case MountGameCard: return Accessibility::MakeAccessibility(m_flag_bits->CanMountGameCardRead(), false);
case MountDeviceSaveData: return Accessibility::MakeAccessibility(m_flag_bits->CanMountDeviceSaveDataRead(), m_flag_bits->CanMountDeviceSaveDataWrite());
case MountSystemSaveData: return Accessibility::MakeAccessibility(m_flag_bits->CanMountSystemSaveDataRead(), m_flag_bits->CanMountSystemSaveDataWrite());
case MountOthersSaveData: return Accessibility::MakeAccessibility(m_flag_bits->CanMountOthersSaveDataRead(), m_flag_bits->CanMountOthersSaveDataWrite());
case MountOthersSystemSaveData: return Accessibility::MakeAccessibility(m_flag_bits->CanMountOthersSystemSaveDataRead(), m_flag_bits->CanMountOthersSystemSaveDataWrite());
case OpenBisPartitionBootPartition1Root: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionBootPartition1RootRead(), m_flag_bits->CanOpenBisPartitionBootPartition1RootWrite());
case OpenBisPartitionBootPartition2Root: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionBootPartition2RootRead(), m_flag_bits->CanOpenBisPartitionBootPartition2RootWrite());
case OpenBisPartitionUserDataRoot: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionUserDataRootRead(), m_flag_bits->CanOpenBisPartitionUserDataRootWrite());
case OpenBisPartitionBootConfigAndPackage2Part1: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part1Read(), m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part1Write());
case OpenBisPartitionBootConfigAndPackage2Part2: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part2Read(), m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part2Write());
case OpenBisPartitionBootConfigAndPackage2Part3: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part3Read(), m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part3Write());
case OpenBisPartitionBootConfigAndPackage2Part4: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part4Read(), m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part4Write());
case OpenBisPartitionBootConfigAndPackage2Part5: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part5Read(), m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part5Write());
case OpenBisPartitionBootConfigAndPackage2Part6: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part6Read(), m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part6Write());
case OpenBisPartitionCalibrationBinary: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionCalibrationBinaryRead(), m_flag_bits->CanOpenBisPartitionCalibrationBinaryWrite());
case OpenBisPartitionCalibrationFile: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionCalibrationFileRead(), m_flag_bits->CanOpenBisPartitionCalibrationFileWrite());
case OpenBisPartitionSafeMode: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionSafeModeRead(), m_flag_bits->CanOpenBisPartitionSafeModeWrite());
case OpenBisPartitionUser: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionUserRead(), m_flag_bits->CanOpenBisPartitionUserWrite());
case OpenBisPartitionSystem: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionSystemRead(), m_flag_bits->CanOpenBisPartitionSystemWrite());
case OpenBisPartitionSystemProperEncryption: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionSystemProperEncryptionRead(), m_flag_bits->CanOpenBisPartitionSystemProperEncryptionWrite());
case OpenBisPartitionSystemProperPartition: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionSystemProperPartitionRead(), m_flag_bits->CanOpenBisPartitionSystemProperPartitionWrite());
case OpenSdCardStorage: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenSdCardStorageRead(), m_flag_bits->CanOpenSdCardStorageWrite());
case OpenGameCardStorage: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenGameCardStorageRead(), m_flag_bits->CanOpenGameCardStorageWrite());
case MountSystemDataPrivate: return Accessibility::MakeAccessibility(m_flag_bits->CanMountSystemDataPrivateRead(), false);
case MountHost: return Accessibility::MakeAccessibility(m_flag_bits->CanMountHostRead(), m_flag_bits->CanMountHostWrite());
case MountRegisteredUpdatePartition: return Accessibility::MakeAccessibility(m_flag_bits->CanMountRegisteredUpdatePartitionRead() && g_is_debug_flag_enabled, false);
case MountSaveDataInternalStorage: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenSaveDataInternalStorageRead(), m_flag_bits->CanOpenSaveDataInternalStorageWrite());
case MountTemporaryDirectory: return Accessibility::MakeAccessibility(m_flag_bits->CanMountTemporaryDirectoryRead(), m_flag_bits->CanMountTemporaryDirectoryWrite());
case MountAllBaseFileSystem: return Accessibility::MakeAccessibility(m_flag_bits->CanMountAllBaseFileSystemRead(), m_flag_bits->CanMountAllBaseFileSystemWrite());
case NotMount: return Accessibility::MakeAccessibility(false, false);
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
bool AccessControl::CanCall(OperationType type) const {
switch (type) {
using enum OperationType;
case InvalidateBisCache: return m_flag_bits->CanInvalidateBisCache();
case EraseMmc: return m_flag_bits->CanEraseMmc();
case GetGameCardDeviceCertificate: return m_flag_bits->CanGetGameCardDeviceCertificate();
case GetGameCardIdSet: return m_flag_bits->CanGetGameCardIdSet();
case FinalizeGameCardDriver: return m_flag_bits->CanFinalizeGameCardDriver();
case GetGameCardAsicInfo: return m_flag_bits->CanGetGameCardAsicInfo();
case CreateSaveData: return m_flag_bits->CanCreateSaveData();
case DeleteSaveData: return m_flag_bits->CanDeleteSaveData();
case CreateSystemSaveData: return m_flag_bits->CanCreateSystemSaveData();
case CreateOthersSystemSaveData: return m_flag_bits->CanCreateOthersSystemSaveData();
case DeleteSystemSaveData: return m_flag_bits->CanDeleteSystemSaveData();
case OpenSaveDataInfoReader: return m_flag_bits->CanOpenSaveDataInfoReader();
case OpenSaveDataInfoReaderForSystem: return m_flag_bits->CanOpenSaveDataInfoReaderForSystem();
case OpenSaveDataInfoReaderForInternal: return m_flag_bits->CanOpenSaveDataInfoReaderForInternal();
case OpenSaveDataMetaFile: return m_flag_bits->CanOpenSaveDataMetaFile();
case SetCurrentPosixTime: return m_flag_bits->CanSetCurrentPosixTime();
case ReadSaveDataFileSystemExtraData: return m_flag_bits->CanReadSaveDataFileSystemExtraData();
case SetGlobalAccessLogMode: return m_flag_bits->CanSetGlobalAccessLogMode();
case SetSpeedEmulationMode: return m_flag_bits->CanSetSpeedEmulationMode();
case FillBis: return m_flag_bits->CanFillBis();
case CorruptSaveData: return m_flag_bits->CanCorruptSaveData();
case CorruptSystemSaveData: return m_flag_bits->CanCorruptSystemSaveData();
case VerifySaveData: return m_flag_bits->CanVerifySaveData();
case DebugSaveData: return m_flag_bits->CanDebugSaveData();
case FormatSdCard: return m_flag_bits->CanFormatSdCard();
case GetRightsId: return m_flag_bits->CanGetRightsId();
case RegisterExternalKey: return m_flag_bits->CanRegisterExternalKey();
case SetEncryptionSeed: return m_flag_bits->CanSetEncryptionSeed();
case WriteSaveDataFileSystemExtraDataTimeStamp: return m_flag_bits->CanWriteSaveDataFileSystemExtraDataTimeStamp();
case WriteSaveDataFileSystemExtraDataFlags: return m_flag_bits->CanWriteSaveDataFileSystemExtraDataFlags();
case WriteSaveDataFileSystemExtraDataCommitId: return m_flag_bits->CanWriteSaveDataFileSystemExtraDataCommitId();
case WriteSaveDataFileSystemExtraDataAll: return m_flag_bits->CanWriteSaveDataFileSystemExtraDataAll();
case ExtendSaveData: return m_flag_bits->CanExtendSaveData();
case ExtendSystemSaveData: return m_flag_bits->CanExtendSystemSaveData();
case ExtendOthersSystemSaveData: return m_flag_bits->CanExtendOthersSystemSaveData();
case RegisterUpdatePartition: return m_flag_bits->CanRegisterUpdatePartition() && g_is_debug_flag_enabled;
case OpenSaveDataTransferManager: return m_flag_bits->CanOpenSaveDataTransferManager();
case OpenSaveDataTransferManagerVersion2: return m_flag_bits->CanOpenSaveDataTransferManagerVersion2();
case OpenSaveDataTransferManagerForSaveDataRepair: return m_flag_bits->CanOpenSaveDataTransferManagerForSaveDataRepair();
case OpenSaveDataTransferManagerForSaveDataRepairTool: return m_flag_bits->CanOpenSaveDataTransferManagerForSaveDataRepairTool();
case OpenSaveDataTransferProhibiter: return m_flag_bits->CanOpenSaveDataTransferProhibiter();
case OpenSaveDataMover: return m_flag_bits->CanOpenSaveDataMover();
case OpenBisWiper: return m_flag_bits->CanOpenBisWiper();
case ListAccessibleSaveDataOwnerId: return m_flag_bits->CanListAccessibleSaveDataOwnerId();
case ControlMmcPatrol: return m_flag_bits->CanControlMmcPatrol();
case OverrideSaveDataTransferTokenSignVerificationKey: return m_flag_bits->CanOverrideSaveDataTransferTokenSignVerificationKey();
case OpenSdCardDetectionEventNotifier: return m_flag_bits->CanOpenSdCardDetectionEventNotifier();
case OpenGameCardDetectionEventNotifier: return m_flag_bits->CanOpenGameCardDetectionEventNotifier();
case OpenSystemDataUpdateEventNotifier: return m_flag_bits->CanOpenSystemDataUpdateEventNotifier();
case NotifySystemDataUpdateEvent: return m_flag_bits->CanNotifySystemDataUpdateEvent();
case OpenAccessFailureDetectionEventNotifier: return m_flag_bits->CanOpenAccessFailureDetectionEventNotifier();
case GetAccessFailureDetectionEvent: return m_flag_bits->CanGetAccessFailureDetectionEvent();
case IsAccessFailureDetected: return m_flag_bits->CanIsAccessFailureDetected();
case ResolveAccessFailure: return m_flag_bits->CanResolveAccessFailure();
case AbandonAccessFailure: return m_flag_bits->CanAbandonAccessFailure();
case QuerySaveDataInternalStorageTotalSize: return m_flag_bits->CanQuerySaveDataInternalStorageTotalSize();
case GetSaveDataCommitId: return m_flag_bits->CanGetSaveDataCommitId();
case SetSdCardAccessibility: return m_flag_bits->CanSetSdCardAccessibility();
case SimulateDevice: return m_flag_bits->CanSimulateDevice();
case CreateSaveDataWithHashSalt: return m_flag_bits->CanCreateSaveDataWithHashSalt();
case RegisterProgramIndexMapInfo: return m_flag_bits->CanRegisterProgramIndexMapInfo();
case ChallengeCardExistence: return m_flag_bits->CanChallengeCardExistence();
case CreateOwnSaveData: return m_flag_bits->CanCreateOwnSaveData();
case DeleteOwnSaveData: return m_flag_bits->CanDeleteOwnSaveData();
case ReadOwnSaveDataFileSystemExtraData: return m_flag_bits->CanReadOwnSaveDataFileSystemExtraData();
case ExtendOwnSaveData: return m_flag_bits->CanExtendOwnSaveData();
case OpenOwnSaveDataTransferProhibiter: return m_flag_bits->CanOpenOwnSaveDataTransferProhibiter();
case FindOwnSaveDataWithFilter: return m_flag_bits->CanFindOwnSaveDataWithFilter();
case OpenSaveDataTransferManagerForRepair: return m_flag_bits->CanOpenSaveDataTransferManagerForRepair();
case SetDebugConfiguration: return m_flag_bits->CanSetDebugConfiguration();
case OpenDataStorageByPath: return m_flag_bits->CanOpenDataStorageByPath();
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
}
}

View File

@@ -19,7 +19,9 @@
#if defined(ATMOSPHERE_OS_LINUX)
#include <unistd.h>
#elif defined(ATMOSPHERE_OS_MACOS)
#include <mach-o/dyld.h>
#include <unistd.h>
#include <mach-o/dyld.h>
#include <sys/param.h>
#endif
namespace ams::fssystem {
@@ -47,10 +49,10 @@ namespace ams::fssystem {
::swprintf_s(path, util::size(path), L"%s%s", drive_name, dir_name);
/* Convert to utf-8. */
const auto res = ::WideCharToMultiByte(CP_UTF8, 0, path, -1, m_path, util::size(m_path), nullptr, nullptr);
if (res == 0) {
AMS_FS_R_ABORT_UNLESS(fs::ResultUnexpectedInPathOnExecutionDirectoryB());
}
const auto res = ::WideCharToMultiByte(CP_UTF8, 0, path, -1, m_path, util::size(m_path), nullptr, nullptr);
if (res == 0) {
AMS_FS_R_ABORT_UNLESS(fs::ResultUnexpectedInPathOnExecutionDirectoryB());
}
}
#elif defined(ATMOSPHERE_OS_LINUX)
{
@@ -60,6 +62,10 @@ namespace ams::fssystem {
}
const int len = std::strlen(full_path);
if (len >= static_cast<int>(sizeof(m_path))) {
AMS_FS_R_ABORT_UNLESS(fs::ResultUnexpectedInPathOnExecutionDirectoryB());
}
std::memcpy(m_path, full_path, len + 1);
for (int i = len - 1; i >= 0; --i) {
@@ -71,11 +77,17 @@ namespace ams::fssystem {
}
#elif defined(ATMOSPHERE_OS_MACOS)
{
char full_path[PATH_MAX + 1] = {};
char full_path[MAXPATHLEN] = {};
uint32_t size = sizeof(full_path);
AMS_ABORT_UNLESS(_NSGetExecutablePath(full_path, std::addressof(size)) == 0);
if (_NSGetExecutablePath(full_path, std::addressof(size)) != 0) {
AMS_FS_R_ABORT_UNLESS(fs::ResultUnexpectedInPathOnExecutionDirectoryA());
}
const int len = std::strlen(full_path);
if (len >= static_cast<int>(sizeof(m_path))) {
AMS_FS_R_ABORT_UNLESS(fs::ResultUnexpectedInPathOnExecutionDirectoryB());
}
std::memcpy(m_path, full_path, len + 1);
for (int i = len - 1; i >= 0; --i) {
@@ -88,6 +100,81 @@ namespace ams::fssystem {
#else
AMS_ABORT("TODO: Unknown OS for PathOnExecutionDirectory");
#endif
const auto len = std::strlen(m_path);
if (m_path[len - 1] != '/' && m_path[len - 1] != '\\') {
if (len + 1 >= sizeof(m_path)) {
AMS_FS_R_ABORT_UNLESS(fs::ResultUnexpectedInPathOnExecutionDirectoryB());
}
m_path[len] = '/';
m_path[len + 1] = 0;
}
}
const char *Get() const {
return m_path;
}
};
class PathOnWorkingDirectory {
private:
char m_path[fs::EntryNameLengthMax + 1];
public:
PathOnWorkingDirectory() {
#if defined(ATMOSPHERE_OS_WINDOWS)
{
/* Get the current directory. */
wchar_t current_directory[fs::EntryNameLengthMax + 1];
if (::GetCurrentDirectoryW(util::size(current_directory), current_directory) == 0) {
AMS_FS_R_ABORT_UNLESS(fs::ResultUnexpectedInPathOnExecutionDirectoryB());
}
/* Convert to utf-8. */
const auto res = ::WideCharToMultiByte(CP_UTF8, 0, current_directory, -1, m_path, util::size(m_path), nullptr, nullptr);
if (res == 0) {
AMS_FS_R_ABORT_UNLESS(fs::ResultUnexpectedInPathOnExecutionDirectoryB());
}
}
#elif defined(ATMOSPHERE_OS_LINUX)
{
char full_path[PATH_MAX] = {};
if (::getcwd(full_path, sizeof(full_path)) == nullptr) {
AMS_FS_R_ABORT_UNLESS(fs::ResultUnexpectedInPathOnExecutionDirectoryB());
}
const int len = std::strlen(full_path);
if (len >= static_cast<int>(sizeof(m_path))) {
AMS_FS_R_ABORT_UNLESS(fs::ResultUnexpectedInPathOnExecutionDirectoryB());
}
std::memcpy(m_path, full_path, len + 1);
}
#elif defined(ATMOSPHERE_OS_MACOS)
{
char full_path[MAXPATHLEN] = {};
if (::getcwd(full_path, sizeof(full_path)) == nullptr) {
AMS_FS_R_ABORT_UNLESS(fs::ResultUnexpectedInPathOnExecutionDirectoryB());
}
const int len = std::strlen(full_path);
if (len >= static_cast<int>(sizeof(m_path))) {
AMS_FS_R_ABORT_UNLESS(fs::ResultUnexpectedInPathOnExecutionDirectoryB());
}
std::memcpy(m_path, full_path, len + 1);
}
#else
AMS_ABORT("TODO: Unknown OS for PathOnWorkingDirectory");
#endif
const auto len = std::strlen(m_path);
if (m_path[len - 1] != '/' && m_path[len - 1] != '\\') {
if (len + 1 >= sizeof(m_path)) {
AMS_FS_R_ABORT_UNLESS(fs::ResultUnexpectedInPathOnExecutionDirectoryB());
}
m_path[len] = '/';
m_path[len + 1] = 0;
}
}
const char *Get() const {
@@ -104,4 +191,9 @@ namespace ams::fssrv::impl {
return s_path_on_execution_directory.Get();
}
const char *GetWorkingDirectoryPath() {
AMS_FUNCTION_LOCAL_STATIC(fssystem::PathOnWorkingDirectory, s_path_on_working_directory);
return s_path_on_working_directory.Get();
}
}

View File

@@ -19,5 +19,6 @@
namespace ams::fssrv::impl {
const char *GetExecutionDirectoryPath();
const char *GetWorkingDirectoryPath();
}

View File

@@ -32,7 +32,7 @@ namespace ams::fssystem {
template<typename BasePointer>
AesCtrStorage<BasePointer>::AesCtrStorage(BasePointer base, const void *key, size_t key_size, const void *iv, size_t iv_size) : m_base_storage(std::move(base)) {
AMS_ASSERT(base != nullptr);
AMS_ASSERT(m_base_storage != nullptr);
AMS_ASSERT(key != nullptr);
AMS_ASSERT(iv != nullptr);
AMS_ASSERT(key_size == KeySize);

View File

@@ -777,7 +777,7 @@ namespace ams::fssystem {
/* Get and validate the meta extents. */
const s64 meta_offset = patch_info.aes_ctr_ex_offset;
const s64 meta_size = util::AlignUp(patch_info.aes_ctr_ex_size, NcaHeader::XtsBlockSize);
const s64 meta_size = util::AlignUp(static_cast<s64>(patch_info.aes_ctr_ex_size), NcaHeader::XtsBlockSize);
R_UNLESS(meta_offset + meta_size <= base_size, fs::ResultNcaBaseStorageOutOfRangeB());
/* Create the encrypted storage. */

View File

@@ -45,6 +45,14 @@ namespace ams::fssystem {
/* ... */
}
void Dump(const void *s, size_t size) {
const u8 *s8 = static_cast<const u8 *>(s);
for (size_t i = 0; i < size; ++i) {
printf("%02X", s8[i]);
}
printf("\n");
}
Result NcaReader::Initialize(std::shared_ptr<fs::IStorage> base_storage, const NcaCryptoConfiguration &crypto_cfg, const NcaCompressionConfiguration &compression_cfg, IHash256GeneratorFactorySelector *hgf_selector) {
/* Validate preconditions. */
AMS_ASSERT(base_storage != nullptr);
@@ -60,6 +68,7 @@ namespace ams::fssystem {
u8 header_decryption_keys[NcaCryptoConfiguration::HeaderEncryptionKeyCount][NcaCryptoConfiguration::Aes128KeySize];
for (size_t i = 0; i < NcaCryptoConfiguration::HeaderEncryptionKeyCount; i++) {
crypto_cfg.generate_key(header_decryption_keys[i], AesXtsStorageForNcaHeader::KeySize, crypto_cfg.header_encrypted_encryption_keys[i], AesXtsStorageForNcaHeader::KeySize, static_cast<s32>(KeyType::NcaHeaderKey), crypto_cfg);
Dump(header_decryption_keys[i], sizeof(header_decryption_keys[i]));
}
/* Create the header storage. */
@@ -119,6 +128,13 @@ namespace ams::fssystem {
/* If we do, then we don't have an external key, so we need to generate decryption keys. */
crypto_cfg.generate_key(m_decryption_keys[NcaHeader::DecryptionKey_AesCtr], crypto::AesDecryptor128::KeySize, m_header.encrypted_key_area + NcaHeader::DecryptionKey_AesCtr * crypto::AesDecryptor128::KeySize, crypto::AesDecryptor128::KeySize, GetKeyTypeValue(m_header.key_index, m_header.GetProperKeyGeneration()), crypto_cfg);
/* If we're building for non-nx board (i.e., a host tool), generate all keys for debug. */
#if !defined(ATMOSPHERE_BOARD_NINTENDO_NX)
crypto_cfg.generate_key(m_decryption_keys[NcaHeader::DecryptionKey_AesXts1], crypto::AesDecryptor128::KeySize, m_header.encrypted_key_area + NcaHeader::DecryptionKey_AesXts1 * crypto::AesDecryptor128::KeySize, crypto::AesDecryptor128::KeySize, GetKeyTypeValue(m_header.key_index, m_header.GetProperKeyGeneration()), crypto_cfg);
crypto_cfg.generate_key(m_decryption_keys[NcaHeader::DecryptionKey_AesXts2], crypto::AesDecryptor128::KeySize, m_header.encrypted_key_area + NcaHeader::DecryptionKey_AesXts2 * crypto::AesDecryptor128::KeySize, crypto::AesDecryptor128::KeySize, GetKeyTypeValue(m_header.key_index, m_header.GetProperKeyGeneration()), crypto_cfg);
crypto_cfg.generate_key(m_decryption_keys[NcaHeader::DecryptionKey_AesCtrEx], crypto::AesDecryptor128::KeySize, m_header.encrypted_key_area + NcaHeader::DecryptionKey_AesCtrEx * crypto::AesDecryptor128::KeySize, crypto::AesDecryptor128::KeySize, GetKeyTypeValue(m_header.key_index, m_header.GetProperKeyGeneration()), crypto_cfg);
#endif
/* Copy the hardware speed emulation key. */
std::memcpy(m_decryption_keys[NcaHeader::DecryptionKey_AesCtrHw], m_header.encrypted_key_area + NcaHeader::DecryptionKey_AesCtrHw * crypto::AesDecryptor128::KeySize, crypto::AesDecryptor128::KeySize);
}
@@ -164,6 +180,11 @@ namespace ams::fssystem {
return m_header.content_type;
}
u8 NcaReader::GetHeaderSign1KeyGeneration() const {
AMS_ASSERT(m_body_storage != nullptr);
return m_header.header1_signature_key_generation;
}
u8 NcaReader::GetKeyGeneration() const {
AMS_ASSERT(m_body_storage != nullptr);
return m_header.GetProperKeyGeneration();

View File

@@ -359,7 +359,7 @@ namespace ams::fssystem {
R_UNLESS(p[0] == RootPath[0], fs::ResultInvalidPathFormat());
/* Check if the path is for a directory. */
if (util::Strncmp(p, RootPath, sizeof(RootPath))) {
if (util::Strncmp(p, RootPath, sizeof(RootPath)) == 0) {
*out = fs::DirectoryEntryType_Directory;
R_SUCCEED();
}

View File

@@ -57,7 +57,7 @@ namespace ams::fssystem::save {
/* Calculate block shift. */
m_verification_block_shift = ILog2(static_cast<u32>(verif_block_size));
AMS_ASSERT(static_cast<size_t>(1ull << m_verification_block_size) == m_verification_block_size);
AMS_ASSERT(static_cast<size_t>(1ull << m_verification_block_shift) == m_verification_block_size);
/* Clear the entry. */
std::memset(m_entries.get(), 0, sizeof(CacheEntry) * m_max_cache_entry_count);
@@ -341,10 +341,14 @@ namespace ams::fssystem::save {
CacheIndex index;
R_TRY(this->UpdateLastResult(this->StoreAssociateBuffer(std::addressof(index), range, entry)));
/* Set the after aligned offset. */
aligned_offset = entry.offset + entry.size;
/* If we need to, flush the cache entry. */
if (index >= 0 && IsEnabledKeepBurstMode() && offset == aligned_offset && (block_alignment * 2 <= size)) {
R_TRY(this->UpdateLastResult(this->FlushCacheEntry(index, false)));
}
}
}

View File

@@ -39,7 +39,7 @@ namespace ams::fssystem::save {
m_buffer_manager = bm;
/* Set upper layer block sizes. */
upper_layer_verif_block_size = std::max(upper_layer_verif_block_size, HashSize);
upper_layer_verif_block_size = std::max(upper_layer_verif_block_size, HashSize);
m_upper_layer_verification_block_size = upper_layer_verif_block_size;
m_upper_layer_verification_block_order = ILog2(static_cast<u32>(upper_layer_verif_block_size));
AMS_ASSERT(m_upper_layer_verification_block_size == (1l << m_upper_layer_verification_block_order));
@@ -334,18 +334,10 @@ namespace ams::fssystem::save {
/* Only allow cache invalidation for RomFs. */
R_UNLESS(m_storage_type != fs::StorageType_SaveData, fs::ResultUnsupportedOperationInIntegrityVerificationStorageB());
/* Validate the range. */
s64 data_size = 0;
R_TRY(m_data_storage.GetSize(std::addressof(data_size)));
R_UNLESS(0 <= offset && offset <= data_size, fs::ResultInvalidOffset());
/* Determine the extents to invalidate. */
const auto sign_offset = (offset >> m_verification_block_order) * HashSize;
const auto sign_size = (std::min(size, data_size - offset) >> m_verification_block_order) * HashSize;
/* Operate on our storages. */
R_TRY(m_hash_storage.OperateRange(dst, dst_size, op_id, sign_offset, sign_size, src, src_size));
R_TRY(m_data_storage.OperateRange(dst, dst_size, op_id, sign_offset, sign_size, src, src_size));
R_TRY(m_hash_storage.OperateRange(dst, dst_size, op_id, 0, std::numeric_limits<s64>::max(), src, src_size));
R_TRY(m_data_storage.OperateRange(dst, dst_size, op_id, offset, size, src, src_size));
return ResultSuccess();
}

View File

@@ -32,12 +32,14 @@ namespace ams::spl::impl {
using Drbg = CtrDrbg<crypto::AesEncryptor128, AesKeySize, false>;
/* Convenient defines. */
#if defined(ATMOSPHERE_OS_HORIZON)
constexpr size_t DeviceAddressSpaceAlign = 4_MB;
constexpr u32 WorkBufferBase = 0x80000000u;
constexpr u32 ComputeAesInMapBase = 0x90000000u;
constexpr u32 ComputeAesOutMapBase = 0xC0000000u;
constexpr size_t ComputeAesSizeMax = static_cast<size_t>(ComputeAesOutMapBase - ComputeAesInMapBase);
#endif
constexpr size_t DeviceUniqueDataIvSize = 0x10;
constexpr size_t DeviceUniqueDataPaddingSize = 0x08;
@@ -248,7 +250,7 @@ namespace ams::spl::impl {
R_ABORT_UNLESS(dd::MapDeviceAddressSpaceAligned(std::addressof(g_device_address_space), dd::GetCurrentProcessHandle(), work_buffer_address, dd::DeviceAddressSpaceMemoryRegionAlignment, g_work_buffer_mapped_address, dd::MemoryPermission_ReadWrite));
#else
/* Just set the work buffer address directly. */
AMS_UNUSED(WorkBufferBase, g_device_address_space);
AMS_UNUSED(g_device_address_space);
g_work_buffer_mapped_address = reinterpret_cast<uintptr_t>(g_work_buffer);
#endif
}

View File

@@ -83,9 +83,8 @@ namespace ams::spl::smc {
constinit u8 g_async_result_buffer[1_KB];
u64 GenerateRandomU64() {
/* TODO: Can/should we make this cryptographically secure? */
u64 v = -1;
os::GenerateRandomBytes(std::addressof(v), sizeof(v));
crypto::GenerateCryptographicallyRandomBytes(std::addressof(v), sizeof(v));
return v;
}
@@ -223,8 +222,7 @@ namespace ams::spl::smc {
//}
Result GenerateRandomBytes(void *out, size_t size) {
/* TODO: Cryptographically secure? */
os::GenerateRandomBytes(out, size);
crypto::GenerateCryptographicallyRandomBytes(out, size);
return smc::Result::Success;
}