nso: Return an optional address from LoadModule

If a malformed NSO is attempted to be loaded, we shouldn't continue
onwards. We should be reporting an error and bailing out.
This commit is contained in:
Lioncash 2018-10-14 21:41:58 -04:00
parent bb9cf8a127
commit bed872ed38
5 changed files with 29 additions and 16 deletions

View file

@ -139,14 +139,22 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(Kernel::Process& process)
for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3", for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3",
"subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) { "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) {
const FileSys::VirtualFile module_file = dir->GetFile(module); const FileSys::VirtualFile module_file = dir->GetFile(module);
if (module_file != nullptr) { if (module_file == nullptr) {
const VAddr load_addr = next_load_addr; continue;
next_load_addr = AppLoader_NSO::LoadModule(*module_file, load_addr,
std::strcmp(module, "rtld") == 0, pm);
LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr);
// Register module with GDBStub
GDBStub::RegisterModule(module, load_addr, next_load_addr - 1, false);
} }
const VAddr load_addr = next_load_addr;
const bool should_pass_arguments = std::strcmp(module, "rtld") == 0;
const auto tentative_next_load_addr =
AppLoader_NSO::LoadModule(*module_file, load_addr, should_pass_arguments, pm);
if (!tentative_next_load_addr) {
return ResultStatus::ErrorLoadingNSO;
}
next_load_addr = *tentative_next_load_addr;
LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr);
// Register module with GDBStub
GDBStub::RegisterModule(module, load_addr, next_load_addr - 1, false);
} }
process.Run(base_address, metadata.GetMainThreadPriority(), metadata.GetMainThreadStackSize()); process.Run(base_address, metadata.GetMainThreadPriority(), metadata.GetMainThreadStackSize());

View file

@ -93,7 +93,7 @@ std::string GetFileTypeString(FileType type) {
return "unknown"; return "unknown";
} }
constexpr std::array<const char*, 59> RESULT_MESSAGES{ constexpr std::array<const char*, 60> RESULT_MESSAGES{
"The operation completed successfully.", "The operation completed successfully.",
"The loader requested to load is already loaded.", "The loader requested to load is already loaded.",
"The operation is not implemented.", "The operation is not implemented.",
@ -128,6 +128,7 @@ constexpr std::array<const char*, 59> RESULT_MESSAGES{
"The RomFS could not be found.", "The RomFS could not be found.",
"The ELF file has incorrect size as determined by the header.", "The ELF file has incorrect size as determined by the header.",
"There was a general error loading the NRO into emulated memory.", "There was a general error loading the NRO into emulated memory.",
"There was a general error loading the NSO into emulated memory.",
"There is no icon available.", "There is no icon available.",
"There is no control data available.", "There is no control data available.",
"The NAX file has a bad header.", "The NAX file has a bad header.",

View file

@ -90,6 +90,7 @@ enum class ResultStatus : u16 {
ErrorNoRomFS, ErrorNoRomFS,
ErrorIncorrectELFFileSize, ErrorIncorrectELFFileSize,
ErrorLoadingNRO, ErrorLoadingNRO,
ErrorLoadingNSO,
ErrorNoIcon, ErrorNoIcon,
ErrorNoControl, ErrorNoControl,
ErrorBadNAXHeader, ErrorBadNAXHeader,

View file

@ -93,9 +93,9 @@ static constexpr u32 PageAlignSize(u32 size) {
return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK;
} }
VAddr AppLoader_NSO::LoadModule(const FileSys::VfsFile& file, VAddr load_base, std::optional<VAddr> AppLoader_NSO::LoadModule(const FileSys::VfsFile& file, VAddr load_base,
bool should_pass_arguments, bool should_pass_arguments,
boost::optional<FileSys::PatchManager> pm) { std::optional<FileSys::PatchManager> pm) {
if (file.GetSize() < sizeof(NsoHeader)) if (file.GetSize() < sizeof(NsoHeader))
return {}; return {};
@ -154,7 +154,7 @@ VAddr AppLoader_NSO::LoadModule(const FileSys::VfsFile& file, VAddr load_base,
program_image.resize(image_size); program_image.resize(image_size);
// Apply patches if necessary // Apply patches if necessary
if (pm != boost::none && pm->HasNSOPatch(nso_header.build_id)) { if (pm && pm->HasNSOPatch(nso_header.build_id)) {
std::vector<u8> pi_header(program_image.size() + 0x100); std::vector<u8> pi_header(program_image.size() + 0x100);
std::memcpy(pi_header.data(), &nso_header, sizeof(NsoHeader)); std::memcpy(pi_header.data(), &nso_header, sizeof(NsoHeader));
std::memcpy(pi_header.data() + 0x100, program_image.data(), program_image.size()); std::memcpy(pi_header.data() + 0x100, program_image.data(), program_image.size());
@ -181,7 +181,9 @@ ResultStatus AppLoader_NSO::Load(Kernel::Process& process) {
// Load module // Load module
const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress();
LoadModule(*file, base_address, true); if (!LoadModule(*file, base_address, true)) {
return ResultStatus::ErrorLoadingNSO;
}
LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address); LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address);
process.Run(base_address, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE); process.Run(base_address, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);

View file

@ -4,6 +4,7 @@
#pragma once #pragma once
#include <optional>
#include "common/common_types.h" #include "common/common_types.h"
#include "core/file_sys/patch_manager.h" #include "core/file_sys/patch_manager.h"
#include "core/loader/linker.h" #include "core/loader/linker.h"
@ -36,9 +37,9 @@ public:
return IdentifyType(file); return IdentifyType(file);
} }
static VAddr LoadModule(const FileSys::VfsFile& file, VAddr load_base, static std::optional<VAddr> LoadModule(const FileSys::VfsFile& file, VAddr load_base,
bool should_pass_arguments, bool should_pass_arguments,
boost::optional<FileSys::PatchManager> pm = boost::none); std::optional<FileSys::PatchManager> pm = {});
ResultStatus Load(Kernel::Process& process) override; ResultStatus Load(Kernel::Process& process) override;
}; };