Add recursion guard for Wii U re-encryption: implement flag to prevent recursive calls during sector processing

This commit is contained in:
2026-03-16 13:28:16 +00:00
parent 70b51ec38e
commit 913d0508a2
2 changed files with 48 additions and 26 deletions

View File

@@ -353,6 +353,7 @@ typedef struct aaruformat_context
uint8_t *wiiu_encrypted_block_cache; ///< Cached re-encrypted 0x8000-byte physical sector
uint64_t wiiu_cached_physical_sector; ///< Physical sector number of cached block
bool wiiu_cache_valid; ///< Whether the encrypted block cache is valid
bool wiiu_building_crypto_block; ///< True while gathering sectors for re-encryption (suppresses recursion)
} aaruformat_context;
/** \struct DumpHardwareEntriesWithData

View File

@@ -435,7 +435,8 @@ AARU_EXPORT int32_t AARU_CALL aaruf_read_sector(void *context, const uint64_t se
}
// Wii U re-encryption: if stored decrypted, re-encrypt for caller
if(*sector_status == SectorStatusUnencrypted && ctx->header.mediaType == WUOD)
if(*sector_status == SectorStatusUnencrypted && ctx->header.mediaType == WUOD &&
!ctx->wiiu_building_crypto_block)
{
if(!ctx->wiiu_encryption_initialized)
{
@@ -455,32 +456,42 @@ AARU_EXPORT int32_t AARU_CALL aaruf_read_sector(void *context, const uint64_t se
if(!ctx->wiiu_cache_valid || ctx->wiiu_cached_physical_sector != phys_sector)
{
// Build the 0x8000 block from the decompressed block cache
uint64_t first_logical = phys_sector * WIIU_LOGICAL_PER_PHYSICAL;
uint32_t sectors_in_block = block_header->length / block_header->sectorSize;
uint64_t block_first = sector_address - offset;
uint64_t first_logical = phys_sector * WIIU_LOGICAL_PER_PHYSICAL;
// Read all 16 logical sectors via aaruf_read_sector with recursion guard
ctx->wiiu_building_crypto_block = true;
for(uint32_t s = 0; s < WIIU_LOGICAL_PER_PHYSICAL; s++)
{
uint64_t logical = first_logical + s;
int64_t idx = (int64_t)(logical - block_first);
if(idx >= 0 && (uint32_t)idx < sectors_in_block)
memcpy(ctx->wiiu_encrypted_block_cache + s * block_header->sectorSize,
block + (uint32_t)idx * block_header->sectorSize, block_header->sectorSize);
if(logical == sector_address)
{
// Current sector is already in data buffer
memcpy(ctx->wiiu_encrypted_block_cache + s * (*length), data, *length);
}
else
memset(ctx->wiiu_encrypted_block_cache + s * block_header->sectorSize, 0,
block_header->sectorSize);
{
uint32_t s_len = *length;
uint8_t s_status = 0;
int32_t s_ret =
aaruf_read_sector(context, logical, false,
ctx->wiiu_encrypted_block_cache + s * s_len, &s_len, &s_status);
if(s_ret != AARUF_STATUS_OK)
memset(ctx->wiiu_encrypted_block_cache + s * (*length), 0, *length);
}
}
ctx->wiiu_building_crypto_block = false;
wiiu_encrypt_physical_sector(part_key, ctx->wiiu_encrypted_block_cache,
WIIU_CRYPTO_SECTOR_SIZE);
ctx->wiiu_cached_physical_sector = phys_sector;
ctx->wiiu_cache_valid = true;
}
memcpy(data, ctx->wiiu_encrypted_block_cache + slice_index * block_header->sectorSize,
block_header->sectorSize);
memcpy(data, ctx->wiiu_encrypted_block_cache + slice_index * (*length), *length);
}
}
@@ -687,7 +698,7 @@ AARU_EXPORT int32_t AARU_CALL aaruf_read_sector(void *context, const uint64_t se
}
// Wii U re-encryption: if stored decrypted, re-encrypt for caller
if(*sector_status == SectorStatusUnencrypted && ctx->header.mediaType == WUOD)
if(*sector_status == SectorStatusUnencrypted && ctx->header.mediaType == WUOD && !ctx->wiiu_building_crypto_block)
{
if(!ctx->wiiu_encryption_initialized)
{
@@ -707,31 +718,41 @@ AARU_EXPORT int32_t AARU_CALL aaruf_read_sector(void *context, const uint64_t se
if(!ctx->wiiu_cache_valid || ctx->wiiu_cached_physical_sector != phys_sector)
{
// Build the 0x8000 block from the decompressed block cache
uint64_t first_logical = phys_sector * WIIU_LOGICAL_PER_PHYSICAL;
uint32_t sectors_in_block = block_header->length / block_header->sectorSize;
uint64_t block_first = sector_address - offset;
uint64_t first_logical = phys_sector * WIIU_LOGICAL_PER_PHYSICAL;
// Read all 16 logical sectors via aaruf_read_sector with recursion guard
ctx->wiiu_building_crypto_block = true;
for(uint32_t s = 0; s < WIIU_LOGICAL_PER_PHYSICAL; s++)
{
uint64_t logical = first_logical + s;
int64_t idx = (int64_t)(logical - block_first);
if(idx >= 0 && (uint32_t)idx < sectors_in_block)
memcpy(ctx->wiiu_encrypted_block_cache + s * block_header->sectorSize,
block + (uint32_t)idx * block_header->sectorSize, block_header->sectorSize);
if(logical == sector_address)
{
// Current sector is already in data buffer
memcpy(ctx->wiiu_encrypted_block_cache + s * (*length), data, *length);
}
else
memset(ctx->wiiu_encrypted_block_cache + s * block_header->sectorSize, 0,
block_header->sectorSize);
{
uint32_t s_len = *length;
uint8_t s_status = 0;
int32_t s_ret =
aaruf_read_sector(context, logical, false, ctx->wiiu_encrypted_block_cache + s * s_len,
&s_len, &s_status);
if(s_ret != AARUF_STATUS_OK)
memset(ctx->wiiu_encrypted_block_cache + s * (*length), 0, *length);
}
}
ctx->wiiu_building_crypto_block = false;
wiiu_encrypt_physical_sector(part_key, ctx->wiiu_encrypted_block_cache, WIIU_CRYPTO_SECTOR_SIZE);
ctx->wiiu_cached_physical_sector = phys_sector;
ctx->wiiu_cache_valid = true;
}
memcpy(data, ctx->wiiu_encrypted_block_cache + slice_index * block_header->sectorSize,
block_header->sectorSize);
memcpy(data, ctx->wiiu_encrypted_block_cache + slice_index * (*length), *length);
}
}