nx_savedata: More fail paths, ensure alignment

This commit is contained in:
shchmue 2020-12-07 19:08:08 -07:00
parent 1f77c50975
commit 044c8b32f0
9 changed files with 51 additions and 34 deletions

View file

@ -38,12 +38,21 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <gfx_utils.h> #include <gfx_utils.h>
void save_allocation_table_storage_init(allocation_table_storage_ctx_t *ctx, substorage *data, allocation_table_ctx_t *table, uint32_t block_size, uint32_t initial_block) { bool save_allocation_table_storage_init(allocation_table_storage_ctx_t *ctx, substorage *data, allocation_table_ctx_t *table, uint32_t block_size, uint32_t initial_block) {
ctx->base_storage = data; ctx->base_storage = data;
ctx->block_size = block_size; ctx->block_size = block_size;
ctx->fat = table; ctx->fat = table;
ctx->initial_block = initial_block; ctx->initial_block = initial_block;
ctx->_length = initial_block == 0xFFFFFFFF ? 0 : save_allocation_table_get_list_length(table, initial_block) * block_size; ctx->_length = 0;
if (initial_block != 0xFFFFFFFF) {
uint32_t list_length = save_allocation_table_get_list_length(table, initial_block);
if (list_length == 0) {
EPRINTF("Allocation table storage init failed!");
return false;
};
ctx->_length = list_length * block_size;
}
return true;
} }
uint32_t save_allocation_table_storage_read(allocation_table_storage_ctx_t *ctx, void *buffer, uint64_t offset, uint64_t count) { uint32_t save_allocation_table_storage_read(allocation_table_storage_ctx_t *ctx, void *buffer, uint64_t offset, uint64_t count) {

View file

@ -52,7 +52,7 @@ static ALWAYS_INLINE void save_allocation_table_storage_get_size(allocation_tabl
*out_size = ctx->_length; *out_size = ctx->_length;
} }
void save_allocation_table_storage_init(allocation_table_storage_ctx_t *ctx, substorage *data, allocation_table_ctx_t *table, uint32_t block_size, uint32_t initial_block); bool save_allocation_table_storage_init(allocation_table_storage_ctx_t *ctx, substorage *data, allocation_table_ctx_t *table, uint32_t block_size, uint32_t initial_block);
uint32_t save_allocation_table_storage_read(allocation_table_storage_ctx_t *ctx, void *buffer, uint64_t offset, uint64_t count); uint32_t save_allocation_table_storage_read(allocation_table_storage_ctx_t *ctx, void *buffer, uint64_t offset, uint64_t count);
uint32_t save_allocation_table_storage_write(allocation_table_storage_ctx_t *ctx, const void *buffer, uint64_t offset, uint64_t count); uint32_t save_allocation_table_storage_write(allocation_table_storage_ctx_t *ctx, const void *buffer, uint64_t offset, uint64_t count);
bool save_allocation_table_storage_set_size(allocation_table_storage_ctx_t *ctx, uint64_t size); bool save_allocation_table_storage_set_size(allocation_table_storage_ctx_t *ctx, uint64_t size);

View file

@ -135,7 +135,7 @@ validity_t save_hierarchical_integrity_verification_storage_validate(hierarchica
validity_t result = VALIDITY_VALID; validity_t result = VALIDITY_VALID;
integrity_verification_storage_ctx_t *storage = &ctx->integrity_storages[3]; integrity_verification_storage_ctx_t *storage = &ctx->integrity_storages[3];
uint64_t block_size = storage->base_storage.sector_size; uint32_t block_size = storage->base_storage.sector_size;
uint32_t block_count = (uint32_t)(DIV_ROUND_UP(ctx->length, block_size)); uint32_t block_count = (uint32_t)(DIV_ROUND_UP(ctx->length, block_size));
uint8_t *buffer = malloc(block_size); uint8_t *buffer = malloc(block_size);
@ -143,7 +143,7 @@ validity_t save_hierarchical_integrity_verification_storage_validate(hierarchica
for (unsigned int i = 0; i < block_count; i++) { for (unsigned int i = 0; i < block_count; i++) {
if (ctx->level_validities[3][i] == VALIDITY_UNCHECKED) { if (ctx->level_validities[3][i] == VALIDITY_UNCHECKED) {
uint64_t storage_size = storage->base_storage.length; uint64_t storage_size = storage->base_storage.length;
uint32_t to_read = MIN((uint32_t)(storage_size - block_size * i), (uint32_t)block_size); uint32_t to_read = MIN((uint32_t)(storage_size - block_size * i), block_size);
substorage_read(&ctx->data_level->base_storage, buffer, block_size * i, to_read); substorage_read(&ctx->data_level->base_storage, buffer, block_size * i, to_read);
} }
if (ctx->level_validities[3][i] == VALIDITY_INVALID) { if (ctx->level_validities[3][i] == VALIDITY_INVALID) {

View file

@ -207,7 +207,7 @@ void save_hierarchical_file_table_unlink_file_from_parent(hierarchical_save_file
return; return;
} }
prev_index = cur_index; prev_index = cur_index;
memcpy(&prev_entry, &cur_entry, sizeof(prev_entry)); memcpy(&prev_entry, &cur_entry, sizeof(save_table_entry_t));
cur_index = prev_entry.next_sibling; cur_index = prev_entry.next_sibling;
} }
} }
@ -236,7 +236,7 @@ void save_hierarchical_file_table_unlink_directory_from_parent(hierarchical_save
return; return;
} }
prev_index = cur_index; prev_index = cur_index;
memcpy(&prev_entry, &cur_entry, sizeof(prev_entry)); memcpy(&prev_entry, &cur_entry, sizeof(save_table_entry_t));
cur_index = prev_entry.next_sibling; cur_index = prev_entry.next_sibling;
} }
} }

View file

@ -52,7 +52,7 @@ void save_ivfc_storage_init(integrity_verification_storage_ctx_t *ctx, integrity
/* buffer must have size count + 0x20 for salt to by copied in at offset 0. */ /* buffer must have size count + 0x20 for salt to by copied in at offset 0. */
static ALWAYS_INLINE void save_ivfc_storage_do_hash(integrity_verification_storage_ctx_t *ctx, uint8_t *out_hash, void *buffer, uint64_t count) { static ALWAYS_INLINE void save_ivfc_storage_do_hash(integrity_verification_storage_ctx_t *ctx, uint8_t *out_hash, void *buffer, uint64_t count) {
memcpy(buffer, ctx->salt, sizeof(ctx->salt)); memcpy(buffer, ctx->salt, sizeof(ctx->salt));
se_calc_sha256(out_hash, buffer, count + sizeof(ctx->salt)); se_calc_sha256_oneshot(out_hash, buffer, count + sizeof(ctx->salt));
out_hash[0x1F] |= 0x80; out_hash[0x1F] |= 0x80;
} }
@ -81,7 +81,7 @@ bool save_ivfc_storage_read(integrity_verification_storage_ctx_t *ctx, void *buf
return false; return false;
} }
uint8_t hash_buffer[0x20] = {0}; uint8_t hash_buffer[0x20] __attribute__((aligned(4))) = {0};
uint64_t hash_pos = block_index * sizeof(hash_buffer); uint64_t hash_pos = block_index * sizeof(hash_buffer);
if (substorage_read(&ctx->hash_storage, hash_buffer, hash_pos, sizeof(hash_buffer)) != sizeof(hash_buffer)) if (substorage_read(&ctx->hash_storage, hash_buffer, hash_pos, sizeof(hash_buffer)) != sizeof(hash_buffer))
@ -99,17 +99,16 @@ bool save_ivfc_storage_read(integrity_verification_storage_ctx_t *ctx, void *buf
return false; return false;
} }
memcpy(buffer, data_buffer + 0x20 + (offset % ctx->base_storage.sector_size), count);
if (ctx->integrity_check_level && ctx->block_validities[block_index] != VALIDITY_UNCHECKED) { if (ctx->integrity_check_level && ctx->block_validities[block_index] != VALIDITY_UNCHECKED) {
memcpy(buffer, data_buffer + 0x20 + (offset % ctx->base_storage.sector_size), count);
free(data_buffer); free(data_buffer);
return true; return true;
} }
uint8_t hash[0x20] = {0}; uint8_t hash[0x20] __attribute__((aligned(4))) = {0};
save_ivfc_storage_do_hash(ctx, hash, data_buffer, ctx->base_storage.sector_size); save_ivfc_storage_do_hash(ctx, hash, data_buffer, ctx->base_storage.sector_size);
memcpy(buffer, data_buffer + 0x20 + (offset % ctx->base_storage.sector_size), count);
free(data_buffer); free(data_buffer);
if (memcmp(hash_buffer, hash, sizeof(hash_buffer)) == 0) { if (memcmp(hash_buffer, hash, sizeof(hash_buffer)) == 0) {
ctx->block_validities[block_index] = VALIDITY_VALID; ctx->block_validities[block_index] = VALIDITY_VALID;
} else { } else {
@ -127,7 +126,7 @@ bool save_ivfc_storage_write(integrity_verification_storage_ctx_t *ctx, const vo
uint64_t block_index = offset / ctx->base_storage.sector_size; uint64_t block_index = offset / ctx->base_storage.sector_size;
uint64_t hash_pos = block_index * 0x20; uint64_t hash_pos = block_index * 0x20;
uint8_t hash[0x20] = {0}; uint8_t hash[0x20] __attribute__((aligned(4))) = {0};
uint8_t *data_buffer = calloc(1, ctx->base_storage.sector_size + 0x20); uint8_t *data_buffer = calloc(1, ctx->base_storage.sector_size + 0x20);
if (count < ctx->base_storage.sector_size) { if (count < ctx->base_storage.sector_size) {
if (substorage_read(&ctx->base_storage.base_storage, data_buffer + 0x20, offset - (offset % ctx->base_storage.sector_size), ctx->base_storage.sector_size) != ctx->base_storage.sector_size) { if (substorage_read(&ctx->base_storage.base_storage, data_buffer + 0x20, offset - (offset % ctx->base_storage.sector_size), ctx->base_storage.sector_size) != ctx->base_storage.sector_size) {

View file

@ -98,13 +98,13 @@ static bool save_process_header(save_ctx_t *ctx) {
ctx->data_ivfc_master = (uint8_t *)&ctx->header + ctx->header.layout.ivfc_master_hash_offset_a; ctx->data_ivfc_master = (uint8_t *)&ctx->header + ctx->header.layout.ivfc_master_hash_offset_a;
ctx->fat_ivfc_master = (uint8_t *)&ctx->header + ctx->header.layout.fat_ivfc_master_hash_a; ctx->fat_ivfc_master = (uint8_t *)&ctx->header + ctx->header.layout.fat_ivfc_master_hash_a;
uint8_t hash[0x20]; uint8_t hash[0x20] __attribute__((aligned(4)));
uint32_t hashed_data_offset = sizeof(ctx->header.layout) + sizeof(ctx->header.cmac) + sizeof(ctx->header._0x10); uint32_t hashed_data_offset = sizeof(ctx->header.layout) + sizeof(ctx->header.cmac) + sizeof(ctx->header._0x10);
uint32_t hashed_data_size = sizeof(ctx->header) - hashed_data_offset; uint32_t hashed_data_size = sizeof(ctx->header) - hashed_data_offset;
se_calc_sha256(hash, (uint8_t *)&ctx->header + hashed_data_offset, hashed_data_size); se_calc_sha256_oneshot(hash, (uint8_t *)&ctx->header + hashed_data_offset, hashed_data_size);
ctx->header_hash_validity = memcmp(hash, ctx->header.layout.hash, 0x20) == 0 ? VALIDITY_VALID : VALIDITY_INVALID; ctx->header_hash_validity = memcmp(hash, ctx->header.layout.hash, sizeof(hash)) == 0 ? VALIDITY_VALID : VALIDITY_INVALID;
unsigned char cmac[0x10] = {}; uint8_t cmac[0x10] __attribute__((aligned(4)));
se_aes_key_set(10, ctx->save_mac_key, 0x10); se_aes_key_set(10, ctx->save_mac_key, 0x10);
se_aes_cmac(10, cmac, 0x10, &ctx->header.layout, sizeof(ctx->header.layout)); se_aes_cmac(10, cmac, 0x10, &ctx->header.layout, sizeof(ctx->header.layout));
if (memcmp(cmac, &ctx->header.cmac, 0x10) == 0) { if (memcmp(cmac, &ctx->header.cmac, 0x10) == 0) {
@ -126,14 +126,14 @@ bool save_process(save_ctx_t *ctx) {
substorage_init(&ctx->base_storage, &file_storage_vt, ctx->file, 0, f_size(ctx->file)); substorage_init(&ctx->base_storage, &file_storage_vt, ctx->file, 0, f_size(ctx->file));
/* Try to parse Header A. */ /* Try to parse Header A. */
if (substorage_read(&ctx->base_storage, &ctx->header, 0, sizeof(ctx->header)) != sizeof(ctx->header)) { if (substorage_read(&ctx->base_storage, &ctx->header, 0, sizeof(ctx->header)) != sizeof(ctx->header)) {
EPRINTF("Failed to read save header!\n"); EPRINTF("Failed to read save header A!\n");
return false; return false;
} }
if (!save_process_header(ctx) || (ctx->header_hash_validity == VALIDITY_INVALID)) { if (!save_process_header(ctx) || (ctx->header_hash_validity == VALIDITY_INVALID)) {
/* Try to parse Header B. */ /* Try to parse Header B. */
if (substorage_read(&ctx->base_storage, &ctx->header, sizeof(ctx->header), sizeof(ctx->header)) != sizeof(ctx->header)) { if (substorage_read(&ctx->base_storage, &ctx->header, sizeof(ctx->header), sizeof(ctx->header)) != sizeof(ctx->header)) {
EPRINTF("Failed to read save header!\n"); EPRINTF("Failed to read save header B!\n");
return false; return false;
} }
@ -147,10 +147,13 @@ bool save_process(save_ctx_t *ctx) {
ctx->data_remap_storage.header = &ctx->header.main_remap_header; ctx->data_remap_storage.header = &ctx->header.main_remap_header;
ctx->meta_remap_storage.header = &ctx->header.meta_remap_header; ctx->meta_remap_storage.header = &ctx->header.meta_remap_header;
u32 data_remap_entry_size = sizeof(remap_entry_t) * ctx->data_remap_storage.header->map_entry_count;
u32 meta_remap_entry_size = sizeof(remap_entry_t) * ctx->meta_remap_storage.header->map_entry_count;
substorage_init(&ctx->data_remap_storage.base_storage, &file_storage_vt, ctx->file, ctx->header.layout.file_map_data_offset, ctx->header.layout.file_map_data_size); substorage_init(&ctx->data_remap_storage.base_storage, &file_storage_vt, ctx->file, ctx->header.layout.file_map_data_offset, ctx->header.layout.file_map_data_size);
ctx->data_remap_storage.map_entries = calloc(1, sizeof(remap_entry_ctx_t) * ctx->data_remap_storage.header->map_entry_count); ctx->data_remap_storage.map_entries = calloc(1, sizeof(remap_entry_ctx_t) * ctx->data_remap_storage.header->map_entry_count);
uint8_t *remap_buffer = malloc(MAX(ctx->data_remap_storage.header->map_entry_count, ctx->meta_remap_storage.header->map_entry_count) * sizeof(remap_entry_t)); uint8_t *remap_buffer = malloc(MAX(data_remap_entry_size, meta_remap_entry_size));
if (substorage_read(&ctx->base_storage, remap_buffer, ctx->header.layout.file_map_entry_offset, sizeof(remap_entry_t) * ctx->data_remap_storage.header->map_entry_count) != sizeof(remap_entry_t) * ctx->data_remap_storage.header->map_entry_count) { if (substorage_read(&ctx->base_storage, remap_buffer, ctx->header.layout.file_map_entry_offset, data_remap_entry_size) != data_remap_entry_size) {
EPRINTF("Failed to read data remap table!"); EPRINTF("Failed to read data remap table!");
free(remap_buffer); free(remap_buffer);
return false; return false;
@ -177,7 +180,7 @@ bool save_process(save_ctx_t *ctx) {
/* Initialize meta remap storage. */ /* Initialize meta remap storage. */
substorage_init(&ctx->meta_remap_storage.base_storage, &hierarchical_duplex_storage_vt, &ctx->duplex_storage, 0, ctx->duplex_storage.data_layer->_length); substorage_init(&ctx->meta_remap_storage.base_storage, &hierarchical_duplex_storage_vt, &ctx->duplex_storage, 0, ctx->duplex_storage.data_layer->_length);
ctx->meta_remap_storage.map_entries = calloc(1, sizeof(remap_entry_ctx_t) * ctx->meta_remap_storage.header->map_entry_count); ctx->meta_remap_storage.map_entries = calloc(1, sizeof(remap_entry_ctx_t) * ctx->meta_remap_storage.header->map_entry_count);
if (substorage_read(&ctx->base_storage, remap_buffer, ctx->header.layout.meta_map_entry_offset, sizeof(remap_entry_t) * ctx->meta_remap_storage.header->map_entry_count) != sizeof(remap_entry_t) * ctx->meta_remap_storage.header->map_entry_count) { if (substorage_read(&ctx->base_storage, remap_buffer, ctx->header.layout.meta_map_entry_offset, meta_remap_entry_size) != meta_remap_entry_size) {
EPRINTF("Failed to read meta remap table!"); EPRINTF("Failed to read meta remap table!");
free(remap_buffer); free(remap_buffer);
return false; return false;
@ -225,9 +228,7 @@ bool save_process(save_ctx_t *ctx) {
} }
/* Initialize core save filesystem. */ /* Initialize core save filesystem. */
save_data_file_system_core_init(&ctx->save_filesystem_core, &ctx->core_data_ivfc_storage.base_storage, ctx->fat_storage, &ctx->header.save_header); return save_data_file_system_core_init(&ctx->save_filesystem_core, &ctx->core_data_ivfc_storage.base_storage, ctx->fat_storage, &ctx->header.save_header);
return true;
} }
void save_free_contexts(save_ctx_t *ctx) { void save_free_contexts(save_ctx_t *ctx) {
@ -292,7 +293,7 @@ bool save_commit(save_ctx_t *ctx) {
uint32_t hashed_data_offset = sizeof(ctx->header.layout) + sizeof(ctx->header.cmac) + sizeof(ctx->header._0x10); uint32_t hashed_data_offset = sizeof(ctx->header.layout) + sizeof(ctx->header.cmac) + sizeof(ctx->header._0x10);
uint32_t hashed_data_size = sizeof(ctx->header) - hashed_data_offset; uint32_t hashed_data_size = sizeof(ctx->header) - hashed_data_offset;
uint8_t *header = (uint8_t *)&ctx->header; uint8_t *header = (uint8_t *)&ctx->header;
se_calc_sha256(ctx->header.layout.hash, header + hashed_data_offset, hashed_data_size); se_calc_sha256_oneshot(ctx->header.layout.hash, header + hashed_data_offset, hashed_data_size);
se_aes_key_set(10, ctx->save_mac_key, 0x10); se_aes_key_set(10, ctx->save_mac_key, 0x10);
se_aes_cmac(10, ctx->header.cmac, 0x10, &ctx->header.layout, sizeof(ctx->header.layout)); se_aes_cmac(10, ctx->header.cmac, 0x10, &ctx->header.layout, sizeof(ctx->header.layout));

View file

@ -38,7 +38,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
void save_data_file_init(save_data_file_ctx_t *ctx, allocation_table_storage_ctx_t *base_storage, const char *path, hierarchical_save_file_table_ctx_t *file_table, uint64_t size, open_mode_t mode) { void save_data_file_init(save_data_file_ctx_t *ctx, allocation_table_storage_ctx_t *base_storage, const char *path, hierarchical_save_file_table_ctx_t *file_table, uint64_t size, open_mode_t mode) {
ctx->mode = mode; ctx->mode = mode;
memcpy(&ctx->base_storage, base_storage, sizeof(ctx->base_storage)); memcpy(&ctx->base_storage, base_storage, sizeof(allocation_table_storage_ctx_t));
ctx->path = path; ctx->path = path;
ctx->file_table = file_table; ctx->file_table = file_table;
ctx->size = size; ctx->size = size;

View file

@ -41,21 +41,29 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <gfx_utils.h> #include <gfx_utils.h>
#include <mem/heap.h> #include <mem/heap.h>
static ALWAYS_INLINE void save_data_file_system_core_open_fat_storage(save_data_file_system_core_ctx_t *ctx, allocation_table_storage_ctx_t *storage_ctx, uint32_t block_index) { static ALWAYS_INLINE bool save_data_file_system_core_open_fat_storage(save_data_file_system_core_ctx_t *ctx, allocation_table_storage_ctx_t *storage_ctx, uint32_t block_index) {
save_allocation_table_storage_init(storage_ctx, ctx->base_storage, &ctx->allocation_table, (uint32_t)ctx->header->block_size, block_index); return save_allocation_table_storage_init(storage_ctx, ctx->base_storage, &ctx->allocation_table, (uint32_t)ctx->header->block_size, block_index);
} }
void save_data_file_system_core_init(save_data_file_system_core_ctx_t *ctx, substorage *storage, void *allocation_table, save_fs_header_t *save_fs_header) { bool save_data_file_system_core_init(save_data_file_system_core_ctx_t *ctx, substorage *storage, void *allocation_table, save_fs_header_t *save_fs_header) {
save_allocation_table_init(&ctx->allocation_table, allocation_table, &save_fs_header->fat_header); save_allocation_table_init(&ctx->allocation_table, allocation_table, &save_fs_header->fat_header);
ctx->header = save_fs_header; ctx->header = save_fs_header;
ctx->base_storage = storage; ctx->base_storage = storage;
save_filesystem_list_ctx_t *dir_table = &ctx->file_table.directory_table; save_filesystem_list_ctx_t *dir_table = &ctx->file_table.directory_table;
save_filesystem_list_ctx_t *file_table = &ctx->file_table.file_table; save_filesystem_list_ctx_t *file_table = &ctx->file_table.file_table;
save_data_file_system_core_open_fat_storage(ctx, &dir_table->storage, save_fs_header->fat_header.directory_table_block); if (!save_data_file_system_core_open_fat_storage(ctx, &dir_table->storage, save_fs_header->fat_header.directory_table_block)) {
save_data_file_system_core_open_fat_storage(ctx, &file_table->storage, save_fs_header->fat_header.file_table_block); EPRINTF("Failed to init dir table for fs core!");
return false;
}
if (!save_data_file_system_core_open_fat_storage(ctx, &file_table->storage, save_fs_header->fat_header.file_table_block)) {
EPRINTF("Failed to init file table for fs core!");
return false;
}
save_fs_list_init(dir_table); save_fs_list_init(dir_table);
save_fs_list_init(file_table); save_fs_list_init(file_table);
return true;
} }
bool save_data_file_system_core_create_directory(save_data_file_system_core_ctx_t *ctx, const char *path) { bool save_data_file_system_core_create_directory(save_data_file_system_core_ctx_t *ctx, const char *path) {

View file

@ -66,7 +66,7 @@ static ALWAYS_INLINE void save_data_file_system_core_get_total_space_size(save_d
*out_total_space = ctx->header->block_size * ctx->header->block_count; *out_total_space = ctx->header->block_size * ctx->header->block_count;
} }
void save_data_file_system_core_init(save_data_file_system_core_ctx_t *ctx, substorage *storage, void *allocation_table, save_fs_header_t *save_fs_header); bool save_data_file_system_core_init(save_data_file_system_core_ctx_t *ctx, substorage *storage, void *allocation_table, save_fs_header_t *save_fs_header);
bool save_data_file_system_core_create_directory(save_data_file_system_core_ctx_t *ctx, const char *path); bool save_data_file_system_core_create_directory(save_data_file_system_core_ctx_t *ctx, const char *path);
bool save_data_file_system_core_create_file(save_data_file_system_core_ctx_t *ctx, const char *path, uint64_t size); bool save_data_file_system_core_create_file(save_data_file_system_core_ctx_t *ctx, const char *path, uint64_t size);