1
0
Fork 0
mirror of https://github.com/DarkMatterCore/nxdumptool.git synced 2024-11-26 12:12:02 +00:00

Fix Patch RomFS ctx init w/missing base NCA FS.

This bug was introduced in c474435ea8.

Other changes include:

* nxdt_rw_poc, bktr: minor cosmetic code changes.
* cnmt: add ContentMetaPlatform enum.
This commit is contained in:
Pablo Curiel 2023-10-12 11:24:03 +02:00
parent bb4608118d
commit ecaeddf356
7 changed files with 44 additions and 28 deletions

View file

@ -934,7 +934,7 @@ int main(int argc, char *argv[])
} }
consoleClear(); consoleClear();
consolePrint(APP_TITLE " v" APP_VERSION " (" GIT_REV "). Built on " BUILD_TIMESTAMP ".\n"); consolePrint(APP_TITLE " v" APP_VERSION " (" GIT_REV ").\nBuilt on " BUILD_TIMESTAMP ".\n");
consolePrint("______________________________\n\n"); consolePrint("______________________________\n\n");
if (cur_menu->parent) consolePrint("press b to go back\n"); if (cur_menu->parent) consolePrint("press b to go back\n");
if (g_umsDeviceCount) consolePrint("press x to safely remove all ums devices\n"); if (g_umsDeviceCount) consolePrint("press x to safely remove all ums devices\n");

View file

@ -41,6 +41,11 @@ typedef enum {
ContentMetaAttribute_Count = 3 ///< Total values supported by this enum. ContentMetaAttribute_Count = 3 ///< Total values supported by this enum.
} ContentMetaAttribute; } ContentMetaAttribute;
typedef enum {
ContentMetaPlatform_Nx = 0,
ContentMetaPlatform_Count = 1 ///< Total values supported by this enum.
} ContentMetaPlatform;
typedef enum { typedef enum {
ContentMetaInstallState_None = 0, ContentMetaInstallState_None = 0,
ContentMetaInstallState_Committed = BIT(0), ContentMetaInstallState_Committed = BIT(0),
@ -56,7 +61,7 @@ typedef struct {
u64 title_id; u64 title_id;
Version version; Version version;
u8 content_meta_type; ///< NcmContentMetaType. u8 content_meta_type; ///< NcmContentMetaType.
u8 reserved_1; u8 content_meta_platform; ///< ContentMetaPlatform.
u16 extended_header_size; ///< Must match the size from the extended header struct for this content meta type (SystemUpdate, Application, Patch, AddOnContent, Delta). u16 extended_header_size; ///< Must match the size from the extended header struct for this content meta type (SystemUpdate, Application, Patch, AddOnContent, Delta).
u16 content_count; ///< Determines how many NcmPackagedContentInfo entries are available after the extended header. u16 content_count; ///< Determines how many NcmPackagedContentInfo entries are available after the extended header.
u16 content_meta_count; ///< Determines how many NcmContentMetaInfo entries are available after the NcmPackagedContentInfo entries. Only used for SystemUpdate. u16 content_meta_count; ///< Determines how many NcmContentMetaInfo entries are available after the NcmPackagedContentInfo entries. Only used for SystemUpdate.
@ -65,7 +70,7 @@ typedef struct {
u8 content_install_type; ///< NcmContentInstallType. u8 content_install_type; ///< NcmContentInstallType.
u8 install_state; ///< ContentMetaInstallState. u8 install_state; ///< ContentMetaInstallState.
Version required_download_system_version; Version required_download_system_version;
u8 reserved_2[0x4]; u8 reserved[0x4];
} ContentMetaPackagedContentMetaHeader; } ContentMetaPackagedContentMetaHeader;
NXDT_ASSERT(ContentMetaPackagedContentMetaHeader, 0x20); NXDT_ASSERT(ContentMetaPackagedContentMetaHeader, 0x20);

View file

@ -50,9 +50,8 @@ typedef struct {
} NcaStorageContext; } NcaStorageContext;
/// Initializes a NCA storage context using a NCA FS section context, optionally providing a pointer to a base NcaStorageContext. /// Initializes a NCA storage context using a NCA FS section context, optionally providing a pointer to a base NcaStorageContext.
/// 'base_ctx' must be provided if dealing with a patch NCA. One of its storages will be set as the original substorage for the initialized NcaStorageContext's Indirect Storage. /// 'base_ctx' shall be provided if dealing with a patch NCA with available base NCA data. This is needed to perform combined reads between a base NCA and a patch NCA.
/// This is needed to perform combined reads between a base NCA and a patch NCA. /// 'base_ctx' shall be NULL if dealing with a base NCA *or* a patch NCA with missing base NCA data.
/// 'base_ctx' shall be NULL if dealing with a base NCA.
bool ncaStorageInitializeContext(NcaStorageContext *out, NcaFsSectionContext *nca_fs_ctx, NcaStorageContext *base_ctx); bool ncaStorageInitializeContext(NcaStorageContext *out, NcaFsSectionContext *nca_fs_ctx, NcaStorageContext *base_ctx);
/// Retrieves the underlying NCA FS section's hierarchical hash target layer extents. Virtual extents may be returned, depending on the base storage type. /// Retrieves the underlying NCA FS section's hierarchical hash target layer extents. Virtual extents may be returned, depending on the base storage type.

View file

@ -1138,8 +1138,8 @@ static bool bktrReadCompressedStorage(BucketTreeVisitor *visitor, void *out, u64
} }
/* Decompress LZ4 block. */ /* Decompress LZ4 block. */
int lz4_res = 0; int lz4_res = LZ4_decompress_safe((char*)read_ptr, (char*)buffer, (int)compressed_data_size, (int)buffer_size);
if ((lz4_res = LZ4_decompress_safe((char*)read_ptr, (char*)buffer, (int)compressed_data_size, (int)buffer_size)) != (int)decompressed_data_size) if (lz4_res != (int)decompressed_data_size)
{ {
LOG_MSG_ERROR("Failed to decompress 0x%lX-byte long compressed block! (%d).", compressed_data_size, lz4_res); LOG_MSG_ERROR("Failed to decompress 0x%lX-byte long compressed block! (%d).", compressed_data_size, lz4_res);
free(buffer); free(buffer);

View file

@ -146,6 +146,12 @@ bool cnmtInitializeContext(ContentMetaContext *out, NcaContext *nca_ctx)
goto end; goto end;
} }
if (out->packaged_header->content_meta_platform >= ContentMetaPlatform_Count)
{
LOG_MSG_ERROR("Invalid platform!");
goto end;
}
if (!out->packaged_header->content_count && out->packaged_header->content_meta_type != NcmContentMetaType_SystemUpdate) if (!out->packaged_header->content_count && out->packaged_header->content_meta_type != NcmContentMetaType_SystemUpdate)
{ {
LOG_MSG_ERROR("Invalid content count!"); LOG_MSG_ERROR("Invalid content count!");

View file

@ -25,13 +25,13 @@
/* Function prototypes. */ /* Function prototypes. */
static bool ncaStorageInitializeBucketTreeContext(BucketTreeContext **out, NcaFsSectionContext *nca_fs_ctx, u8 storage_type); static bool ncaStorageInitializeBucketTreeContext(BucketTreeContext **out, NcaFsSectionContext *nca_fs_ctx, u8 storage_type);
static bool ncaStorageSetPatchOriginalSubStorage(NcaStorageContext *patch_ctx, NcaFsSectionContext *patch_nca_fs_ctx, NcaStorageContext *base_ctx); static bool ncaStorageSetPatchOriginalSubStorage(NcaStorageContext *patch_ctx, NcaStorageContext *base_ctx);
static bool ncaStorageInitializeCompressedStorageBucketTreeContext(NcaStorageContext *out, NcaFsSectionContext *nca_fs_ctx); static bool ncaStorageInitializeCompressedStorageBucketTreeContext(NcaStorageContext *out, NcaFsSectionContext *nca_fs_ctx);
bool ncaStorageInitializeContext(NcaStorageContext *out, NcaFsSectionContext *nca_fs_ctx, NcaStorageContext *base_ctx) bool ncaStorageInitializeContext(NcaStorageContext *out, NcaFsSectionContext *nca_fs_ctx, NcaStorageContext *base_ctx)
{ {
if (!out || !nca_fs_ctx || !nca_fs_ctx->enabled || (nca_fs_ctx->section_type == NcaFsSectionType_PatchRomFs && \ if (!out || !nca_fs_ctx || !nca_fs_ctx->enabled || (nca_fs_ctx->section_type == NcaFsSectionType_PatchRomFs && \
(!nca_fs_ctx->has_patch_indirect_layer || !nca_fs_ctx->has_patch_aes_ctr_ex_layer || nca_fs_ctx->has_sparse_layer || !base_ctx))) (!nca_fs_ctx->has_patch_indirect_layer || !nca_fs_ctx->has_patch_aes_ctr_ex_layer || nca_fs_ctx->has_sparse_layer)))
{ {
LOG_MSG_ERROR("Invalid parameters!"); LOG_MSG_ERROR("Invalid parameters!");
return false; return false;
@ -61,7 +61,7 @@ bool ncaStorageInitializeContext(NcaStorageContext *out, NcaFsSectionContext *nc
/* Check if both Indirect and AesCtrEx layers are available. */ /* Check if both Indirect and AesCtrEx layers are available. */
if (nca_fs_ctx->section_type == NcaFsSectionType_PatchRomFs) if (nca_fs_ctx->section_type == NcaFsSectionType_PatchRomFs)
{ {
/* Initialize AesCtrEx and Indirect layers. */ /* Initialize AesCtrEx layer. */
if (!ncaStorageInitializeBucketTreeContext(&(out->aes_ctr_ex_storage), nca_fs_ctx, BucketTreeStorageType_AesCtrEx) || \ if (!ncaStorageInitializeBucketTreeContext(&(out->aes_ctr_ex_storage), nca_fs_ctx, BucketTreeStorageType_AesCtrEx) || \
!ncaStorageInitializeBucketTreeContext(&(out->indirect_storage), nca_fs_ctx, BucketTreeStorageType_Indirect)) goto end; !ncaStorageInitializeBucketTreeContext(&(out->indirect_storage), nca_fs_ctx, BucketTreeStorageType_Indirect)) goto end;
@ -69,8 +69,8 @@ bool ncaStorageInitializeContext(NcaStorageContext *out, NcaFsSectionContext *nc
if (!bktrSetRegularSubStorage(out->aes_ctr_ex_storage, nca_fs_ctx)) goto end; if (!bktrSetRegularSubStorage(out->aes_ctr_ex_storage, nca_fs_ctx)) goto end;
/* Set Indirect layer's substorages (Base + AesCtrEx). */ /* Set Indirect layer's substorages (Base + AesCtrEx). */
if (!ncaStorageSetPatchOriginalSubStorage(out, nca_fs_ctx, base_ctx)) goto end; if (!ncaStorageSetPatchOriginalSubStorage(out, base_ctx) || \
if (!bktrSetBucketTreeSubStorage(out->indirect_storage, out->aes_ctr_ex_storage, 1)) goto end; !bktrSetBucketTreeSubStorage(out->indirect_storage, out->aes_ctr_ex_storage, 1)) goto end;
/* Update base storage type. */ /* Update base storage type. */
out->base_storage_type = NcaStorageBaseStorageType_Indirect; out->base_storage_type = NcaStorageBaseStorageType_Indirect;
@ -261,21 +261,27 @@ end:
return success; return success;
} }
static bool ncaStorageSetPatchOriginalSubStorage(NcaStorageContext *patch_ctx, NcaFsSectionContext *patch_nca_fs_ctx, NcaStorageContext *base_ctx) static bool ncaStorageSetPatchOriginalSubStorage(NcaStorageContext *patch_ctx, NcaStorageContext *base_ctx)
{ {
NcaFsSectionContext *patch_nca_fs_ctx = NULL, *base_nca_fs_ctx = NULL;
NcaContext *patch_nca_ctx = NULL, *base_nca_ctx = NULL; NcaContext *patch_nca_ctx = NULL, *base_nca_ctx = NULL;
if (!patch_ctx || !patch_ctx->indirect_storage || !patch_ctx->aes_ctr_ex_storage || !patch_nca_fs_ctx || !ncaStorageIsValidContext(base_ctx) || \ bool missing_base_ctx = !ncaStorageIsValidContext(base_ctx);
!(patch_nca_ctx = patch_nca_fs_ctx->nca_ctx) || !(base_nca_ctx = base_ctx->nca_fs_ctx->nca_ctx) || \
patch_nca_fs_ctx->section_type != NcaFsSectionType_PatchRomFs || base_ctx->nca_fs_ctx->section_type != NcaFsSectionType_RomFs || \ bool success = false;
if (!patch_ctx || !patch_ctx->indirect_storage || !patch_ctx->aes_ctr_ex_storage || !(patch_nca_fs_ctx = patch_ctx->indirect_storage->nca_fs_ctx) || \
patch_nca_fs_ctx->section_type != NcaFsSectionType_PatchRomFs || !(patch_nca_ctx = patch_nca_fs_ctx->nca_ctx) || \
(!missing_base_ctx && (!(base_nca_fs_ctx = base_ctx->nca_fs_ctx) || base_nca_fs_ctx->section_type != NcaFsSectionType_RomFs || !(base_nca_ctx = base_nca_fs_ctx->nca_ctx) || \
patch_nca_ctx->header.program_id != base_nca_ctx->header.program_id || patch_nca_ctx->header.content_type != base_nca_ctx->header.content_type || \ patch_nca_ctx->header.program_id != base_nca_ctx->header.program_id || patch_nca_ctx->header.content_type != base_nca_ctx->header.content_type || \
patch_nca_ctx->id_offset != base_nca_ctx->id_offset || patch_nca_ctx->title_version.value < base_nca_ctx->title_version.value) patch_nca_ctx->id_offset != base_nca_ctx->id_offset || patch_nca_ctx->title_version.value < base_nca_ctx->title_version.value)))
{ {
LOG_MSG_ERROR("Invalid parameters!"); LOG_MSG_ERROR("Invalid parameters!");
return false; return false;
} }
bool success = false; /* Return immediately if we passed all patch context checks, but we're missing a base context. */
if (missing_base_ctx) return true;
/* Set original substorage. */ /* Set original substorage. */
switch(base_ctx->base_storage_type) switch(base_ctx->base_storage_type)

View file

@ -66,7 +66,7 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *base
if (patch_nca_fs_ctx) if (patch_nca_fs_ctx)
{ {
/* Initialize base NCA storage context. */ /* Initialize base NCA storage context. */
if (!ncaStorageInitializeContext(patch_storage_ctx, patch_nca_fs_ctx, base_storage_ctx)) if (!ncaStorageInitializeContext(patch_storage_ctx, patch_nca_fs_ctx, missing_base_romfs ? NULL : base_storage_ctx))
{ {
LOG_MSG_ERROR("Failed to initialize patch NCA storage context!"); LOG_MSG_ERROR("Failed to initialize patch NCA storage context!");
goto end; goto end;