2020-10-08 22:52:31 +01:00
/*
* npdm . c
*
2022-03-17 12:58:40 +00:00
* Copyright ( c ) 2020 - 2022 , DarkMatterCore < pabloacurielz @ gmail . com > .
2020-10-08 22:52:31 +01:00
*
* This file is part of nxdumptool ( https : //github.com/DarkMatterCore/nxdumptool).
*
2021-03-25 19:26:58 +00:00
* nxdumptool is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
2020-10-08 22:52:31 +01:00
*
2021-03-25 19:26:58 +00:00
* nxdumptool is distributed in the hope that 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 .
2020-10-08 22:52:31 +01:00
*
* You should have received a copy of the GNU General Public License
2021-03-25 19:26:58 +00:00
* along with this program . If not , see < https : //www.gnu.org/licenses/>.
2020-10-08 22:52:31 +01:00
*/
2021-03-26 04:35:14 +00:00
# include "nxdt_utils.h"
2020-10-08 22:52:31 +01:00
# include "npdm.h"
2020-10-10 22:08:17 +01:00
# include "rsa.h"
2020-10-08 22:52:31 +01:00
2020-10-10 20:29:14 +01:00
bool npdmInitializeContext ( NpdmContext * out , PartitionFileSystemContext * pfs_ctx )
{
NcaContext * nca_ctx = NULL ;
u64 cur_offset = 0 ;
2021-03-07 23:22:49 +00:00
bool success = false , dump_meta_header = false , dump_acid_header = false , dump_aci_header = false ;
2022-06-26 02:34:31 +01:00
PartitionFileSystemEntry * pfs_entry = NULL ;
2022-07-05 02:04:28 +01:00
2022-07-04 01:20:51 +01:00
if ( ! out | | ! pfs_ctx | | ! ncaStorageIsValidContext ( & ( pfs_ctx - > storage_ctx ) ) | | ! ( nca_ctx = ( NcaContext * ) pfs_ctx - > nca_fs_ctx - > nca_ctx ) | | \
2022-07-04 00:36:01 +01:00
nca_ctx - > content_type ! = NcmContentType_Program | | ! pfs_ctx - > offset | | ! pfs_ctx - > size | | ! pfs_ctx - > is_exefs | | \
pfs_ctx - > header_size < = sizeof ( PartitionFileSystemHeader ) | | ! pfs_ctx - > header )
2020-10-10 20:29:14 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid parameters! " ) ;
2020-10-10 20:29:14 +01:00
return false ;
}
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
/* Free output context beforehand. */
npdmFreeContext ( out ) ;
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
/* Get 'main.npdm' file entry. */
2022-06-26 02:34:31 +01:00
if ( ! ( pfs_entry = pfsGetEntryByName ( pfs_ctx , " main.npdm " ) ) )
2020-10-10 20:29:14 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " 'main.npdm' entry unavailable in ExeFS! " ) ;
2020-10-10 20:29:14 +01:00
goto end ;
}
2022-07-05 02:04:28 +01:00
2022-07-12 17:34:49 +01:00
LOG_MSG_INFO ( " Found 'main.npdm' entry in Program NCA \" %s \" . " , nca_ctx - > content_id_str ) ;
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
/* Check raw NPDM size. */
2022-06-26 02:34:31 +01:00
if ( ! pfs_entry - > size )
2020-10-10 20:29:14 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid raw NPDM size! " ) ;
2020-10-10 20:29:14 +01:00
goto end ;
}
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
/* Allocate memory for the raw NPDM data. */
2022-06-26 02:34:31 +01:00
out - > raw_data_size = pfs_entry - > size ;
2020-10-10 20:29:14 +01:00
if ( ! ( out - > raw_data = malloc ( out - > raw_data_size ) ) )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Failed to allocate memory for the raw NPDM data! " ) ;
2020-10-10 20:29:14 +01:00
goto end ;
}
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
/* Read raw NPDM data into memory buffer. */
2022-06-26 02:34:31 +01:00
if ( ! pfsReadEntryData ( pfs_ctx , pfs_entry , out - > raw_data , out - > raw_data_size , 0 ) )
2020-10-10 20:29:14 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Failed to read raw NPDM data! " ) ;
2020-10-10 20:29:14 +01:00
goto end ;
}
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
/* Verify meta header. */
out - > meta_header = ( NpdmMetaHeader * ) out - > raw_data ;
cur_offset + = sizeof ( NpdmMetaHeader ) ;
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
if ( __builtin_bswap32 ( out - > meta_header - > magic ) ! = NPDM_META_MAGIC )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid meta header magic word! (0x%08X != 0x%08X). " , __builtin_bswap32 ( out - > meta_header - > magic ) , __builtin_bswap32 ( NPDM_META_MAGIC ) ) ;
2021-03-07 23:22:49 +00:00
dump_meta_header = true ;
2020-10-10 20:29:14 +01:00
goto end ;
}
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
if ( ! out - > meta_header - > flags . is_64bit_instruction & & ( out - > meta_header - > flags . process_address_space = = NpdmProcessAddressSpace_AddressSpace64BitOld | | \
out - > meta_header - > flags . process_address_space = = NpdmProcessAddressSpace_AddressSpace64Bit ) )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid meta header flags! (0x%02X). " , * ( ( u8 * ) & ( out - > meta_header - > flags ) ) ) ;
2021-03-07 23:22:49 +00:00
dump_meta_header = true ;
2020-10-10 20:29:14 +01:00
goto end ;
}
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
if ( out - > meta_header - > main_thread_priority > NPDM_MAIN_THREAD_MAX_PRIORITY )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid main thread priority! (0x%02X). " , out - > meta_header - > main_thread_priority ) ;
2021-03-07 23:22:49 +00:00
dump_meta_header = true ;
2020-10-10 20:29:14 +01:00
goto end ;
}
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
if ( out - > meta_header - > main_thread_core_number > NPDM_MAIN_THREAD_MAX_CORE_NUMBER )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid main thread core number! (%u). " , out - > meta_header - > main_thread_core_number ) ;
2021-03-07 23:22:49 +00:00
dump_meta_header = true ;
2020-10-10 20:29:14 +01:00
goto end ;
}
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
if ( out - > meta_header - > system_resource_size > NPDM_SYSTEM_RESOURCE_MAX_SIZE )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid system resource size! (0x%X). " , out - > meta_header - > system_resource_size ) ;
2021-03-07 23:22:49 +00:00
dump_meta_header = true ;
2020-10-10 20:29:14 +01:00
goto end ;
}
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
if ( ! IS_ALIGNED ( out - > meta_header - > main_thread_stack_size , NPDM_MAIN_THREAD_STACK_SIZE_ALIGNMENT ) )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid main thread stack size! (0x%X). " , out - > meta_header - > main_thread_stack_size ) ;
2021-03-07 23:22:49 +00:00
dump_meta_header = true ;
2020-10-10 20:29:14 +01:00
goto end ;
}
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
if ( out - > meta_header - > aci_offset < sizeof ( NpdmMetaHeader ) | | out - > meta_header - > aci_size < sizeof ( NpdmAciHeader ) | | ( out - > meta_header - > aci_offset + out - > meta_header - > aci_size ) > out - > raw_data_size )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid ACI0 offset/size! (0x%X, 0x%X). " , out - > meta_header - > aci_offset , out - > meta_header - > aci_size ) ;
2021-03-07 23:22:49 +00:00
dump_meta_header = true ;
2020-10-10 20:29:14 +01:00
goto end ;
}
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
if ( out - > meta_header - > acid_offset < sizeof ( NpdmMetaHeader ) | | out - > meta_header - > acid_size < sizeof ( NpdmAcidHeader ) | | ( out - > meta_header - > acid_offset + out - > meta_header - > acid_size ) > out - > raw_data_size )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid ACID offset/size! (0x%X, 0x%X). " , out - > meta_header - > acid_offset , out - > meta_header - > acid_size ) ;
2021-03-07 23:22:49 +00:00
dump_meta_header = true ;
2020-10-10 20:29:14 +01:00
goto end ;
}
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
if ( out - > meta_header - > aci_offset = = out - > meta_header - > acid_offset | | \
( out - > meta_header - > aci_offset > out - > meta_header - > acid_offset & & out - > meta_header - > aci_offset < ( out - > meta_header - > acid_offset + out - > meta_header - > acid_size ) ) | | \
( out - > meta_header - > acid_offset > out - > meta_header - > aci_offset & & out - > meta_header - > acid_offset < ( out - > meta_header - > aci_offset + out - > meta_header - > aci_size ) ) )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " ACI0/ACID sections overlap! (0x%X, 0x%X | 0x%X, 0x%X). " , out - > meta_header - > aci_offset , out - > meta_header - > aci_size , out - > meta_header - > acid_offset , out - > meta_header - > acid_size ) ;
2021-03-07 23:22:49 +00:00
dump_meta_header = true ;
2020-10-10 20:29:14 +01:00
goto end ;
}
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
/* Verify ACID section. */
out - > acid_header = ( NpdmAcidHeader * ) ( out - > raw_data + out - > meta_header - > acid_offset ) ;
cur_offset + = out - > meta_header - > acid_size ;
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
if ( __builtin_bswap32 ( out - > acid_header - > magic ) ! = NPDM_ACID_MAGIC )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid ACID header magic word! (0x%08X != 0x%08X). " , __builtin_bswap32 ( out - > acid_header - > magic ) , __builtin_bswap32 ( NPDM_ACID_MAGIC ) ) ;
2021-03-07 23:22:49 +00:00
dump_meta_header = dump_acid_header = true ;
2020-10-10 20:29:14 +01:00
goto end ;
}
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
if ( out - > acid_header - > size ! = ( out - > meta_header - > acid_size - sizeof ( out - > acid_header - > signature ) ) )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid ACID header size! (0x%X). " , out - > acid_header - > size ) ;
2021-03-07 23:22:49 +00:00
dump_meta_header = dump_acid_header = true ;
2020-10-10 20:29:14 +01:00
goto end ;
}
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
if ( out - > acid_header - > program_id_min > out - > acid_header - > program_id_max )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid ACID program ID range! (%016lX - %016lX). " , out - > acid_header - > program_id_min , out - > acid_header - > program_id_max ) ;
2021-03-07 23:22:49 +00:00
dump_meta_header = dump_acid_header = true ;
2020-10-10 20:29:14 +01:00
goto end ;
}
2022-07-05 02:04:28 +01:00
2020-10-13 15:00:03 +01:00
if ( out - > acid_header - > fs_access_control_offset < sizeof ( NpdmAcidHeader ) | | out - > acid_header - > fs_access_control_size < sizeof ( NpdmFsAccessControlDescriptor ) | | \
2020-10-10 20:29:14 +01:00
( out - > acid_header - > fs_access_control_offset + out - > acid_header - > fs_access_control_size ) > out - > meta_header - > acid_size )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid ACID FsAccessControl offset/size! (0x%X, 0x%X). " , out - > acid_header - > fs_access_control_offset , out - > acid_header - > fs_access_control_size ) ;
2021-03-07 23:22:49 +00:00
dump_meta_header = dump_acid_header = true ;
2020-10-10 20:29:14 +01:00
goto end ;
}
2022-07-05 02:04:28 +01:00
2020-10-13 15:00:03 +01:00
out - > acid_fac_descriptor = ( NpdmFsAccessControlDescriptor * ) ( out - > raw_data + out - > meta_header - > acid_offset + out - > acid_header - > fs_access_control_offset ) ;
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
if ( out - > acid_header - > srv_access_control_size )
{
if ( out - > acid_header - > srv_access_control_offset < sizeof ( NpdmAcidHeader ) | | \
( out - > acid_header - > srv_access_control_offset + out - > acid_header - > srv_access_control_size ) > out - > meta_header - > acid_size )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid ACID SrvAccessControl offset/size! (0x%X, 0x%X). " , out - > acid_header - > srv_access_control_offset , out - > acid_header - > srv_access_control_size ) ;
2021-03-07 23:22:49 +00:00
dump_meta_header = dump_acid_header = true ;
2020-10-10 20:29:14 +01:00
goto end ;
}
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
out - > acid_sac_descriptor = ( NpdmSrvAccessControlDescriptorEntry * ) ( out - > raw_data + out - > meta_header - > acid_offset + out - > acid_header - > srv_access_control_offset ) ;
}
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
if ( out - > acid_header - > kernel_capability_size )
{
if ( ! IS_ALIGNED ( out - > acid_header - > kernel_capability_size , sizeof ( NpdmKernelCapabilityDescriptorEntry ) ) | | \
out - > acid_header - > kernel_capability_offset < sizeof ( NpdmAcidHeader ) | | \
( out - > acid_header - > kernel_capability_offset + out - > acid_header - > kernel_capability_size ) > out - > meta_header - > acid_size )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid ACID KernelCapability offset/size! (0x%X, 0x%X). " , out - > acid_header - > kernel_capability_offset , out - > acid_header - > kernel_capability_size ) ;
2021-03-07 23:22:49 +00:00
dump_meta_header = dump_acid_header = true ;
2020-10-10 20:29:14 +01:00
goto end ;
}
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
out - > acid_kc_descriptor = ( NpdmKernelCapabilityDescriptorEntry * ) ( out - > raw_data + out - > meta_header - > acid_offset + out - > acid_header - > kernel_capability_offset ) ;
}
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
/* Verify ACI0 section. */
out - > aci_header = ( NpdmAciHeader * ) ( out - > raw_data + out - > meta_header - > aci_offset ) ;
cur_offset + = out - > meta_header - > aci_size ;
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
if ( __builtin_bswap32 ( out - > aci_header - > magic ) ! = NPDM_ACI0_MAGIC )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid ACI0 header magic word! (0x%08X != 0x%08X). " , __builtin_bswap32 ( out - > aci_header - > magic ) , __builtin_bswap32 ( NPDM_ACI0_MAGIC ) ) ;
2021-03-07 23:22:49 +00:00
dump_meta_header = dump_acid_header = dump_aci_header = true ;
2020-10-10 20:29:14 +01:00
goto end ;
}
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
if ( out - > aci_header - > program_id ! = nca_ctx - > header . program_id )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " ACI0 program ID mismatch! (%016lX != %016lX). " , out - > aci_header - > program_id , nca_ctx - > header . program_id ) ;
2021-03-07 23:22:49 +00:00
dump_meta_header = dump_acid_header = dump_aci_header = true ;
2020-10-10 20:29:14 +01:00
goto end ;
}
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
if ( out - > aci_header - > program_id < out - > acid_header - > program_id_min | | out - > aci_header - > program_id > out - > acid_header - > program_id_max )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " ACI0 program ID out of ACID program ID range! (%016lX, %016lX - %016lX). " , out - > aci_header - > program_id , out - > acid_header - > program_id_min , out - > acid_header - > program_id_max ) ;
2021-03-07 23:22:49 +00:00
dump_meta_header = dump_acid_header = dump_aci_header = true ;
2020-10-10 20:29:14 +01:00
goto end ;
}
2022-07-05 02:04:28 +01:00
2020-10-13 15:00:03 +01:00
if ( out - > aci_header - > fs_access_control_offset < sizeof ( NpdmAciHeader ) | | out - > aci_header - > fs_access_control_size < sizeof ( NpdmFsAccessControlData ) | | \
2020-10-10 20:29:14 +01:00
( out - > aci_header - > fs_access_control_offset + out - > aci_header - > fs_access_control_size ) > out - > meta_header - > aci_size )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid ACI0 FsAccessControl offset/size! (0x%X, 0x%X). " , out - > aci_header - > fs_access_control_offset , out - > aci_header - > fs_access_control_size ) ;
2021-03-07 23:22:49 +00:00
dump_meta_header = dump_acid_header = dump_aci_header = true ;
2020-10-10 20:29:14 +01:00
goto end ;
}
2022-07-05 02:04:28 +01:00
2020-10-13 15:00:03 +01:00
out - > aci_fac_data = ( NpdmFsAccessControlData * ) ( out - > raw_data + out - > meta_header - > aci_offset + out - > aci_header - > fs_access_control_offset ) ;
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
if ( out - > aci_header - > srv_access_control_size )
{
if ( out - > aci_header - > srv_access_control_offset < sizeof ( NpdmAciHeader ) | | \
( out - > aci_header - > srv_access_control_offset + out - > aci_header - > srv_access_control_size ) > out - > meta_header - > aci_size )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid ACI0 SrvAccessControl offset/size! (0x%X, 0x%X). " , out - > aci_header - > srv_access_control_offset , out - > aci_header - > srv_access_control_size ) ;
2021-03-07 23:22:49 +00:00
dump_meta_header = dump_acid_header = dump_aci_header = true ;
2020-10-10 20:29:14 +01:00
goto end ;
}
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
out - > aci_sac_descriptor = ( NpdmSrvAccessControlDescriptorEntry * ) ( out - > raw_data + out - > meta_header - > aci_offset + out - > aci_header - > srv_access_control_offset ) ;
}
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
if ( out - > aci_header - > kernel_capability_size )
{
if ( ! IS_ALIGNED ( out - > aci_header - > kernel_capability_size , sizeof ( NpdmKernelCapabilityDescriptorEntry ) ) | | \
out - > aci_header - > kernel_capability_offset < sizeof ( NpdmAciHeader ) | | \
( out - > aci_header - > kernel_capability_offset + out - > aci_header - > kernel_capability_size ) > out - > meta_header - > aci_size )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid ACI0 KernelCapability offset/size! (0x%X, 0x%X). " , out - > aci_header - > kernel_capability_offset , out - > aci_header - > kernel_capability_size ) ;
2021-03-07 23:22:49 +00:00
dump_meta_header = dump_acid_header = dump_aci_header = true ;
2020-10-10 20:29:14 +01:00
goto end ;
}
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
out - > aci_kc_descriptor = ( NpdmKernelCapabilityDescriptorEntry * ) ( out - > raw_data + out - > meta_header - > aci_offset + out - > aci_header - > kernel_capability_offset ) ;
}
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
/* Safety check: verify raw NPDM size. */
if ( out - > raw_data_size < cur_offset )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid raw NPDM size! (0x%lX < 0x%lX). " , out - > raw_data_size , cur_offset ) ;
2020-10-10 20:29:14 +01:00
goto end ;
}
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
success = true ;
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
end :
2021-03-07 23:22:49 +00:00
if ( ! success )
{
2022-07-12 17:34:49 +01:00
if ( dump_aci_header ) LOG_DATA_DEBUG ( out - > aci_header , sizeof ( NpdmAciHeader ) , " NPDM ACI0 Header dump: " ) ;
if ( dump_acid_header ) LOG_DATA_DEBUG ( out - > acid_header , sizeof ( NpdmAcidHeader ) , " NPDM ACID Header dump: " ) ;
if ( dump_meta_header ) LOG_DATA_DEBUG ( out - > meta_header , sizeof ( NpdmMetaHeader ) , " NPDM Meta Header dump: " ) ;
2022-07-05 02:04:28 +01:00
2021-03-07 23:22:49 +00:00
npdmFreeContext ( out ) ;
}
2022-07-05 02:04:28 +01:00
2020-10-10 20:29:14 +01:00
return success ;
}