program_metadata: Unpack FileAccessHeader and FileAccessControl

Avoids a reference binding to a misaligned addresses. Unpacking one
requires unpacking the other, otherwise there'll be a misaligned address
on the leftover one.
This commit is contained in:
lat9nq 2021-06-10 16:25:25 -04:00 committed by lat9nq
parent eaca010ee9
commit bfb7cbc292
2 changed files with 51 additions and 15 deletions

View file

@ -34,11 +34,55 @@ Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) {
return Loader::ResultStatus::ErrorBadACIHeader; return Loader::ResultStatus::ErrorBadACIHeader;
} }
if (sizeof(FileAccessControl) != file->ReadObject(&acid_file_access, acid_header.fac_offset)) { // Load acid_file_access per-component instead of the entire struct, since this struct does not
// reflect the layout of the real data.
std::size_t current_offset = acid_header.fac_offset;
if (sizeof(FileAccessControl::version) != file->ReadBytes(&acid_file_access.version,
sizeof(FileAccessControl::version),
current_offset)) {
return Loader::ResultStatus::ErrorBadFileAccessControl;
}
if (sizeof(FileAccessControl::permissions) !=
file->ReadBytes(&acid_file_access.permissions, sizeof(FileAccessControl::permissions),
current_offset += sizeof(FileAccessControl::version) + 3)) {
return Loader::ResultStatus::ErrorBadFileAccessControl;
}
if (sizeof(FileAccessControl::unknown) !=
file->ReadBytes(&acid_file_access.unknown, sizeof(FileAccessControl::unknown),
current_offset + sizeof(FileAccessControl::permissions))) {
return Loader::ResultStatus::ErrorBadFileAccessControl; return Loader::ResultStatus::ErrorBadFileAccessControl;
} }
if (sizeof(FileAccessHeader) != file->ReadObject(&aci_file_access, aci_header.fah_offset)) { // Load aci_file_access per-component instead of the entire struct, same as acid_file_access
current_offset = aci_header.fah_offset;
if (sizeof(FileAccessHeader::version) != file->ReadBytes(&aci_file_access.version,
sizeof(FileAccessHeader::version),
current_offset)) {
return Loader::ResultStatus::ErrorBadFileAccessHeader;
}
if (sizeof(FileAccessHeader::permissions) !=
file->ReadBytes(&aci_file_access.permissions, sizeof(FileAccessHeader::permissions),
current_offset += sizeof(FileAccessHeader::version) + 3)) {
return Loader::ResultStatus::ErrorBadFileAccessHeader;
}
if (sizeof(FileAccessHeader::unk_offset) !=
file->ReadBytes(&aci_file_access.unk_offset, sizeof(FileAccessHeader::unk_offset),
current_offset += sizeof(FileAccessHeader::permissions))) {
return Loader::ResultStatus::ErrorBadFileAccessHeader;
}
if (sizeof(FileAccessHeader::unk_size) !=
file->ReadBytes(&aci_file_access.unk_size, sizeof(FileAccessHeader::unk_size),
current_offset += sizeof(FileAccessHeader::unk_offset))) {
return Loader::ResultStatus::ErrorBadFileAccessHeader;
}
if (sizeof(FileAccessHeader::unk_offset_2) !=
file->ReadBytes(&aci_file_access.unk_offset_2, sizeof(FileAccessHeader::unk_offset_2),
current_offset += sizeof(FileAccessHeader::unk_size))) {
return Loader::ResultStatus::ErrorBadFileAccessHeader;
}
if (sizeof(FileAccessHeader::unk_size_2) !=
file->ReadBytes(&aci_file_access.unk_size_2, sizeof(FileAccessHeader::unk_size_2),
current_offset + sizeof(FileAccessHeader::unk_offset_2))) {
return Loader::ResultStatus::ErrorBadFileAccessHeader; return Loader::ResultStatus::ErrorBadFileAccessHeader;
} }
@ -153,9 +197,7 @@ void ProgramMetadata::Print() const {
LOG_DEBUG(Service_FS, " > Is Retail: {}", acid_header.is_retail ? "YES" : "NO"); LOG_DEBUG(Service_FS, " > Is Retail: {}", acid_header.is_retail ? "YES" : "NO");
LOG_DEBUG(Service_FS, "Title ID Min: 0x{:016X}", acid_header.title_id_min); LOG_DEBUG(Service_FS, "Title ID Min: 0x{:016X}", acid_header.title_id_min);
LOG_DEBUG(Service_FS, "Title ID Max: 0x{:016X}", acid_header.title_id_max); LOG_DEBUG(Service_FS, "Title ID Max: 0x{:016X}", acid_header.title_id_max);
u64_le permissions_l; // local copy to fix alignment error LOG_DEBUG(Service_FS, "Filesystem Access: 0x{:016X}\n", acid_file_access.permissions);
std::memcpy(&permissions_l, &acid_file_access.permissions, sizeof(permissions_l));
LOG_DEBUG(Service_FS, "Filesystem Access: 0x{:016X}\n", permissions_l);
// Begin ACI0 printing (actual perms, unsigned) // Begin ACI0 printing (actual perms, unsigned)
LOG_DEBUG(Service_FS, "Magic: {:.4}", aci_header.magic.data()); LOG_DEBUG(Service_FS, "Magic: {:.4}", aci_header.magic.data());

View file

@ -143,20 +143,18 @@ private:
static_assert(sizeof(AciHeader) == 0x40, "ACI0 header structure size is wrong"); static_assert(sizeof(AciHeader) == 0x40, "ACI0 header structure size is wrong");
#pragma pack(push, 1) // FileAccessControl and FileAccessHeader need loaded per-component: this layout does not
// reflect the real layout to avoid reference binding to misaligned addresses
struct FileAccessControl { struct FileAccessControl {
u8 version; u8 version;
INSERT_PADDING_BYTES(3); // 3 padding bytes
u64_le permissions; u64_le permissions;
std::array<u8, 0x20> unknown; std::array<u8, 0x20> unknown;
}; };
static_assert(sizeof(FileAccessControl) == 0x2C, "FS access control structure size is wrong");
struct FileAccessHeader { struct FileAccessHeader {
u8 version; u8 version;
INSERT_PADDING_BYTES(3); // 3 padding bytes
u64_le permissions; u64_le permissions;
u32_le unk_offset; u32_le unk_offset;
u32_le unk_size; u32_le unk_size;
@ -164,10 +162,6 @@ private:
u32_le unk_size_2; u32_le unk_size_2;
}; };
static_assert(sizeof(FileAccessHeader) == 0x1C, "FS access header structure size is wrong");
#pragma pack(pop)
Header npdm_header; Header npdm_header;
AciHeader aci_header; AciHeader aci_header;
AcidHeader acid_header; AcidHeader acid_header;