ldr.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <memory>
  5. #include <fmt/format.h>
  6. #include <mbedtls/sha256.h>
  7. #include "common/alignment.h"
  8. #include "common/hex_util.h"
  9. #include "core/hle/ipc_helpers.h"
  10. #include "core/hle/kernel/process.h"
  11. #include "core/hle/service/ldr/ldr.h"
  12. #include "core/hle/service/service.h"
  13. #include "core/loader/nro.h"
  14. namespace Service::LDR {
  15. namespace ErrCodes {
  16. enum {
  17. InvalidMemoryState = 51,
  18. InvalidNRO = 52,
  19. InvalidNRR = 53,
  20. MissingNRRHash = 54,
  21. MaximumNRO = 55,
  22. MaximumNRR = 56,
  23. AlreadyLoaded = 57,
  24. InvalidAlignment = 81,
  25. InvalidSize = 82,
  26. InvalidNROAddress = 84,
  27. InvalidNRRAddress = 85,
  28. NotInitialized = 87,
  29. };
  30. }
  31. constexpr ResultCode ERROR_INVALID_MEMORY_STATE(ErrorModule::Loader, ErrCodes::InvalidMemoryState);
  32. constexpr ResultCode ERROR_INVALID_NRO(ErrorModule::Loader, ErrCodes::InvalidNRO);
  33. constexpr ResultCode ERROR_INVALID_NRR(ErrorModule::Loader, ErrCodes::InvalidNRR);
  34. constexpr ResultCode ERROR_MISSING_NRR_HASH(ErrorModule::Loader, ErrCodes::MissingNRRHash);
  35. constexpr ResultCode ERROR_MAXIMUM_NRO(ErrorModule::Loader, ErrCodes::MaximumNRO);
  36. constexpr ResultCode ERROR_MAXIMUM_NRR(ErrorModule::Loader, ErrCodes::MaximumNRR);
  37. constexpr ResultCode ERROR_ALREADY_LOADED(ErrorModule::Loader, ErrCodes::AlreadyLoaded);
  38. constexpr ResultCode ERROR_INVALID_ALIGNMENT(ErrorModule::Loader, ErrCodes::InvalidAlignment);
  39. constexpr ResultCode ERROR_INVALID_SIZE(ErrorModule::Loader, ErrCodes::InvalidSize);
  40. constexpr ResultCode ERROR_INVALID_NRO_ADDRESS(ErrorModule::Loader, ErrCodes::InvalidNROAddress);
  41. constexpr ResultCode ERROR_INVALID_NRR_ADDRESS(ErrorModule::Loader, ErrCodes::InvalidNRRAddress);
  42. constexpr ResultCode ERROR_NOT_INITIALIZED(ErrorModule::Loader, ErrCodes::NotInitialized);
  43. constexpr u64 MAXIMUM_LOADED_RO = 0x40;
  44. class DebugMonitor final : public ServiceFramework<DebugMonitor> {
  45. public:
  46. explicit DebugMonitor() : ServiceFramework{"ldr:dmnt"} {
  47. // clang-format off
  48. static const FunctionInfo functions[] = {
  49. {0, nullptr, "AddProcessToDebugLaunchQueue"},
  50. {1, nullptr, "ClearDebugLaunchQueue"},
  51. {2, nullptr, "GetNsoInfos"},
  52. };
  53. // clang-format on
  54. RegisterHandlers(functions);
  55. }
  56. };
  57. class ProcessManager final : public ServiceFramework<ProcessManager> {
  58. public:
  59. explicit ProcessManager() : ServiceFramework{"ldr:pm"} {
  60. // clang-format off
  61. static const FunctionInfo functions[] = {
  62. {0, nullptr, "CreateProcess"},
  63. {1, nullptr, "GetProgramInfo"},
  64. {2, nullptr, "RegisterTitle"},
  65. {3, nullptr, "UnregisterTitle"},
  66. };
  67. // clang-format on
  68. RegisterHandlers(functions);
  69. }
  70. };
  71. class Shell final : public ServiceFramework<Shell> {
  72. public:
  73. explicit Shell() : ServiceFramework{"ldr:shel"} {
  74. // clang-format off
  75. static const FunctionInfo functions[] = {
  76. {0, nullptr, "AddProcessToLaunchQueue"},
  77. {1, nullptr, "ClearLaunchQueue"},
  78. };
  79. // clang-format on
  80. RegisterHandlers(functions);
  81. }
  82. };
  83. class RelocatableObject final : public ServiceFramework<RelocatableObject> {
  84. public:
  85. explicit RelocatableObject() : ServiceFramework{"ldr:ro"} {
  86. // clang-format off
  87. static const FunctionInfo functions[] = {
  88. {0, &RelocatableObject::LoadNro, "LoadNro"},
  89. {1, &RelocatableObject::UnloadNro, "UnloadNro"},
  90. {2, &RelocatableObject::LoadNrr, "LoadNrr"},
  91. {3, &RelocatableObject::UnloadNrr, "UnloadNrr"},
  92. {4, &RelocatableObject::Initialize, "Initialize"},
  93. };
  94. // clang-format on
  95. RegisterHandlers(functions);
  96. }
  97. void LoadNrr(Kernel::HLERequestContext& ctx) {
  98. IPC::RequestParser rp{ctx};
  99. rp.Skip(2, false);
  100. const VAddr nrr_addr{rp.Pop<VAddr>()};
  101. const u64 nrr_size{rp.Pop<u64>()};
  102. if (!initialized) {
  103. LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
  104. IPC::ResponseBuilder rb{ctx, 2};
  105. rb.Push(ERROR_NOT_INITIALIZED);
  106. return;
  107. }
  108. if (nrr.size() >= MAXIMUM_LOADED_RO) {
  109. LOG_ERROR(Service_LDR, "Loading new NRR would exceed the maximum number of loaded NRRs "
  110. "(0x40)! Failing...");
  111. IPC::ResponseBuilder rb{ctx, 2};
  112. rb.Push(ERROR_MAXIMUM_NRR);
  113. return;
  114. }
  115. // NRR Address does not fall on 0x1000 byte boundary
  116. if (!Common::Is4KBAligned(nrr_addr)) {
  117. LOG_ERROR(Service_LDR, "NRR Address has invalid alignment (actual {:016X})!", nrr_addr);
  118. IPC::ResponseBuilder rb{ctx, 2};
  119. rb.Push(ERROR_INVALID_ALIGNMENT);
  120. return;
  121. }
  122. // NRR Size is zero or causes overflow
  123. if (nrr_addr + nrr_size <= nrr_addr || nrr_size == 0 || !Common::Is4KBAligned(nrr_size)) {
  124. LOG_ERROR(Service_LDR, "NRR Size is invalid! (nrr_address={:016X}, nrr_size={:016X})",
  125. nrr_addr, nrr_size);
  126. IPC::ResponseBuilder rb{ctx, 2};
  127. rb.Push(ERROR_INVALID_SIZE);
  128. return;
  129. }
  130. // Read NRR data from memory
  131. std::vector<u8> nrr_data(nrr_size);
  132. Memory::ReadBlock(nrr_addr, nrr_data.data(), nrr_size);
  133. NRRHeader header;
  134. std::memcpy(&header, nrr_data.data(), sizeof(NRRHeader));
  135. if (header.magic != Common::MakeMagic('N', 'R', 'R', '0')) {
  136. LOG_ERROR(Service_LDR, "NRR did not have magic 'NRR0' (actual {:08X})!", header.magic);
  137. IPC::ResponseBuilder rb{ctx, 2};
  138. rb.Push(ERROR_INVALID_NRR);
  139. return;
  140. }
  141. if (header.size != nrr_size) {
  142. LOG_ERROR(Service_LDR,
  143. "NRR header reported size did not match LoadNrr parameter size! "
  144. "(header_size={:016X}, loadnrr_size={:016X})",
  145. header.size, nrr_size);
  146. IPC::ResponseBuilder rb{ctx, 2};
  147. rb.Push(ERROR_INVALID_SIZE);
  148. return;
  149. }
  150. if (Core::CurrentProcess()->GetTitleID() != header.title_id) {
  151. LOG_ERROR(Service_LDR,
  152. "Attempting to load NRR with title ID other than current process. (actual "
  153. "{:016X})!",
  154. header.title_id);
  155. IPC::ResponseBuilder rb{ctx, 2};
  156. rb.Push(ERROR_INVALID_NRR);
  157. return;
  158. }
  159. std::vector<SHA256Hash> hashes;
  160. // Copy all hashes in the NRR (specified by hash count/hash offset) into vector.
  161. for (std::size_t i = header.hash_offset;
  162. i < (header.hash_offset + (header.hash_count * sizeof(SHA256Hash))); i += 8) {
  163. SHA256Hash hash;
  164. std::memcpy(hash.data(), nrr_data.data() + i, sizeof(SHA256Hash));
  165. hashes.emplace_back(hash);
  166. }
  167. nrr.insert_or_assign(nrr_addr, std::move(hashes));
  168. IPC::ResponseBuilder rb{ctx, 2};
  169. rb.Push(RESULT_SUCCESS);
  170. }
  171. void UnloadNrr(Kernel::HLERequestContext& ctx) {
  172. if (!initialized) {
  173. LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
  174. IPC::ResponseBuilder rb{ctx, 2};
  175. rb.Push(ERROR_NOT_INITIALIZED);
  176. return;
  177. }
  178. IPC::RequestParser rp{ctx};
  179. rp.Skip(2, false);
  180. const auto nrr_addr{rp.Pop<VAddr>()};
  181. if (!Common::Is4KBAligned(nrr_addr)) {
  182. LOG_ERROR(Service_LDR, "NRR Address has invalid alignment (actual {:016X})!", nrr_addr);
  183. IPC::ResponseBuilder rb{ctx, 2};
  184. rb.Push(ERROR_INVALID_ALIGNMENT);
  185. return;
  186. }
  187. const auto iter = nrr.find(nrr_addr);
  188. if (iter == nrr.end()) {
  189. LOG_ERROR(Service_LDR,
  190. "Attempting to unload NRR which has not been loaded! (addr={:016X})",
  191. nrr_addr);
  192. IPC::ResponseBuilder rb{ctx, 2};
  193. rb.Push(ERROR_INVALID_NRR_ADDRESS);
  194. return;
  195. }
  196. nrr.erase(iter);
  197. IPC::ResponseBuilder rb{ctx, 2};
  198. rb.Push(RESULT_SUCCESS);
  199. }
  200. void LoadNro(Kernel::HLERequestContext& ctx) {
  201. IPC::RequestParser rp{ctx};
  202. rp.Skip(2, false);
  203. const VAddr nro_addr{rp.Pop<VAddr>()};
  204. const u64 nro_size{rp.Pop<u64>()};
  205. const VAddr bss_addr{rp.Pop<VAddr>()};
  206. const u64 bss_size{rp.Pop<u64>()};
  207. if (!initialized) {
  208. LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
  209. IPC::ResponseBuilder rb{ctx, 2};
  210. rb.Push(ERROR_NOT_INITIALIZED);
  211. return;
  212. }
  213. if (nro.size() >= MAXIMUM_LOADED_RO) {
  214. LOG_ERROR(Service_LDR, "Loading new NRO would exceed the maximum number of loaded NROs "
  215. "(0x40)! Failing...");
  216. IPC::ResponseBuilder rb{ctx, 2};
  217. rb.Push(ERROR_MAXIMUM_NRO);
  218. return;
  219. }
  220. // NRO Address does not fall on 0x1000 byte boundary
  221. if (!Common::Is4KBAligned(nro_addr)) {
  222. LOG_ERROR(Service_LDR, "NRO Address has invalid alignment (actual {:016X})!", nro_addr);
  223. IPC::ResponseBuilder rb{ctx, 2};
  224. rb.Push(ERROR_INVALID_ALIGNMENT);
  225. return;
  226. }
  227. // NRO Size or BSS Size is zero or causes overflow
  228. const auto nro_size_valid =
  229. nro_size != 0 && nro_addr + nro_size > nro_addr && Common::Is4KBAligned(nro_size);
  230. const auto bss_size_valid =
  231. nro_size + bss_size >= nro_size && (bss_size == 0 || bss_addr + bss_size > bss_addr);
  232. if (!nro_size_valid || !bss_size_valid) {
  233. LOG_ERROR(Service_LDR,
  234. "NRO Size or BSS Size is invalid! (nro_address={:016X}, nro_size={:016X}, "
  235. "bss_address={:016X}, bss_size={:016X})",
  236. nro_addr, nro_size, bss_addr, bss_size);
  237. IPC::ResponseBuilder rb{ctx, 2};
  238. rb.Push(ERROR_INVALID_SIZE);
  239. return;
  240. }
  241. // Read NRO data from memory
  242. std::vector<u8> nro_data(nro_size);
  243. Memory::ReadBlock(nro_addr, nro_data.data(), nro_size);
  244. SHA256Hash hash{};
  245. mbedtls_sha256(nro_data.data(), nro_data.size(), hash.data(), 0);
  246. // NRO Hash is already loaded
  247. if (std::any_of(nro.begin(), nro.end(), [&hash](const std::pair<VAddr, NROInfo>& info) {
  248. return info.second.hash == hash;
  249. })) {
  250. LOG_ERROR(Service_LDR, "NRO is already loaded!");
  251. IPC::ResponseBuilder rb{ctx, 2};
  252. rb.Push(ERROR_ALREADY_LOADED);
  253. return;
  254. }
  255. // NRO Hash is not in any loaded NRR
  256. if (!IsValidNROHash(hash)) {
  257. LOG_ERROR(Service_LDR,
  258. "NRO hash is not present in any currently loaded NRRs (hash={})!",
  259. Common::HexArrayToString(hash));
  260. IPC::ResponseBuilder rb{ctx, 2};
  261. rb.Push(ERROR_MISSING_NRR_HASH);
  262. return;
  263. }
  264. NROHeader header;
  265. std::memcpy(&header, nro_data.data(), sizeof(NROHeader));
  266. if (!IsValidNRO(header, nro_size, bss_size)) {
  267. LOG_ERROR(Service_LDR, "NRO was invalid!");
  268. IPC::ResponseBuilder rb{ctx, 2};
  269. rb.Push(ERROR_INVALID_NRO);
  270. return;
  271. }
  272. // Load NRO as new executable module
  273. auto* process = Core::CurrentProcess();
  274. auto& vm_manager = process->VMManager();
  275. auto map_address = vm_manager.FindFreeRegion(nro_size + bss_size);
  276. if (!map_address.Succeeded() ||
  277. *map_address + nro_size + bss_size > vm_manager.GetAddressSpaceEndAddress()) {
  278. LOG_ERROR(Service_LDR,
  279. "General error while allocation memory or no available memory to allocate!");
  280. IPC::ResponseBuilder rb{ctx, 2};
  281. rb.Push(ERROR_INVALID_MEMORY_STATE);
  282. return;
  283. }
  284. ASSERT(process->MirrorMemory(*map_address, nro_addr, nro_size,
  285. Kernel::MemoryState::ModuleCodeStatic) == RESULT_SUCCESS);
  286. ASSERT(process->UnmapMemory(nro_addr, 0, nro_size) == RESULT_SUCCESS);
  287. if (bss_size > 0) {
  288. ASSERT(process->MirrorMemory(*map_address + nro_size, bss_addr, bss_size,
  289. Kernel::MemoryState::ModuleCodeStatic) == RESULT_SUCCESS);
  290. ASSERT(process->UnmapMemory(bss_addr, 0, bss_size) == RESULT_SUCCESS);
  291. }
  292. vm_manager.ReprotectRange(*map_address, header.text_size,
  293. Kernel::VMAPermission::ReadExecute);
  294. vm_manager.ReprotectRange(*map_address + header.ro_offset, header.ro_size,
  295. Kernel::VMAPermission::Read);
  296. vm_manager.ReprotectRange(*map_address + header.rw_offset, header.rw_size,
  297. Kernel::VMAPermission::ReadWrite);
  298. Core::System::GetInstance().ArmInterface(0).ClearInstructionCache();
  299. Core::System::GetInstance().ArmInterface(1).ClearInstructionCache();
  300. Core::System::GetInstance().ArmInterface(2).ClearInstructionCache();
  301. Core::System::GetInstance().ArmInterface(3).ClearInstructionCache();
  302. nro.insert_or_assign(*map_address, NROInfo{hash, nro_size + bss_size});
  303. IPC::ResponseBuilder rb{ctx, 4};
  304. rb.Push(RESULT_SUCCESS);
  305. rb.Push(*map_address);
  306. }
  307. void UnloadNro(Kernel::HLERequestContext& ctx) {
  308. IPC::RequestParser rp{ctx};
  309. rp.Skip(2, false);
  310. const VAddr mapped_addr{rp.PopRaw<VAddr>()};
  311. const VAddr heap_addr{rp.PopRaw<VAddr>()};
  312. if (!initialized) {
  313. LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
  314. IPC::ResponseBuilder rb{ctx, 2};
  315. rb.Push(ERROR_NOT_INITIALIZED);
  316. return;
  317. }
  318. if (!Common::Is4KBAligned(mapped_addr) || !Common::Is4KBAligned(heap_addr)) {
  319. LOG_ERROR(Service_LDR,
  320. "NRO/BSS Address has invalid alignment (actual nro_addr={:016X}, "
  321. "bss_addr={:016X})!",
  322. mapped_addr, heap_addr);
  323. IPC::ResponseBuilder rb{ctx, 2};
  324. rb.Push(ERROR_INVALID_ALIGNMENT);
  325. return;
  326. }
  327. const auto iter = nro.find(mapped_addr);
  328. if (iter == nro.end()) {
  329. LOG_ERROR(Service_LDR,
  330. "The NRO attempting to unmap was not mapped or has an invalid address "
  331. "(actual {:016X})!",
  332. mapped_addr);
  333. IPC::ResponseBuilder rb{ctx, 2};
  334. rb.Push(ERROR_INVALID_NRO_ADDRESS);
  335. return;
  336. }
  337. auto* process = Core::CurrentProcess();
  338. auto& vm_manager = process->VMManager();
  339. const auto& nro_size = iter->second.size;
  340. ASSERT(process->MirrorMemory(heap_addr, mapped_addr, nro_size,
  341. Kernel::MemoryState::ModuleCodeStatic) == RESULT_SUCCESS);
  342. ASSERT(process->UnmapMemory(mapped_addr, 0, nro_size) == RESULT_SUCCESS);
  343. Core::System::GetInstance().ArmInterface(0).ClearInstructionCache();
  344. Core::System::GetInstance().ArmInterface(1).ClearInstructionCache();
  345. Core::System::GetInstance().ArmInterface(2).ClearInstructionCache();
  346. Core::System::GetInstance().ArmInterface(3).ClearInstructionCache();
  347. nro.erase(iter);
  348. IPC::ResponseBuilder rb{ctx, 2};
  349. rb.Push(RESULT_SUCCESS);
  350. }
  351. void Initialize(Kernel::HLERequestContext& ctx) {
  352. initialized = true;
  353. IPC::ResponseBuilder rb{ctx, 2};
  354. rb.Push(RESULT_SUCCESS);
  355. LOG_WARNING(Service_LDR, "(STUBBED) called");
  356. }
  357. private:
  358. using SHA256Hash = std::array<u8, 0x20>;
  359. struct NROHeader {
  360. u32_le entrypoint_insn;
  361. u32_le mod_offset;
  362. INSERT_PADDING_WORDS(2);
  363. u32_le magic;
  364. INSERT_PADDING_WORDS(1);
  365. u32_le nro_size;
  366. INSERT_PADDING_WORDS(1);
  367. u32_le text_offset;
  368. u32_le text_size;
  369. u32_le ro_offset;
  370. u32_le ro_size;
  371. u32_le rw_offset;
  372. u32_le rw_size;
  373. u32_le bss_size;
  374. INSERT_PADDING_WORDS(1);
  375. std::array<u8, 0x20> build_id;
  376. INSERT_PADDING_BYTES(0x20);
  377. };
  378. static_assert(sizeof(NROHeader) == 0x80, "NROHeader has invalid size.");
  379. struct NRRHeader {
  380. u32_le magic;
  381. INSERT_PADDING_BYTES(0x1C);
  382. u64_le title_id_mask;
  383. u64_le title_id_pattern;
  384. std::array<u8, 0x100> modulus;
  385. std::array<u8, 0x100> signature_1;
  386. std::array<u8, 0x100> signature_2;
  387. u64_le title_id;
  388. u32_le size;
  389. INSERT_PADDING_BYTES(4);
  390. u32_le hash_offset;
  391. u32_le hash_count;
  392. INSERT_PADDING_BYTES(8);
  393. };
  394. static_assert(sizeof(NRRHeader) == 0x350, "NRRHeader has incorrect size.");
  395. struct NROInfo {
  396. SHA256Hash hash;
  397. u64 size;
  398. };
  399. bool initialized = false;
  400. std::map<VAddr, NROInfo> nro;
  401. std::map<VAddr, std::vector<SHA256Hash>> nrr;
  402. bool IsValidNROHash(const SHA256Hash& hash) {
  403. return std::any_of(
  404. nrr.begin(), nrr.end(), [&hash](const std::pair<VAddr, std::vector<SHA256Hash>>& p) {
  405. return std::find(p.second.begin(), p.second.end(), hash) != p.second.end();
  406. });
  407. }
  408. static bool IsValidNRO(const NROHeader& header, u64 nro_size, u64 bss_size) {
  409. return header.magic == Common::MakeMagic('N', 'R', 'O', '0') &&
  410. header.nro_size == nro_size && header.bss_size == bss_size &&
  411. header.ro_offset == header.text_offset + header.text_size &&
  412. header.rw_offset == header.ro_offset + header.ro_size &&
  413. nro_size == header.rw_offset + header.rw_size &&
  414. Common::Is4KBAligned(header.text_size) && Common::Is4KBAligned(header.ro_size) &&
  415. Common::Is4KBAligned(header.rw_size);
  416. }
  417. };
  418. void InstallInterfaces(SM::ServiceManager& sm) {
  419. std::make_shared<DebugMonitor>()->InstallAsService(sm);
  420. std::make_shared<ProcessManager>()->InstallAsService(sm);
  421. std::make_shared<Shell>()->InstallAsService(sm);
  422. std::make_shared<RelocatableObject>()->InstallAsService(sm);
  423. }
  424. } // namespace Service::LDR