forked from eden-emu/eden
		
	Merge pull request #7975 from bunnei/ldr-fix
hle: service: ldr: Use deterministic addresses when mapping NROs.
This commit is contained in:
		
						commit
						6f670381cf
					
				
					 2 changed files with 63 additions and 25 deletions
				
			
		|  | @ -253,7 +253,9 @@ public: | ||||||
|     constexpr bool IsInsideASLRRegion(VAddr address, std::size_t size) const { |     constexpr bool IsInsideASLRRegion(VAddr address, std::size_t size) const { | ||||||
|         return !IsOutsideASLRRegion(address, size); |         return !IsOutsideASLRRegion(address, size); | ||||||
|     } |     } | ||||||
| 
 |     constexpr std::size_t GetNumGuardPages() const { | ||||||
|  |         return IsKernel() ? 1 : 4; | ||||||
|  |     } | ||||||
|     PAddr GetPhysicalAddr(VAddr addr) const { |     PAddr GetPhysicalAddr(VAddr addr) const { | ||||||
|         const auto backing_addr = page_table_impl.backing_addr[addr >> PageBits]; |         const auto backing_addr = page_table_impl.backing_addr[addr >> PageBits]; | ||||||
|         ASSERT(backing_addr); |         ASSERT(backing_addr); | ||||||
|  | @ -275,10 +277,6 @@ private: | ||||||
|         return is_aslr_enabled; |         return is_aslr_enabled; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     constexpr std::size_t GetNumGuardPages() const { |  | ||||||
|         return IsKernel() ? 1 : 4; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     constexpr bool ContainsPages(VAddr addr, std::size_t num_pages) const { |     constexpr bool ContainsPages(VAddr addr, std::size_t num_pages) const { | ||||||
|         return (address_space_start <= addr) && |         return (address_space_start <= addr) && | ||||||
|                (num_pages <= (address_space_end - address_space_start) / PageSize) && |                (num_pages <= (address_space_end - address_space_start) / PageSize) && | ||||||
|  |  | ||||||
|  | @ -288,7 +288,7 @@ public: | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     bool ValidateRegionForMap(Kernel::KPageTable& page_table, VAddr start, std::size_t size) const { |     bool ValidateRegionForMap(Kernel::KPageTable& page_table, VAddr start, std::size_t size) const { | ||||||
|         constexpr std::size_t padding_size{4 * Kernel::PageSize}; |         const std::size_t padding_size{page_table.GetNumGuardPages() * Kernel::PageSize}; | ||||||
|         const auto start_info{page_table.QueryInfo(start - 1)}; |         const auto start_info{page_table.QueryInfo(start - 1)}; | ||||||
| 
 | 
 | ||||||
|         if (start_info.state != Kernel::KMemoryState::Free) { |         if (start_info.state != Kernel::KMemoryState::Free) { | ||||||
|  | @ -308,31 +308,69 @@ public: | ||||||
|         return (start + size + padding_size) <= (end_info.GetAddress() + end_info.GetSize()); |         return (start + size + padding_size) <= (end_info.GetAddress() + end_info.GetSize()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     VAddr GetRandomMapRegion(const Kernel::KPageTable& page_table, std::size_t size) const { |     ResultCode GetAvailableMapRegion(Kernel::KPageTable& page_table, u64 size, VAddr& out_addr) { | ||||||
|         VAddr addr{}; |         size = Common::AlignUp(size, Kernel::PageSize); | ||||||
|         const std::size_t end_pages{(page_table.GetAliasCodeRegionSize() - size) >> |         size += page_table.GetNumGuardPages() * Kernel::PageSize * 4; | ||||||
|                                     Kernel::PageBits}; | 
 | ||||||
|         do { |         const auto is_region_available = [&](VAddr addr) { | ||||||
|             addr = page_table.GetAliasCodeRegionStart() + |             const auto end_addr = addr + size; | ||||||
|                    (Kernel::KSystemControl::GenerateRandomRange(0, end_pages) << Kernel::PageBits); |             while (addr < end_addr) { | ||||||
|         } while (!page_table.IsInsideAddressSpace(addr, size) || |                 if (system.Memory().IsValidVirtualAddress(addr)) { | ||||||
|                  page_table.IsInsideHeapRegion(addr, size) || |                     return false; | ||||||
|                  page_table.IsInsideAliasRegion(addr, size)); |  | ||||||
|         return addr; |  | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|     ResultVal<VAddr> MapProcessCodeMemory(Kernel::KProcess* process, VAddr baseAddress, |                 if (!page_table.IsInsideAddressSpace(out_addr, size)) { | ||||||
|                                           u64 size) const { |                     return false; | ||||||
|         for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) { |                 } | ||||||
|             auto& page_table{process->PageTable()}; |  | ||||||
|             const VAddr addr{GetRandomMapRegion(page_table, size)}; |  | ||||||
|             const ResultCode result{page_table.MapCodeMemory(addr, baseAddress, size)}; |  | ||||||
| 
 | 
 | ||||||
|  |                 if (page_table.IsInsideHeapRegion(out_addr, size)) { | ||||||
|  |                     return false; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 if (page_table.IsInsideAliasRegion(out_addr, size)) { | ||||||
|  |                     return false; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 addr += Kernel::PageSize; | ||||||
|  |             } | ||||||
|  |             return true; | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         bool succeeded = false; | ||||||
|  |         const auto map_region_end = | ||||||
|  |             page_table.GetAliasCodeRegionStart() + page_table.GetAliasCodeRegionSize(); | ||||||
|  |         while (current_map_addr < map_region_end) { | ||||||
|  |             if (is_region_available(current_map_addr)) { | ||||||
|  |                 succeeded = true; | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             current_map_addr += 0x100000; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (!succeeded) { | ||||||
|  |             UNREACHABLE_MSG("Out of address space!"); | ||||||
|  |             return Kernel::ResultOutOfMemory; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         out_addr = current_map_addr; | ||||||
|  |         current_map_addr += size; | ||||||
|  | 
 | ||||||
|  |         return ResultSuccess; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ResultVal<VAddr> MapProcessCodeMemory(Kernel::KProcess* process, VAddr base_addr, u64 size) { | ||||||
|  |         auto& page_table{process->PageTable()}; | ||||||
|  |         VAddr addr{}; | ||||||
|  | 
 | ||||||
|  |         for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) { | ||||||
|  |             R_TRY(GetAvailableMapRegion(page_table, size, addr)); | ||||||
|  | 
 | ||||||
|  |             const ResultCode result{page_table.MapCodeMemory(addr, base_addr, size)}; | ||||||
|             if (result == Kernel::ResultInvalidCurrentMemory) { |             if (result == Kernel::ResultInvalidCurrentMemory) { | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             CASCADE_CODE(result); |             R_TRY(result); | ||||||
| 
 | 
 | ||||||
|             if (ValidateRegionForMap(page_table, addr, size)) { |             if (ValidateRegionForMap(page_table, addr, size)) { | ||||||
|                 return addr; |                 return addr; | ||||||
|  | @ -343,7 +381,7 @@ public: | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     ResultVal<VAddr> MapNro(Kernel::KProcess* process, VAddr nro_addr, std::size_t nro_size, |     ResultVal<VAddr> MapNro(Kernel::KProcess* process, VAddr nro_addr, std::size_t nro_size, | ||||||
|                             VAddr bss_addr, std::size_t bss_size, std::size_t size) const { |                             VAddr bss_addr, std::size_t bss_size, std::size_t size) { | ||||||
|         for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) { |         for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) { | ||||||
|             auto& page_table{process->PageTable()}; |             auto& page_table{process->PageTable()}; | ||||||
|             VAddr addr{}; |             VAddr addr{}; | ||||||
|  | @ -597,6 +635,7 @@ public: | ||||||
|         LOG_WARNING(Service_LDR, "(STUBBED) called"); |         LOG_WARNING(Service_LDR, "(STUBBED) called"); | ||||||
| 
 | 
 | ||||||
|         initialized = true; |         initialized = true; | ||||||
|  |         current_map_addr = system.CurrentProcess()->PageTable().GetAliasCodeRegionStart(); | ||||||
| 
 | 
 | ||||||
|         IPC::ResponseBuilder rb{ctx, 2}; |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|         rb.Push(ResultSuccess); |         rb.Push(ResultSuccess); | ||||||
|  | @ -607,6 +646,7 @@ private: | ||||||
| 
 | 
 | ||||||
|     std::map<VAddr, NROInfo> nro; |     std::map<VAddr, NROInfo> nro; | ||||||
|     std::map<VAddr, std::vector<SHA256Hash>> nrr; |     std::map<VAddr, std::vector<SHA256Hash>> nrr; | ||||||
|  |     VAddr current_map_addr{}; | ||||||
| 
 | 
 | ||||||
|     bool IsValidNROHash(const SHA256Hash& hash) const { |     bool IsValidNROHash(const SHA256Hash& hash) const { | ||||||
|         return std::any_of(nrr.begin(), nrr.end(), [&hash](const auto& p) { |         return std::any_of(nrr.begin(), nrr.end(), [&hash](const auto& p) { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bunnei
						bunnei