updater: use fs bindings

This commit is contained in:
Michael Scire 2020-03-07 20:48:47 -08:00
parent 1fbaaa3c18
commit 60636cdc57
7 changed files with 152 additions and 170 deletions

View File

@ -65,7 +65,12 @@ namespace ams::sm {
AMS_ABORT_UNLESS(!this->has_initialized); AMS_ABORT_UNLESS(!this->has_initialized);
sm::DoWithSession([&]() { sm::DoWithSession([&]() {
if constexpr (std::is_same<decltype(Initializer()), void>::value) {
Initializer();
this->result = ResultSuccess();
} else {
this->result = Initializer(); this->result = Initializer();
}
}); });
this->has_initialized = R_SUCCEEDED(this->result); this->has_initialized = R_SUCCEEDED(this->result);

View File

@ -32,25 +32,26 @@ namespace ams::updater {
/* Configuration Prototypes. */ /* Configuration Prototypes. */
bool HasEks(BootImageUpdateType boot_image_update_type); bool HasEks(BootImageUpdateType boot_image_update_type);
bool HasAutoRcmPreserve(BootImageUpdateType boot_image_update_type); bool HasAutoRcmPreserve(BootImageUpdateType boot_image_update_type);
NcmContentMetaType GetNcmContentMetaType(BootModeType mode); ncm::ContentMetaType GetContentMetaType(BootModeType mode);
Result GetBootImagePackageDataId(u64 *out_data_id, BootModeType mode, void *work_buffer, size_t work_buffer_size); Result GetBootImagePackageId(ncm::SystemDataId *out_data_id, BootModeType mode, void *work_buffer, size_t work_buffer_size);
/* Verification Prototypes. */ /* Verification Prototypes. */
Result GetVerificationState(VerificationState *out, void *work_buffer, size_t work_buffer_size); Result GetVerificationState(VerificationState *out, void *work_buffer, size_t work_buffer_size);
Result VerifyBootImages(u64 data_id, BootModeType mode, void *work_buffer, size_t work_buffer_size, BootImageUpdateType boot_image_update_type); Result VerifyBootImages(ncm::SystemDataId data_id, BootModeType mode, void *work_buffer, size_t work_buffer_size, BootImageUpdateType boot_image_update_type);
Result VerifyBootImagesNormal(u64 data_id, void *work_buffer, size_t work_buffer_size, BootImageUpdateType boot_image_update_type); Result VerifyBootImagesNormal(ncm::SystemDataId data_id, void *work_buffer, size_t work_buffer_size, BootImageUpdateType boot_image_update_type);
Result VerifyBootImagesSafe(u64 data_id, void *work_buffer, size_t work_buffer_size, BootImageUpdateType boot_image_update_type); Result VerifyBootImagesSafe(ncm::SystemDataId data_id, void *work_buffer, size_t work_buffer_size, BootImageUpdateType boot_image_update_type);
/* Update Prototypes. */ /* Update Prototypes. */
Result SetVerificationNeeded(BootModeType mode, bool needed, void *work_buffer, size_t work_buffer_size); Result SetVerificationNeeded(BootModeType mode, bool needed, void *work_buffer, size_t work_buffer_size);
Result UpdateBootImages(u64 data_id, BootModeType mode, void *work_buffer, size_t work_buffer_size, BootImageUpdateType boot_image_update_type); Result UpdateBootImages(ncm::SystemDataId data_id, BootModeType mode, void *work_buffer, size_t work_buffer_size, BootImageUpdateType boot_image_update_type);
Result UpdateBootImagesNormal(u64 data_id, void *work_buffer, size_t work_buffer_size, BootImageUpdateType boot_image_update_type); Result UpdateBootImagesNormal(ncm::SystemDataId data_id, void *work_buffer, size_t work_buffer_size, BootImageUpdateType boot_image_update_type);
Result UpdateBootImagesSafe(u64 data_id, void *work_buffer, size_t work_buffer_size, BootImageUpdateType boot_image_update_type); Result UpdateBootImagesSafe(ncm::SystemDataId data_id, void *work_buffer, size_t work_buffer_size, BootImageUpdateType boot_image_update_type);
/* Package helpers. */ /* Package helpers. */
Result ValidateBctFileHash(Boot0Accessor &accessor, Boot0Partition which, const void *stored_hash, void *work_buffer, size_t work_buffer_size, BootImageUpdateType boot_image_update_type); Result ValidateBctFileHash(Boot0Accessor &accessor, Boot0Partition which, const void *stored_hash, void *work_buffer, size_t work_buffer_size, BootImageUpdateType boot_image_update_type);
Result GetPackage2Hash(void *dst_hash, size_t package2_size, void *work_buffer, size_t work_buffer_size, Package2Type which); Result GetPackage2Hash(void *dst_hash, size_t package2_size, void *work_buffer, size_t work_buffer_size, Package2Type which);
Result WritePackage2(void *work_buffer, size_t work_buffer_size, Package2Type which, BootImageUpdateType boot_image_update_type); Result WritePackage2(void *work_buffer, size_t work_buffer_size, Package2Type which, BootImageUpdateType boot_image_update_type);
Result CompareHash(const void *lhs, const void *rhs, size_t size);
/* Implementations. */ /* Implementations. */
Result ValidateWorkBuffer(const void *work_buffer, size_t work_buffer_size) { Result ValidateWorkBuffer(const void *work_buffer, size_t work_buffer_size) {
@ -80,12 +81,12 @@ namespace ams::updater {
} }
} }
NcmContentMetaType GetNcmContentMetaType(BootModeType mode) { ncm::ContentMetaType GetContentMetaType(BootModeType mode) {
switch (mode) { switch (mode) {
case BootModeType::Normal: case BootModeType::Normal:
return NcmContentMetaType_BootImagePackage; return ncm::ContentMetaType::BootImagePackage;
case BootModeType::Safe: case BootModeType::Safe:
return NcmContentMetaType_BootImagePackageSafe; return ncm::ContentMetaType::BootImagePackageSafe;
AMS_UNREACHABLE_DEFAULT_CASE(); AMS_UNREACHABLE_DEFAULT_CASE();
} }
} }
@ -114,8 +115,8 @@ namespace ams::updater {
Result VerifyBootImagesAndRepairIfNeeded(bool *out_repaired, BootModeType mode, void *work_buffer, size_t work_buffer_size, BootImageUpdateType boot_image_update_type) { Result VerifyBootImagesAndRepairIfNeeded(bool *out_repaired, BootModeType mode, void *work_buffer, size_t work_buffer_size, BootImageUpdateType boot_image_update_type) {
/* Get system data id for boot images (819/81A/81B/81C). */ /* Get system data id for boot images (819/81A/81B/81C). */
u64 bip_data_id = 0; ncm::SystemDataId bip_data_id;
R_TRY(GetBootImagePackageDataId(&bip_data_id, mode, work_buffer, work_buffer_size)); R_TRY(GetBootImagePackageId(&bip_data_id, mode, work_buffer, work_buffer_size));
/* Verify the boot images in NAND. */ /* Verify the boot images in NAND. */
R_TRY_CATCH(VerifyBootImages(bip_data_id, mode, work_buffer, work_buffer_size, boot_image_update_type)) { R_TRY_CATCH(VerifyBootImages(bip_data_id, mode, work_buffer, work_buffer_size, boot_image_update_type)) {
@ -130,47 +131,40 @@ namespace ams::updater {
return SetVerificationNeeded(mode, false, work_buffer, work_buffer_size); return SetVerificationNeeded(mode, false, work_buffer, work_buffer_size);
} }
Result GetBootImagePackageDataId(u64 *out_data_id, BootModeType mode, void *work_buffer, size_t work_buffer_size) { Result GetBootImagePackageId(ncm::SystemDataId *out_data_id, BootModeType mode, void *work_buffer, size_t work_buffer_size) {
/* Ensure we can read content metas. */ /* Ensure we can read content metas. */
constexpr size_t MaxContentMetas = 0x40; constexpr size_t MaxContentMetas = 0x40;
AMS_ABORT_UNLESS(work_buffer_size >= sizeof(NcmContentMetaKey) * MaxContentMetas); AMS_ABORT_UNLESS(work_buffer_size >= sizeof(ncm::ContentMetaKey) * MaxContentMetas);
/* Open NAND System meta database, list contents. */ /* Open NAND System meta database, list contents. */
NcmContentMetaDatabase meta_db; ncm::ContentMetaDatabase db;
R_TRY(ncmOpenContentMetaDatabase(&meta_db, NcmStorageId_BuiltInSystem)); R_TRY(ncm::OpenContentMetaDatabase(std::addressof(db), ncm::StorageId::BuiltInSystem));
ON_SCOPE_EXIT { serviceClose(&meta_db.s); };
NcmContentMetaKey *records = reinterpret_cast<NcmContentMetaKey *>(work_buffer); ncm::ContentMetaKey *keys = reinterpret_cast<ncm::ContentMetaKey *>(work_buffer);
const auto content_meta_type = GetContentMetaType(mode);
const auto content_meta_type = GetNcmContentMetaType(mode); auto count = db.ListContentMeta(keys, MaxContentMetas, content_meta_type);
s32 written_entries; R_UNLESS(count.total > 0, ResultBootImagePackageNotFound());
s32 total_entries;
R_TRY(ncmContentMetaDatabaseList(&meta_db, &total_entries, &written_entries, records, MaxContentMetas * sizeof(*records), content_meta_type, 0, 0, UINT64_MAX, NcmContentInstallType_Full));
if (total_entries <= 0) {
return ResultBootImagePackageNotFound();
}
AMS_ABORT_UNLESS(total_entries == written_entries);
/* Output is sorted, return the lowest valid exfat entry. */ /* Output is sorted, return the lowest valid exfat entry. */
if (total_entries > 1) { if (count.total > 1) {
for (size_t i = 0; i < size_t(total_entries); i++) { for (auto i = 0; i < count.total; i++) {
u8 attr; u8 attr;
R_TRY(ncmContentMetaDatabaseGetAttributes(&meta_db, &records[i], &attr)); R_TRY(db.GetAttributes(std::addressof(attr), keys[i]));
if (attr & NcmContentMetaAttribute_IncludesExFatDriver) { if (attr & ncm::ContentMetaAttribute_IncludesExFatDriver) {
*out_data_id = records[i].id; out_data_id->value = keys[i].id;
return ResultSuccess(); return ResultSuccess();
} }
} }
} }
/* If there's only one entry or no exfat entries, return that entry. */ /* If there's only one entry or no exfat entries, return that entry. */
*out_data_id = records[0].id; out_data_id->value = keys[0].id;
return ResultSuccess(); return ResultSuccess();
} }
Result VerifyBootImages(u64 data_id, BootModeType mode, void *work_buffer, size_t work_buffer_size, BootImageUpdateType boot_image_update_type) { Result VerifyBootImages(ncm::SystemDataId data_id, BootModeType mode, void *work_buffer, size_t work_buffer_size, BootImageUpdateType boot_image_update_type) {
switch (mode) { switch (mode) {
case BootModeType::Normal: case BootModeType::Normal:
return VerifyBootImagesNormal(data_id, work_buffer, work_buffer_size, boot_image_update_type); return VerifyBootImagesNormal(data_id, work_buffer, work_buffer_size, boot_image_update_type);
@ -180,20 +174,22 @@ namespace ams::updater {
} }
} }
Result VerifyBootImagesNormal(u64 data_id, void *work_buffer, size_t work_buffer_size, BootImageUpdateType boot_image_update_type) { Result VerifyBootImagesNormal(ncm::SystemDataId data_id, void *work_buffer, size_t work_buffer_size, BootImageUpdateType boot_image_update_type) {
/* Ensure work buffer is big enough for us to do what we want to do. */ /* Ensure work buffer is big enough for us to do what we want to do. */
R_TRY(ValidateWorkBuffer(work_buffer, work_buffer_size)); R_TRY(ValidateWorkBuffer(work_buffer, work_buffer_size));
R_TRY_CATCH(romfsMountFromDataArchive(data_id, NcmStorageId_BuiltInSystem, GetBootImagePackageMountPath())) { /* Mount the boot image package. */
const char *mount_name = GetMountName();
R_TRY_CATCH(fs::MountSystemData(mount_name, data_id)) {
R_CONVERT(fs::ResultTargetNotFound, ResultBootImagePackageNotFound()) R_CONVERT(fs::ResultTargetNotFound, ResultBootImagePackageNotFound())
} R_END_TRY_CATCH; } R_END_TRY_CATCH;
ON_SCOPE_EXIT { R_ABORT_UNLESS(romfsUnmount(GetBootImagePackageMountPath())); }; ON_SCOPE_EXIT { fs::Unmount(mount_name); };
/* Read and validate hashes of boot images. */ /* Read and validate hashes of boot images. */
{ {
size_t size; size_t size;
u8 nand_hash[SHA256_HASH_SIZE]; u8 nand_hash[crypto::Sha256Generator::HashSize];
u8 file_hash[SHA256_HASH_SIZE]; u8 file_hash[crypto::Sha256Generator::HashSize];
Boot0Accessor boot0_accessor; Boot0Accessor boot0_accessor;
R_TRY(boot0_accessor.Initialize()); R_TRY(boot0_accessor.Initialize());
@ -209,44 +205,42 @@ namespace ams::updater {
/* Compare Package1 Normal/Sub hashes. */ /* Compare Package1 Normal/Sub hashes. */
R_TRY(GetFileHash(&size, file_hash, GetPackage1Path(boot_image_update_type), work_buffer, work_buffer_size)); R_TRY(GetFileHash(&size, file_hash, GetPackage1Path(boot_image_update_type), work_buffer, work_buffer_size));
R_TRY(boot0_accessor.GetHash(nand_hash, size, work_buffer, work_buffer_size, Boot0Partition::Package1NormalMain)); R_TRY(boot0_accessor.GetHash(nand_hash, size, work_buffer, work_buffer_size, Boot0Partition::Package1NormalMain));
if (std::memcmp(file_hash, nand_hash, SHA256_HASH_SIZE) != 0) { R_TRY(CompareHash(file_hash, nand_hash, sizeof(file_hash)));
return ResultNeedsRepairBootImages();
}
R_TRY(boot0_accessor.GetHash(nand_hash, size, work_buffer, work_buffer_size, Boot0Partition::Package1NormalSub)); R_TRY(boot0_accessor.GetHash(nand_hash, size, work_buffer, work_buffer_size, Boot0Partition::Package1NormalSub));
if (std::memcmp(file_hash, nand_hash, SHA256_HASH_SIZE) != 0) { R_TRY(CompareHash(file_hash, nand_hash, sizeof(file_hash)));
return ResultNeedsRepairBootImages();
}
/* Compare Package2 Normal/Sub hashes. */ /* Compare Package2 Normal/Sub hashes. */
R_TRY(GetFileHash(&size, file_hash, GetPackage2Path(boot_image_update_type), work_buffer, work_buffer_size)); R_TRY(GetFileHash(&size, file_hash, GetPackage2Path(boot_image_update_type), work_buffer, work_buffer_size));
R_TRY(GetPackage2Hash(nand_hash, size, work_buffer, work_buffer_size, Package2Type::NormalMain)); R_TRY(GetPackage2Hash(nand_hash, size, work_buffer, work_buffer_size, Package2Type::NormalMain));
if (std::memcmp(file_hash, nand_hash, SHA256_HASH_SIZE) != 0) { R_TRY(CompareHash(file_hash, nand_hash, sizeof(file_hash)));
return ResultNeedsRepairBootImages();
}
R_TRY(GetPackage2Hash(nand_hash, size, work_buffer, work_buffer_size, Package2Type::NormalSub)); R_TRY(GetPackage2Hash(nand_hash, size, work_buffer, work_buffer_size, Package2Type::NormalSub));
if (std::memcmp(file_hash, nand_hash, SHA256_HASH_SIZE) != 0) { R_TRY(CompareHash(file_hash, nand_hash, sizeof(file_hash)));
return ResultNeedsRepairBootImages();
}
} }
return ResultSuccess(); return ResultSuccess();
} }
Result VerifyBootImagesSafe(u64 data_id, void *work_buffer, size_t work_buffer_size, BootImageUpdateType boot_image_update_type) { Result VerifyBootImagesSafe(ncm::SystemDataId data_id, void *work_buffer, size_t work_buffer_size, BootImageUpdateType boot_image_update_type) {
/* Ensure work buffer is big enough for us to do what we want to do. */ /* Ensure work buffer is big enough for us to do what we want to do. */
R_TRY(ValidateWorkBuffer(work_buffer, work_buffer_size)); R_TRY(ValidateWorkBuffer(work_buffer, work_buffer_size));
R_TRY_CATCH(romfsMountFromDataArchive(data_id, NcmStorageId_BuiltInSystem, GetBootImagePackageMountPath())) { /* Mount the boot image package. */
const char *mount_name = GetMountName();
R_TRY_CATCH(fs::MountSystemData(mount_name, data_id)) {
R_CONVERT(fs::ResultTargetNotFound, ResultBootImagePackageNotFound()) R_CONVERT(fs::ResultTargetNotFound, ResultBootImagePackageNotFound())
} R_END_TRY_CATCH; } R_END_TRY_CATCH;
ON_SCOPE_EXIT { R_ABORT_UNLESS(romfsUnmount(GetBootImagePackageMountPath())); }; ON_SCOPE_EXIT { fs::Unmount(mount_name); };
/* Read and validate hashes of boot images. */ /* Read and validate hashes of boot images. */
{ {
size_t size; size_t size;
u8 nand_hash[SHA256_HASH_SIZE]; u8 nand_hash[crypto::Sha256Generator::HashSize];
u8 file_hash[SHA256_HASH_SIZE]; u8 file_hash[crypto::Sha256Generator::HashSize];
Boot0Accessor boot0_accessor; Boot0Accessor boot0_accessor;
R_TRY(boot0_accessor.Initialize()); R_TRY(boot0_accessor.Initialize());
@ -267,31 +261,27 @@ namespace ams::updater {
/* Compare Package1 Normal/Sub hashes. */ /* Compare Package1 Normal/Sub hashes. */
R_TRY(GetFileHash(&size, file_hash, GetPackage1Path(boot_image_update_type), work_buffer, work_buffer_size)); R_TRY(GetFileHash(&size, file_hash, GetPackage1Path(boot_image_update_type), work_buffer, work_buffer_size));
R_TRY(boot1_accessor.GetHash(nand_hash, size, work_buffer, work_buffer_size, Boot1Partition::Package1SafeMain)); R_TRY(boot1_accessor.GetHash(nand_hash, size, work_buffer, work_buffer_size, Boot1Partition::Package1SafeMain));
if (std::memcmp(file_hash, nand_hash, SHA256_HASH_SIZE) != 0) { R_TRY(CompareHash(file_hash, nand_hash, sizeof(file_hash)));
return ResultNeedsRepairBootImages();
}
R_TRY(boot1_accessor.GetHash(nand_hash, size, work_buffer, work_buffer_size, Boot1Partition::Package1SafeSub)); R_TRY(boot1_accessor.GetHash(nand_hash, size, work_buffer, work_buffer_size, Boot1Partition::Package1SafeSub));
if (std::memcmp(file_hash, nand_hash, SHA256_HASH_SIZE) != 0) { R_TRY(CompareHash(file_hash, nand_hash, sizeof(file_hash)));
return ResultNeedsRepairBootImages();
}
/* Compare Package2 Normal/Sub hashes. */ /* Compare Package2 Normal/Sub hashes. */
R_TRY(GetFileHash(&size, file_hash, GetPackage2Path(boot_image_update_type), work_buffer, work_buffer_size)); R_TRY(GetFileHash(&size, file_hash, GetPackage2Path(boot_image_update_type), work_buffer, work_buffer_size));
R_TRY(GetPackage2Hash(nand_hash, size, work_buffer, work_buffer_size, Package2Type::SafeMain)); R_TRY(GetPackage2Hash(nand_hash, size, work_buffer, work_buffer_size, Package2Type::SafeMain));
if (std::memcmp(file_hash, nand_hash, SHA256_HASH_SIZE) != 0) { R_TRY(CompareHash(file_hash, nand_hash, sizeof(file_hash)));
return ResultNeedsRepairBootImages();
}
R_TRY(GetPackage2Hash(nand_hash, size, work_buffer, work_buffer_size, Package2Type::SafeSub)); R_TRY(GetPackage2Hash(nand_hash, size, work_buffer, work_buffer_size, Package2Type::SafeSub));
if (std::memcmp(file_hash, nand_hash, SHA256_HASH_SIZE) != 0) { R_TRY(CompareHash(file_hash, nand_hash, sizeof(file_hash)));
return ResultNeedsRepairBootImages();
}
} }
return ResultSuccess(); return ResultSuccess();
} }
Result UpdateBootImages(u64 data_id, BootModeType mode, void *work_buffer, size_t work_buffer_size, BootImageUpdateType boot_image_update_type) { Result UpdateBootImages(ncm::SystemDataId data_id, BootModeType mode, void *work_buffer, size_t work_buffer_size, BootImageUpdateType boot_image_update_type) {
switch (mode) { switch (mode) {
case BootModeType::Normal: case BootModeType::Normal:
return UpdateBootImagesNormal(data_id, work_buffer, work_buffer_size, boot_image_update_type); return UpdateBootImagesNormal(data_id, work_buffer, work_buffer_size, boot_image_update_type);
@ -301,14 +291,16 @@ namespace ams::updater {
} }
} }
Result UpdateBootImagesNormal(u64 data_id, void *work_buffer, size_t work_buffer_size, BootImageUpdateType boot_image_update_type) { Result UpdateBootImagesNormal(ncm::SystemDataId data_id, void *work_buffer, size_t work_buffer_size, BootImageUpdateType boot_image_update_type) {
/* Ensure work buffer is big enough for us to do what we want to do. */ /* Ensure work buffer is big enough for us to do what we want to do. */
R_TRY(ValidateWorkBuffer(work_buffer, work_buffer_size)); R_TRY(ValidateWorkBuffer(work_buffer, work_buffer_size));
R_TRY_CATCH(romfsMountFromDataArchive(data_id, NcmStorageId_BuiltInSystem, GetBootImagePackageMountPath())) { /* Mount the boot image package. */
const char *mount_name = GetMountName();
R_TRY_CATCH(fs::MountSystemData(mount_name, data_id)) {
R_CONVERT(fs::ResultTargetNotFound, ResultBootImagePackageNotFound()) R_CONVERT(fs::ResultTargetNotFound, ResultBootImagePackageNotFound())
} R_END_TRY_CATCH; } R_END_TRY_CATCH;
ON_SCOPE_EXIT { R_ABORT_UNLESS(romfsUnmount(GetBootImagePackageMountPath())); }; ON_SCOPE_EXIT { fs::Unmount(mount_name); };
{ {
Boot0Accessor boot0_accessor; Boot0Accessor boot0_accessor;
@ -356,14 +348,16 @@ namespace ams::updater {
return ResultSuccess(); return ResultSuccess();
} }
Result UpdateBootImagesSafe(u64 data_id, void *work_buffer, size_t work_buffer_size, BootImageUpdateType boot_image_update_type) { Result UpdateBootImagesSafe(ncm::SystemDataId data_id, void *work_buffer, size_t work_buffer_size, BootImageUpdateType boot_image_update_type) {
/* Ensure work buffer is big enough for us to do what we want to do. */ /* Ensure work buffer is big enough for us to do what we want to do. */
R_TRY(ValidateWorkBuffer(work_buffer, work_buffer_size)); R_TRY(ValidateWorkBuffer(work_buffer, work_buffer_size));
R_TRY_CATCH(romfsMountFromDataArchive(data_id, NcmStorageId_BuiltInSystem, GetBootImagePackageMountPath())) { /* Mount the boot image package. */
const char *mount_name = GetMountName();
R_TRY_CATCH(fs::MountSystemData(mount_name, data_id)) {
R_CONVERT(fs::ResultTargetNotFound, ResultBootImagePackageNotFound()) R_CONVERT(fs::ResultTargetNotFound, ResultBootImagePackageNotFound())
} R_END_TRY_CATCH; } R_END_TRY_CATCH;
ON_SCOPE_EXIT { R_ABORT_UNLESS(romfsUnmount(GetBootImagePackageMountPath())); }; ON_SCOPE_EXIT { fs::Unmount(mount_name); };
{ {
Boot0Accessor boot0_accessor; Boot0Accessor boot0_accessor;
@ -450,14 +444,10 @@ namespace ams::updater {
R_TRY(accessor.PreserveAutoRcm(bct, work, which)); R_TRY(accessor.PreserveAutoRcm(bct, work, which));
} }
u8 file_hash[SHA256_HASH_SIZE]; u8 file_hash[crypto::Sha256Generator::HashSize];
sha256CalculateHash(file_hash, bct, BctSize); crypto::GenerateSha256Hash(file_hash, sizeof(file_hash), bct, BctSize);
if (std::memcmp(file_hash, stored_hash, SHA256_HASH_SIZE) != 0) { return CompareHash(file_hash, stored_hash, sizeof(file_hash));
return ResultNeedsRepairBootImages();
}
return ResultSuccess();
} }
Result GetPackage2Hash(void *dst_hash, size_t package2_size, void *work_buffer, size_t work_buffer_size, Package2Type which) { Result GetPackage2Hash(void *dst_hash, size_t package2_size, void *work_buffer, size_t work_buffer_size, Package2Type which) {
@ -476,6 +466,11 @@ namespace ams::updater {
return accessor.Write(GetPackage2Path(boot_image_update_type), work_buffer, work_buffer_size, Package2Partition::Package2); return accessor.Write(GetPackage2Path(boot_image_update_type), work_buffer, work_buffer_size, Package2Partition::Package2);
} }
Result CompareHash(const void *lhs, const void *rhs, size_t size) {
R_UNLESS(crypto::IsSameBytes(lhs, rhs, size), ResultNeedsRepairBootImages());
return ResultSuccess();
}
} }
BootImageUpdateType GetBootImageUpdateType(spl::HardwareType hw_type) { BootImageUpdateType GetBootImageUpdateType(spl::HardwareType hw_type) {
@ -508,7 +503,7 @@ namespace ams::updater {
} }
/* Get a session to ncm. */ /* Get a session to ncm. */
sm::ScopedServiceHolder<ncmInitialize, ncmExit> ncm_holder; sm::ScopedServiceHolder<ncm::Initialize, ncm::Finalize> ncm_holder;
R_ABORT_UNLESS(ncm_holder.GetResult()); R_ABORT_UNLESS(ncm_holder.GetResult());
/* Verify normal, verify safe as needed. */ /* Verify normal, verify safe as needed. */

View File

@ -18,47 +18,38 @@
namespace ams::updater { namespace ams::updater {
Result BisAccessor::Initialize() { Result BisAccessor::Initialize() {
R_TRY(fsOpenBisStorage(&this->storage, this->partition_id)); return fs::OpenBisPartition(std::addressof(this->storage), this->partition_id);
this->active = true;
return ResultSuccess();
} }
void BisAccessor::Finalize() { void BisAccessor::Finalize() {
if (this->active) { /* ... */
fsStorageClose(&this->storage);
this->active = false;
}
} }
Result BisAccessor::Read(void *dst, size_t size, u64 offset) { Result BisAccessor::Read(void *dst, size_t size, u64 offset) {
AMS_ABORT_UNLESS((offset % SectorAlignment) == 0); AMS_ABORT_UNLESS((offset % SectorAlignment) == 0);
return fsStorageRead(&this->storage, offset, dst, size); return this->storage->Read(static_cast<u32>(offset), dst, size);
} }
Result BisAccessor::Write(u64 offset, const void *src, size_t size) { Result BisAccessor::Write(u64 offset, const void *src, size_t size) {
AMS_ABORT_UNLESS((offset % SectorAlignment) == 0); AMS_ABORT_UNLESS((offset % SectorAlignment) == 0);
return fsStorageWrite(&this->storage, offset, src, size); return this->storage->Write(static_cast<u32>(offset), src, size);
} }
Result BisAccessor::Write(u64 offset, size_t size, const char *bip_path, void *work_buffer, size_t work_buffer_size) { Result BisAccessor::Write(u64 offset, size_t size, const char *bip_path, void *work_buffer, size_t work_buffer_size) {
AMS_ABORT_UNLESS((offset % SectorAlignment) == 0); AMS_ABORT_UNLESS((offset % SectorAlignment) == 0);
AMS_ABORT_UNLESS((work_buffer_size % SectorAlignment) == 0); AMS_ABORT_UNLESS((work_buffer_size % SectorAlignment) == 0);
FILE *bip_fp = fopen(bip_path, "rb"); fs::FileHandle file;
if (bip_fp == NULL) { R_TRY_CATCH(fs::OpenFile(std::addressof(file), bip_path, fs::OpenMode_Read)) {
return ResultInvalidBootImagePackage(); R_CONVERT(fs::ResultPathNotFound, ResultInvalidBootImagePackage())
} } R_END_TRY_CATCH;
ON_SCOPE_EXIT { fclose(bip_fp); }; ON_SCOPE_EXIT { fs::CloseFile(file); };
size_t written = 0; size_t written = 0;
while (true) { while (true) {
std::memset(work_buffer, 0, work_buffer_size); std::memset(work_buffer, 0, work_buffer_size);
size_t read_size = fread(work_buffer, 1, work_buffer_size, bip_fp); size_t read_size;
if (read_size != work_buffer_size) { R_TRY(fs::ReadFile(std::addressof(read_size), file, written, work_buffer, work_buffer_size, fs::ReadOption()));
if (ferror(bip_fp)) {
return fsdevGetLastResult();
}
}
AMS_ABORT_UNLESS(written + read_size <= size); AMS_ABORT_UNLESS(written + read_size <= size);
size_t aligned_size = ((read_size + SectorAlignment - 1) / SectorAlignment) * SectorAlignment; size_t aligned_size = ((read_size + SectorAlignment - 1) / SectorAlignment) * SectorAlignment;
@ -91,18 +82,19 @@ namespace ams::updater {
AMS_ABORT_UNLESS((offset % SectorAlignment) == 0); AMS_ABORT_UNLESS((offset % SectorAlignment) == 0);
AMS_ABORT_UNLESS((work_buffer_size % SectorAlignment) == 0); AMS_ABORT_UNLESS((work_buffer_size % SectorAlignment) == 0);
Sha256Context sha_ctx; crypto::Sha256Generator generator;
sha256ContextCreate(&sha_ctx); generator.Initialize();
size_t total_read = 0; size_t total_read = 0;
while (total_read < hash_size) { while (total_read < hash_size) {
size_t cur_read_size = std::min(work_buffer_size, size - total_read); size_t cur_read_size = std::min(work_buffer_size, size - total_read);
size_t cur_update_size = std::min(cur_read_size, hash_size - total_read); size_t cur_update_size = std::min(cur_read_size, hash_size - total_read);
R_TRY(this->Read(work_buffer, cur_read_size, offset + total_read)); R_TRY(this->Read(work_buffer, cur_read_size, offset + total_read));
sha256ContextUpdate(&sha_ctx, work_buffer, cur_update_size); generator.Update(work_buffer, cur_update_size);
total_read += cur_read_size; total_read += cur_read_size;
} }
sha256ContextGetHash(&sha_ctx, dst); generator.GetHash(dst, hash_size);
return ResultSuccess(); return ResultSuccess();
} }
@ -143,6 +135,7 @@ namespace ams::updater {
void *dst_pubk = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(dst_bct) + BctPubkOffset); void *dst_pubk = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(dst_bct) + BctPubkOffset);
void *src_pubk = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(work_buffer) + BctPubkOffset); void *src_pubk = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(work_buffer) + BctPubkOffset);
std::memcpy(dst_pubk, src_pubk, BctPubkSize); std::memcpy(dst_pubk, src_pubk, BctPubkSize);
return ResultSuccess(); return ResultSuccess();
} }

View File

@ -20,19 +20,14 @@
namespace ams::updater { namespace ams::updater {
class BisAccessor { class BisAccessor {
NON_COPYABLE(BisAccessor);
public: public:
static constexpr size_t SectorAlignment = 0x200; static constexpr size_t SectorAlignment = 0x200;
private: private:
FsStorage storage = {}; std::unique_ptr<fs::IStorage> storage;
FsBisPartitionId partition_id; const fs::BisPartitionId partition_id;
bool active;
public: public:
BisAccessor(FsBisPartitionId id) : partition_id(id), active(false) { } explicit BisAccessor(fs::BisPartitionId id) : partition_id(id) { /* ... */ }
~BisAccessor() {
if (this->active) {
fsStorageClose(&storage);
}
}
public: public:
Result Initialize(); Result Initialize();
@ -121,11 +116,12 @@ namespace ams::updater {
template<typename Meta> template<typename Meta>
class PartitionAccessor : public BisAccessor { class PartitionAccessor : public BisAccessor {
NON_COPYABLE(PartitionAccessor);
public: public:
using EnumType = typename Meta::EnumType; using EnumType = typename Meta::EnumType;
using OffsetSizeType = typename Meta::OffsetSizeType; using OffsetSizeType = typename Meta::OffsetSizeType;
public: public:
PartitionAccessor(FsBisPartitionId id) : BisAccessor(id) { } explicit PartitionAccessor(fs::BisPartitionId id) : BisAccessor(id) { /* ... */ }
private: private:
constexpr const OffsetSizeType *FindEntry(EnumType which) { constexpr const OffsetSizeType *FindEntry(EnumType which) {
const OffsetSizeType *entry = nullptr; const OffsetSizeType *entry = nullptr;
@ -182,27 +178,27 @@ namespace ams::updater {
RepairSub, RepairSub,
}; };
static constexpr FsBisPartitionId GetPackage2StorageId(Package2Type which) { static constexpr fs::BisPartitionId GetPackage2StorageId(Package2Type which) {
switch (which) { switch (which) {
case Package2Type::NormalMain: case Package2Type::NormalMain:
return FsBisPartitionId_BootConfigAndPackage2Part1; return fs::BisPartitionId::BootConfigAndPackage2Part1;
case Package2Type::NormalSub: case Package2Type::NormalSub:
return FsBisPartitionId_BootConfigAndPackage2Part2; return fs::BisPartitionId::BootConfigAndPackage2Part2;
case Package2Type::SafeMain: case Package2Type::SafeMain:
return FsBisPartitionId_BootConfigAndPackage2Part3; return fs::BisPartitionId::BootConfigAndPackage2Part3;
case Package2Type::SafeSub: case Package2Type::SafeSub:
return FsBisPartitionId_BootConfigAndPackage2Part4; return fs::BisPartitionId::BootConfigAndPackage2Part4;
case Package2Type::RepairMain: case Package2Type::RepairMain:
return FsBisPartitionId_BootConfigAndPackage2Part5; return fs::BisPartitionId::BootConfigAndPackage2Part5;
case Package2Type::RepairSub: case Package2Type::RepairSub:
return FsBisPartitionId_BootConfigAndPackage2Part6; return fs::BisPartitionId::BootConfigAndPackage2Part6;
AMS_UNREACHABLE_DEFAULT_CASE(); AMS_UNREACHABLE_DEFAULT_CASE();
} }
} }
class Boot0Accessor : public PartitionAccessor<Boot0Meta> { class Boot0Accessor : public PartitionAccessor<Boot0Meta> {
public: public:
static constexpr FsBisPartitionId PartitionId = FsBisPartitionId_BootPartition1Root; static constexpr fs::BisPartitionId PartitionId = fs::BisPartitionId::BootPartition1Root;
static constexpr size_t BctPubkOffset = 0x210; static constexpr size_t BctPubkOffset = 0x210;
static constexpr size_t BctPubkSize = 0x100; static constexpr size_t BctPubkSize = 0x100;
static constexpr size_t BctEksOffset = 0x450; static constexpr size_t BctEksOffset = 0x450;
@ -222,7 +218,7 @@ namespace ams::updater {
class Boot1Accessor : public PartitionAccessor<Boot1Meta> { class Boot1Accessor : public PartitionAccessor<Boot1Meta> {
public: public:
static constexpr FsBisPartitionId PartitionId = FsBisPartitionId_BootPartition2Root; static constexpr fs::BisPartitionId PartitionId = fs::BisPartitionId::BootPartition2Root;
public: public:
Boot1Accessor() : PartitionAccessor<Boot1Meta>(PartitionId) { } Boot1Accessor() : PartitionAccessor<Boot1Meta>(PartitionId) { }
}; };

View File

@ -18,49 +18,43 @@
namespace ams::updater { namespace ams::updater {
Result ReadFile(size_t *out_size, void *dst, size_t dst_size, const char *path) { Result ReadFile(size_t *out_size, void *dst, size_t dst_size, const char *path) {
FILE *fp = fopen(path, "rb"); /* Open the file. */
if (fp == NULL) { fs::FileHandle file;
return ResultInvalidBootImagePackage(); R_TRY_CATCH(fs::OpenFile(std::addressof(file), path, fs::OpenMode_Read)) {
} R_CONVERT(fs::ResultPathNotFound, ResultInvalidBootImagePackage())
ON_SCOPE_EXIT { fclose(fp); }; } R_END_TRY_CATCH;
ON_SCOPE_EXIT { fs::CloseFile(file); };
std::memset(dst, 0, dst_size); std::memset(dst, 0, dst_size);
size_t read_size = fread(dst, 1, dst_size, fp); return fs::ReadFile(out_size, file, 0, dst, dst_size, fs::ReadOption());
if (ferror(fp)) {
return fsdevGetLastResult();
}
*out_size = read_size;
return ResultSuccess();
} }
Result GetFileHash(size_t *out_size, void *dst_hash, const char *path, void *work_buffer, size_t work_buffer_size) { Result GetFileHash(size_t *out_size, void *dst_hash, const char *path, void *work_buffer, size_t work_buffer_size) {
FILE *fp = fopen(path, "rb"); /* Open the file. */
if (fp == NULL) { fs::FileHandle file;
return ResultInvalidBootImagePackage(); R_TRY_CATCH(fs::OpenFile(std::addressof(file), path, fs::OpenMode_Read)) {
} R_CONVERT(fs::ResultPathNotFound, ResultInvalidBootImagePackage())
ON_SCOPE_EXIT { fclose(fp); }; } R_END_TRY_CATCH;
ON_SCOPE_EXIT { fs::CloseFile(file); };
Sha256Context sha_ctx; /* Read in chunks, hashing as we go. */
sha256ContextCreate(&sha_ctx); crypto::Sha256Generator generator;
generator.Initialize();
size_t total_size = 0; size_t total_size = 0;
while (true) { while (true) {
size_t read_size = fread(work_buffer, 1, work_buffer_size, fp); size_t size;
if (ferror(fp)) { R_TRY(fs::ReadFile(std::addressof(size), file, total_size, work_buffer, work_buffer_size, fs::ReadOption()));
return fsdevGetLastResult();
}
if (read_size == 0) {
break;
}
sha256ContextUpdate(&sha_ctx, work_buffer, read_size); generator.Update(work_buffer, size);
total_size += read_size; total_size += size;
if (read_size != work_buffer_size) {
if (size != work_buffer_size) {
break; break;
} }
} }
sha256ContextGetHash(&sha_ctx, dst_hash); generator.GetHash(dst_hash, crypto::Sha256Generator::HashSize);
*out_size = total_size; *out_size = total_size;
return ResultSuccess(); return ResultSuccess();
} }

View File

@ -13,7 +13,6 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <sys/stat.h>
#include "updater_paths.hpp" #include "updater_paths.hpp"
namespace ams::updater { namespace ams::updater {
@ -21,7 +20,7 @@ namespace ams::updater {
namespace { namespace {
/* Actual paths. */ /* Actual paths. */
constexpr const char *BootImagePackageMountPath = "bip"; constexpr const char *BootImagePackageMountName = "bip";
constexpr const char *BctPathNx = "bip:/nx/bct"; constexpr const char *BctPathNx = "bip:/nx/bct";
constexpr const char *Package1PathNx = "bip:/nx/package1"; constexpr const char *Package1PathNx = "bip:/nx/package1";
constexpr const char *Package2PathNx = "bip:/nx/package2"; constexpr const char *Package2PathNx = "bip:/nx/package2";
@ -33,12 +32,12 @@ namespace ams::updater {
AMS_ABORT_UNLESS(num_candidates > 0); AMS_ABORT_UNLESS(num_candidates > 0);
for (size_t i = 0; i < num_candidates; i++) { for (size_t i = 0; i < num_candidates; i++) {
struct stat buf; fs::DirectoryEntryType type;
if (stat(candidates[i], &buf) != 0) { if (R_FAILED(fs::GetEntryType(std::addressof(type), candidates[i]))) {
continue; continue;
} }
if (!S_ISREG(buf.st_mode)) { if (type != fs::DirectoryEntryType_File) {
continue; continue;
} }
@ -51,8 +50,8 @@ namespace ams::updater {
} }
const char *GetBootImagePackageMountPath() { const char *GetMountName() {
return BootImagePackageMountPath; return BootImagePackageMountName;
} }

View File

@ -19,7 +19,7 @@
namespace ams::updater { namespace ams::updater {
/* Path functionality. */ /* Path functionality. */
const char *GetBootImagePackageMountPath(); const char *GetMountName();
const char *GetBctPath(BootImageUpdateType boot_image_update_type); const char *GetBctPath(BootImageUpdateType boot_image_update_type);
const char *GetPackage1Path(BootImageUpdateType boot_image_update_type); const char *GetPackage1Path(BootImageUpdateType boot_image_update_type);
const char *GetPackage2Path(BootImageUpdateType boot_image_update_type); const char *GetPackage2Path(BootImageUpdateType boot_image_update_type);