Merge pull request #6142 from lat9nq/prog_meta_ref_bind_address
program_metadata: Avoid reference binding to misaligned address
This commit is contained in:
		| @@ -33,11 +33,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; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -152,9 +196,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()); | ||||||
|   | |||||||
| @@ -144,20 +144,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; | ||||||
| @@ -165,10 +163,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; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user