ro: start implementing 23.0.0 changes
This commit is contained in:
@@ -19,12 +19,12 @@
|
||||
#include <stratosphere/ro/ro_types.hpp>
|
||||
#include <stratosphere/sf.hpp>
|
||||
|
||||
#define AMS_RO_I_RO_INTERFACE_INTERFACE_INFO(C, H) \
|
||||
AMS_SF_METHOD_INFO(C, H, 0, Result, MapManualLoadModuleMemory, (sf::Out<u64> out_load_address, const sf::ClientProcessId &client_pid, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size), (out_load_address, client_pid, nro_address, nro_size, bss_address, bss_size)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 1, Result, UnmapManualLoadModuleMemory, (const sf::ClientProcessId &client_pid, u64 nro_address), (client_pid, nro_address)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 2, Result, RegisterModuleInfo, (const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size), (client_pid, nrr_address, nrr_size)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 3, Result, UnregisterModuleInfo, (const sf::ClientProcessId &client_pid, u64 nrr_address), (client_pid, nrr_address)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 4, Result, RegisterProcessHandle, (const sf::ClientProcessId &client_pid, sf::CopyHandle &&process_h), (client_pid, std::move(process_h))) \
|
||||
AMS_SF_METHOD_INFO(C, H, 10, Result, RegisterProcessModuleInfo, (const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size, sf::CopyHandle &&process_h), (client_pid, nrr_address, nrr_size, std::move(process_h)), hos::Version_7_0_0)
|
||||
#define AMS_RO_I_RO_INTERFACE_INTERFACE_INFO(C, H) \
|
||||
AMS_SF_METHOD_INFO(C, H, 0, Result, MapManualLoadModuleMemory, (sf::Out<u64> out_load_address, const sf::ClientProcessId &client_pid, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size), (out_load_address, client_pid, nro_address, nro_size, bss_address, bss_size)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 1, Result, UnmapManualLoadModuleMemory, (const sf::ClientProcessId &client_pid, u64 nro_address), (client_pid, nro_address)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 2, Result, RegisterModuleInfo, (const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size), (client_pid, nrr_address, nrr_size)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 3, Result, UnregisterModuleInfo, (const sf::ClientProcessId &client_pid, u64 nrr_address), (client_pid, nrr_address)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 4, Result, RegisterProcessHandle, (const sf::ClientProcessId &client_pid, sf::CopyHandle &&process_h), (client_pid, std::move(process_h))) \
|
||||
AMS_SF_METHOD_INFO(C, H, 10, Result, RegisterModuleInfoWithUserProcessHandle, (const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size, sf::CopyHandle &&process_h), (client_pid, nrr_address, nrr_size, std::move(process_h)), hos::Version_7_0_0)
|
||||
|
||||
AMS_SF_DEFINE_INTERFACE(ams::ro::impl, IRoInterface, AMS_RO_I_RO_INTERFACE_INTERFACE_INFO, 0xA52C55A9)
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <stratosphere/ncm/ncm_ids.hpp>
|
||||
#include <stratosphere/rocrt/rocrt.hpp>
|
||||
|
||||
namespace ams::ro {
|
||||
|
||||
@@ -40,30 +41,30 @@ namespace ams::ro {
|
||||
u64 program_id_mask;
|
||||
u64 program_id_pattern;
|
||||
u8 reserved_10[0x10];
|
||||
u8 modulus[RsaKeySize];
|
||||
u8 signature[RsaKeySize];
|
||||
u8 public_key[RsaKeySize];
|
||||
u8 sign[RsaKeySize];
|
||||
};
|
||||
static_assert(sizeof(NrrCertification) == NrrCertification::RsaKeySize + NrrCertification::SignedSize);
|
||||
|
||||
class NrrHeader {
|
||||
public:
|
||||
static constexpr u32 Magic = util::FourCC<'N','R','R','0'>::Code;
|
||||
static constexpr u32 Signature = util::FourCC<'N','R','R','0'>::Code;
|
||||
private:
|
||||
u32 m_magic;
|
||||
u32 m_signature;
|
||||
u32 m_key_generation;
|
||||
u8 m_reserved_08[0x08];
|
||||
NrrCertification m_certification;
|
||||
u8 m_signature[0x100];
|
||||
u8 m_sign[0x100];
|
||||
ncm::ProgramId m_program_id;
|
||||
u32 m_size;
|
||||
u8 m_nrr_kind; /* 7.0.0+ */
|
||||
u8 m_reserved_33D[3];
|
||||
u32 m_hashes_offset;
|
||||
u32 m_num_hashes;
|
||||
u32 m_hash_list_offset_address;
|
||||
u32 m_num_hash;
|
||||
u8 m_reserved_348[8];
|
||||
public:
|
||||
bool IsMagicValid() const {
|
||||
return m_magic == Magic;
|
||||
return m_signature == Signature;
|
||||
}
|
||||
|
||||
bool IsProgramIdValid() const {
|
||||
@@ -85,11 +86,11 @@ namespace ams::ro {
|
||||
}
|
||||
|
||||
u32 GetNumHashes() const {
|
||||
return m_num_hashes;
|
||||
return m_num_hash;
|
||||
}
|
||||
|
||||
size_t GetHashesOffset() const {
|
||||
return m_hashes_offset;
|
||||
return m_hash_list_offset_address;
|
||||
}
|
||||
|
||||
uintptr_t GetHashes() const {
|
||||
@@ -101,7 +102,7 @@ namespace ams::ro {
|
||||
}
|
||||
|
||||
const u8 *GetCertificationSignature() const {
|
||||
return m_certification.signature;
|
||||
return m_certification.sign;
|
||||
}
|
||||
|
||||
const u8 *GetCertificationSignedArea() const {
|
||||
@@ -109,11 +110,11 @@ namespace ams::ro {
|
||||
}
|
||||
|
||||
const u8 *GetCertificationModulus() const {
|
||||
return m_certification.modulus;
|
||||
return m_certification.public_key;
|
||||
}
|
||||
|
||||
const u8 *GetSignature() const {
|
||||
return m_signature;
|
||||
return m_sign;
|
||||
}
|
||||
|
||||
const u8 *GetSignedArea() const {
|
||||
@@ -132,31 +133,44 @@ namespace ams::ro {
|
||||
return AMS_OFFSETOF(NrrHeader, m_program_id);
|
||||
}
|
||||
|
||||
static constexpr size_t RocrtHeaderSize = 0x10;
|
||||
struct RocrtHeader {
|
||||
rocrt::ModuleHeaderLocation module_header_location;
|
||||
u32 reserved;
|
||||
};
|
||||
static_assert(sizeof(RocrtHeader) == RocrtHeaderSize);
|
||||
|
||||
class NroHeader {
|
||||
public:
|
||||
static constexpr u32 Magic = util::FourCC<'N','R','O','0'>::Code;
|
||||
static constexpr u32 Signature = util::FourCC<'N','R','O','0'>::Code;
|
||||
static constexpr u32 FlagAlignedHeader = 1;
|
||||
static constexpr u32 FlagCompress = 2;
|
||||
private:
|
||||
u32 m_entrypoint_insn;
|
||||
u32 m_mod_offset;
|
||||
u8 m_reserved_08[0x8];
|
||||
u32 m_magic;
|
||||
u8 m_version;
|
||||
RocrtHeader m_rocrt;
|
||||
u32 m_signature;
|
||||
u32 m_version;
|
||||
u32 m_size;
|
||||
u32 m_flags;
|
||||
u32 m_text_offset;
|
||||
u32 m_text_memory_offset;
|
||||
u32 m_text_size;
|
||||
u32 m_ro_offset;
|
||||
u32 m_ro_memory_offset;
|
||||
u32 m_ro_size;
|
||||
u32 m_rw_offset;
|
||||
u32 m_rw_size;
|
||||
u32 m_data_memory_offset;
|
||||
u32 m_data_size;
|
||||
u32 m_bss_size;
|
||||
u8 m_reserved_3C[0x4];
|
||||
u32 m_additional_header_offset; /* 23.0.0+ */
|
||||
ModuleId m_module_id;
|
||||
u8 m_reserved_60[0x20];
|
||||
u32 m_dso_handle_offset;
|
||||
u32 m_reserved_64;
|
||||
u32 m_embedded_offset;
|
||||
u32 m_embedded_size;
|
||||
u32 m_dyn_str_offset;
|
||||
u32 m_dyn_str_size;
|
||||
u32 m_dyn_sym_offset;
|
||||
u32 m_dyn_sym_size;
|
||||
public:
|
||||
bool IsMagicValid() const {
|
||||
return m_magic == Magic;
|
||||
return m_signature == Signature;
|
||||
}
|
||||
|
||||
u32 GetVersion() const {
|
||||
@@ -175,8 +189,12 @@ namespace ams::ro {
|
||||
return m_flags & FlagAlignedHeader;
|
||||
}
|
||||
|
||||
bool IsCompress() const {
|
||||
return m_flags & FlagCompress;
|
||||
}
|
||||
|
||||
u32 GetTextOffset() const {
|
||||
return m_text_offset;
|
||||
return m_text_memory_offset;
|
||||
}
|
||||
|
||||
u32 GetTextSize() const {
|
||||
@@ -184,7 +202,7 @@ namespace ams::ro {
|
||||
}
|
||||
|
||||
u32 GetRoOffset() const {
|
||||
return m_ro_offset;
|
||||
return m_ro_memory_offset;
|
||||
}
|
||||
|
||||
u32 GetRoSize() const {
|
||||
@@ -192,21 +210,60 @@ namespace ams::ro {
|
||||
}
|
||||
|
||||
u32 GetRwOffset() const {
|
||||
return m_rw_offset;
|
||||
return m_data_memory_offset;
|
||||
}
|
||||
|
||||
u32 GetRwSize() const {
|
||||
return m_rw_size;
|
||||
return m_data_size;
|
||||
}
|
||||
|
||||
u32 GetBssSize() const {
|
||||
return m_bss_size;
|
||||
}
|
||||
|
||||
u32 GetAdditionalHeaderOffset() const {
|
||||
return m_additional_header_offset;
|
||||
}
|
||||
|
||||
const ModuleId *GetModuleId() const {
|
||||
return std::addressof(m_module_id);
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(NroHeader) == 0x80, "NroHeader definition!");
|
||||
|
||||
class AdditionalNroHeader {
|
||||
public:
|
||||
static constexpr u32 Signature = util::FourCC<'N','R','A','0'>::Code;
|
||||
private:
|
||||
u32 m_signature;
|
||||
u8 m_reserved_04[0xC];
|
||||
u32 m_compressed_size;
|
||||
u32 m_reserved_14;
|
||||
u32 m_hash_size;
|
||||
u32 m_hash_offset;
|
||||
u8 m_reserved_20[0x40];
|
||||
u8 m_hash[0x20];
|
||||
public:
|
||||
bool IsMagicValid() const {
|
||||
return m_signature == Signature;
|
||||
}
|
||||
|
||||
u32 GetCompressedSize() const {
|
||||
return m_compressed_size;
|
||||
}
|
||||
|
||||
u32 GetHashSize() const {
|
||||
return m_hash_size;
|
||||
}
|
||||
|
||||
u32 GetHashOffset() const {
|
||||
return m_hash_offset;
|
||||
}
|
||||
|
||||
const u8 *GetHash() const {
|
||||
return m_hash;
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(AdditionalNroHeader) == 0x80, "AdditionalNroHeader definition!");
|
||||
|
||||
}
|
||||
|
||||
@@ -29,11 +29,18 @@ namespace ams::rocrt {
|
||||
u32 exception_info_start_offset;
|
||||
u32 exception_info_end_offset;
|
||||
u32 module_offset;
|
||||
u32 relro_start_offset; /* 19.0.0+ */
|
||||
u32 full_relro_end_offset; /* 19.0.0+ */
|
||||
u32 nx_debug_link_start_offset; /* 19.0.0+ */
|
||||
u32 nx_debug_link_end_offset; /* 19.0.0+ */
|
||||
u32 note_gnu_build_id_start_offset; /* 19.0.0+ */
|
||||
u32 note_gnu_build_id_end_offset; /* 19.0.0+ */
|
||||
};
|
||||
|
||||
struct ModuleHeaderLocation {
|
||||
u32 pad;
|
||||
u32 version;
|
||||
u32 header_offset;
|
||||
u32 version_offset;
|
||||
};
|
||||
|
||||
constexpr inline u32 CheckModuleHeaderSignature(const ModuleHeader *header) {
|
||||
|
||||
@@ -25,18 +25,20 @@ namespace ams::ro {
|
||||
R_DEFINE_ERROR_RESULT(OutOfAddressSpace, 2);
|
||||
R_DEFINE_ERROR_RESULT(AlreadyLoaded, 3);
|
||||
R_DEFINE_ERROR_RESULT(InvalidNro, 4);
|
||||
|
||||
R_DEFINE_ERROR_RESULT(NotFound, 5);
|
||||
R_DEFINE_ERROR_RESULT(InvalidNrr, 6);
|
||||
R_DEFINE_ERROR_RESULT(TooManyNro, 7);
|
||||
R_DEFINE_ERROR_RESULT(TooManyNrr, 8);
|
||||
R_DEFINE_ERROR_RESULT(NotAuthorized, 9);
|
||||
R_DEFINE_ERROR_RESULT(InvalidNrrKind, 10);
|
||||
R_DEFINE_ERROR_RESULT(InvalidBssSize, 11);
|
||||
|
||||
R_DEFINE_ERROR_RESULT(NotImplemented, 1022);
|
||||
R_DEFINE_ERROR_RESULT(InternalError, 1023);
|
||||
|
||||
R_DEFINE_ERROR_RESULT(InvalidAddress, 1025);
|
||||
R_DEFINE_ERROR_RESULT(InvalidSize, 1026);
|
||||
|
||||
R_DEFINE_ERROR_RESULT(InvalidCurrentMemory, 1027);
|
||||
R_DEFINE_ERROR_RESULT(NotLoaded, 1028);
|
||||
R_DEFINE_ERROR_RESULT(NotRegistered, 1029);
|
||||
R_DEFINE_ERROR_RESULT(InvalidSession, 1030);
|
||||
|
||||
@@ -55,8 +55,10 @@ namespace ams::ro::impl {
|
||||
u64 bss_heap_address;
|
||||
u64 bss_heap_size;
|
||||
u64 code_size;
|
||||
u64 ro_size; /* 23.0.0+ */
|
||||
u64 rw_size;
|
||||
ModuleId module_id;
|
||||
bool is_compress; /* 23.0.0+ */
|
||||
};
|
||||
|
||||
struct NrrInfo {
|
||||
@@ -73,6 +75,16 @@ namespace ams::ro::impl {
|
||||
Sha256Hash signed_area_hash;
|
||||
};
|
||||
|
||||
struct AdditionalNroHeaderInfo {
|
||||
u32 signature;
|
||||
u8 reserved_04[0xC];
|
||||
u32 compressed_size;
|
||||
u32 reserved_14;
|
||||
u32 hash_size;
|
||||
u32 hash_offset;
|
||||
u8 reserved_20[0x40];
|
||||
};
|
||||
|
||||
struct ProcessContext {
|
||||
private:
|
||||
bool m_nro_in_use[MaxNroInfos]{};
|
||||
@@ -247,18 +259,9 @@ namespace ams::ro::impl {
|
||||
R_THROW(ro::ResultNotAuthorized());
|
||||
}
|
||||
|
||||
Result ValidateNro(ModuleId *out_module_id, u64 *out_rx_size, u64 *out_ro_size, u64 *out_rw_size, bool *out_aligned_header, u64 base_address, u64 expected_nro_size, u64 expected_bss_size) {
|
||||
/* Map the NRO. */
|
||||
void *mapped_memory = nullptr;
|
||||
R_TRY_CATCH(os::MapProcessMemory(std::addressof(mapped_memory), m_process_handle, base_address, expected_nro_size, ro::impl::GenerateSecureRandom)) {
|
||||
R_CONVERT(os::ResultOutOfAddressSpace, ro::ResultOutOfAddressSpace())
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
/* When we're done, unmap the memory. */
|
||||
ON_SCOPE_EXIT { os::UnmapProcessMemory(mapped_memory, m_process_handle, base_address, expected_nro_size); };
|
||||
|
||||
Result ValidateNro(NroHeader **out_header, AdditionalNroHeaderInfo **out_additional_header_info, void *out_additional_header_hash, u8 *mapped_memory, u64 expected_nro_size, u64 expected_bss_size) {
|
||||
/* Validate header. */
|
||||
const NroHeader *header = static_cast<const NroHeader *>(mapped_memory);
|
||||
NroHeader *header = reinterpret_cast<NroHeader *>(mapped_memory);
|
||||
R_UNLESS(header->IsMagicValid(), ro::ResultInvalidNro());
|
||||
|
||||
/* Read sizes from header. */
|
||||
@@ -271,16 +274,27 @@ namespace ams::ro::impl {
|
||||
const u64 rw_size = header->GetRwSize();
|
||||
const u64 bss_size = header->GetBssSize();
|
||||
|
||||
/* Validate sizes meet expected. */
|
||||
R_UNLESS(nro_size == expected_nro_size, ro::ResultInvalidNro());
|
||||
R_UNLESS(bss_size == expected_bss_size, ro::ResultInvalidNro());
|
||||
|
||||
/* Validate all sizes are aligned. */
|
||||
R_UNLESS(util::IsAligned(text_size, os::MemoryPageSize), ro::ResultInvalidNro());
|
||||
R_UNLESS(util::IsAligned(ro_size, os::MemoryPageSize), ro::ResultInvalidNro());
|
||||
R_UNLESS(util::IsAligned(rw_size, os::MemoryPageSize), ro::ResultInvalidNro());
|
||||
R_UNLESS(util::IsAligned(bss_size, os::MemoryPageSize), ro::ResultInvalidNro());
|
||||
|
||||
/* Validate sizes meet expected. */
|
||||
R_UNLESS(nro_size == expected_nro_size, ro::ResultInvalidNro());
|
||||
|
||||
/* Account for compression when checking bss size. */
|
||||
if (header->IsCompress()) {
|
||||
R_UNLESS((bss_size - expected_nro_size + (rw_ofs + rw_size)) == expected_bss_size, ro::ResultInvalidBssSize());
|
||||
} else {
|
||||
/* 23.0.0+ uses the new error code here too. */
|
||||
if (hos::GetVersion() >= hos::Version_23_0_0) {
|
||||
R_UNLESS(bss_size == expected_bss_size, ro::ResultInvalidBssSize());
|
||||
} else {
|
||||
R_UNLESS(bss_size == expected_bss_size, ro::ResultInvalidNro());
|
||||
}
|
||||
}
|
||||
|
||||
/* Validate sections are in order. */
|
||||
R_UNLESS(text_ofs <= ro_ofs, ro::ResultInvalidNro());
|
||||
R_UNLESS(ro_ofs <= rw_ofs, ro::ResultInvalidNro());
|
||||
@@ -289,7 +303,11 @@ namespace ams::ro::impl {
|
||||
R_UNLESS(text_ofs == 0, ro::ResultInvalidNro());
|
||||
R_UNLESS(text_ofs + text_size == ro_ofs, ro::ResultInvalidNro());
|
||||
R_UNLESS(ro_ofs + ro_size == rw_ofs, ro::ResultInvalidNro());
|
||||
R_UNLESS(rw_ofs + rw_size == nro_size, ro::ResultInvalidNro());
|
||||
|
||||
/* Only check data section if not using compression. */
|
||||
if (!header->IsCompress()) {
|
||||
R_UNLESS(rw_ofs + rw_size == nro_size, ro::ResultInvalidNro());
|
||||
}
|
||||
|
||||
/* Verify NRO hash. */
|
||||
R_TRY(this->ValidateHasNroHash(header));
|
||||
@@ -298,15 +316,106 @@ namespace ams::ro::impl {
|
||||
const ModuleId *module_id = header->GetModuleId();
|
||||
R_UNLESS(R_FAILED(this->GetNroInfoByModuleId(nullptr, module_id)), ro::ResultAlreadyLoaded());
|
||||
|
||||
/* Validate compression related fields. */
|
||||
if (header->IsCompress()) {
|
||||
const u64 additional_header_offset = header->GetAdditionalHeaderOffset();
|
||||
|
||||
/* Compression must have aligned header as well. */
|
||||
R_UNLESS(header->IsAlignedHeader(), ro::ResultInvalidNro());
|
||||
|
||||
/* Validate additional header offset. */
|
||||
R_UNLESS(additional_header_offset == 0x80, ro::ResultInvalidNro());
|
||||
|
||||
/* Validate additional header. */
|
||||
AdditionalNroHeader *additional_header = reinterpret_cast<AdditionalNroHeader *>(mapped_memory + additional_header_offset);
|
||||
R_UNLESS(additional_header->IsMagicValid(), ro::ResultInvalidNro());
|
||||
|
||||
/* Read sizes from header. */
|
||||
const u64 hash_size = additional_header->GetHashSize();
|
||||
const u64 hash_offset = additional_header->GetHashOffset();
|
||||
const u64 compressed_size = additional_header->GetCompressedSize();
|
||||
|
||||
/* Validate additional header hash size and offset. */
|
||||
R_UNLESS(hash_size == 0x20, ro::ResultInvalidNro());
|
||||
R_UNLESS(hash_offset == 0xE0, ro::ResultInvalidNro());
|
||||
|
||||
/* Copy the additional header hash to output. */
|
||||
std::memcpy(out_additional_header_hash, additional_header->GetHash(), hash_size);
|
||||
|
||||
/* Validate compressed size. */
|
||||
R_UNLESS(rw_ofs + rw_size > nro_size, ro::ResultInvalidNro());
|
||||
R_UNLESS(compressed_size >= 0x1000, ro::ResultInvalidNro());
|
||||
R_UNLESS(util::AlignUp(compressed_size, os::MemoryPageSize) == expected_nro_size, ro::ResultInvalidNro());
|
||||
|
||||
/* Copy the additional header info to output. This is AdditionalNroHeader minus the hash. */
|
||||
std::memcpy(out_additional_header_info, additional_header, sizeof(*additional_header) - hash_size);
|
||||
} else {
|
||||
/* Explicitly clear additional header hash and info. */
|
||||
std::memset(out_additional_header_hash, 0, crypto::Sha256Generator::HashSize);
|
||||
std::memset(out_additional_header_info, 0, sizeof(AdditionalNroHeaderInfo));
|
||||
}
|
||||
|
||||
/* Copy the header to output. */
|
||||
*out_header = header;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result DecompressNro(u8 *mapped_nro, u64 expected_nro_size, const NroHeader *nro_header, u32 compressed_size) {
|
||||
/* TODO */
|
||||
AMS_UNUSED(mapped_nro, expected_nro_size, nro_header, compressed_size);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CheckAdditionalHeaderHash(const u8 *mapped_nro, const void *additional_nro_header_hash, size_t additional_nro_header_hash_size, u64 rw_ofs, u64 rw_size) {
|
||||
/* Calculate hash. */
|
||||
Sha256Hash nro_rw_hash;
|
||||
crypto::GenerateSha256(std::addressof(nro_rw_hash), additional_nro_header_hash_size, mapped_nro + 0x1000, (rw_ofs + rw_size) - 0x1000);
|
||||
|
||||
/* Compare the hashes. */
|
||||
const Sha256Hash *expected_hash = reinterpret_cast<const Sha256Hash *>(additional_nro_header_hash);
|
||||
if (*expected_hash != nro_rw_hash) {
|
||||
R_THROW(ro::ResultInvalidNro());
|
||||
}
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ParseNro(ModuleId *out_module_id, u64 *out_rx_size, u64 *out_ro_size, u64 *out_rw_size, bool *out_aligned_header, bool *out_is_compress, u64 base_address, u64 expected_nro_size, u64 expected_bss_size) {
|
||||
/* Map the NRO. */
|
||||
void *mapped_memory = nullptr;
|
||||
R_TRY_CATCH(os::MapProcessMemory(std::addressof(mapped_memory), m_process_handle, base_address, expected_nro_size, ro::impl::GenerateSecureRandom)) {
|
||||
R_CONVERT(os::ResultOutOfAddressSpace, ro::ResultOutOfAddressSpace())
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
/* When we're done, unmap the memory. */
|
||||
ON_SCOPE_EXIT { os::UnmapProcessMemory(mapped_memory, m_process_handle, base_address, expected_nro_size); };
|
||||
|
||||
/* ValidateNro */
|
||||
NroHeader *nro_header = nullptr;
|
||||
AdditionalNroHeaderInfo *additional_nro_header_info = nullptr;
|
||||
u8 additional_nro_header_hash[crypto::Sha256Generator::HashSize];
|
||||
R_TRY(this->ValidateNro(std::addressof(nro_header), std::addressof(additional_nro_header_info), std::addressof(additional_nro_header_hash), static_cast<u8 *>(mapped_memory), expected_nro_size, expected_bss_size));
|
||||
|
||||
/* DecompressNro */
|
||||
if (nro_header->IsCompress()) {
|
||||
R_TRY(this->DecompressNro(static_cast<u8 *>(mapped_memory), expected_nro_size, nro_header, additional_nro_header_info->compressed_size));
|
||||
|
||||
/* CheckAdditionalHeaderHash */
|
||||
if (nro_header->GetAdditionalHeaderOffset() != 0) {
|
||||
R_TRY(this->CheckAdditionalHeaderHash(static_cast<u8 *>(mapped_memory), std::addressof(additional_nro_header_hash), sizeof(additional_nro_header_hash), nro_header->GetRwOffset(), nro_header->GetRwSize()));
|
||||
}
|
||||
}
|
||||
|
||||
/* Apply patches to NRO. */
|
||||
LocateAndApplyIpsPatchesToModule(module_id, static_cast<u8 *>(mapped_memory), nro_size);
|
||||
const ModuleId *module_id = nro_header->GetModuleId();
|
||||
LocateAndApplyIpsPatchesToModule(module_id, static_cast<u8 *>(mapped_memory), nro_header->GetSize());
|
||||
|
||||
/* Copy to output. */
|
||||
*out_module_id = *module_id;
|
||||
*out_rx_size = text_size;
|
||||
*out_ro_size = ro_size;
|
||||
*out_rw_size = rw_size;
|
||||
*out_aligned_header = header->IsAlignedHeader();
|
||||
*out_rx_size = nro_header->GetTextSize();
|
||||
*out_ro_size = nro_header->GetRoSize();
|
||||
*out_rw_size = nro_header->GetRwSize();
|
||||
*out_aligned_header = nro_header->IsAlignedHeader();
|
||||
*out_is_compress = nro_header->IsCompress();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
@@ -547,26 +656,34 @@ namespace ams::ro::impl {
|
||||
/* Check we have space for a new NRO. */
|
||||
NroInfo *nro_info = nullptr;
|
||||
R_TRY(context->GetFreeNroInfo(std::addressof(nro_info)));
|
||||
nro_info->nro_heap_address = nro_address;
|
||||
nro_info->nro_heap_size = nro_size;
|
||||
nro_info->bss_heap_address = bss_address;
|
||||
nro_info->bss_heap_size = bss_size;
|
||||
|
||||
/* Map the NRO. */
|
||||
R_TRY(MapNro(std::addressof(nro_info->base_address), context->GetProcessHandle(), nro_address, nro_size, bss_address, bss_size));
|
||||
ON_RESULT_FAILURE { UnmapNro(context->GetProcessHandle(), nro_info->base_address, nro_address, nro_size, bss_address, bss_size); };
|
||||
|
||||
/* Validate the NRO (parsing region extents). */
|
||||
/* Parse the NRO. */
|
||||
u64 rx_size = 0, ro_size = 0, rw_size = 0;
|
||||
bool aligned_header = false;
|
||||
R_TRY(context->ValidateNro(std::addressof(nro_info->module_id), std::addressof(rx_size), std::addressof(ro_size), std::addressof(rw_size), std::addressof(aligned_header), nro_info->base_address, nro_size, bss_size));
|
||||
bool is_compress = false;
|
||||
R_TRY(context->ParseNro(std::addressof(nro_info->module_id), std::addressof(rx_size), std::addressof(ro_size), std::addressof(rw_size), std::addressof(aligned_header), std::addressof(is_compress), nro_info->base_address, nro_size, bss_size));
|
||||
|
||||
/* Set NRO perms. */
|
||||
R_TRY(SetNroPerms(context->GetProcessHandle(), nro_info->base_address, rx_size, ro_size, rw_size + bss_size, aligned_header));
|
||||
|
||||
context->SetNroInfoInUse(nro_info, true);
|
||||
nro_info->code_size = rx_size + ro_size;
|
||||
nro_info->nro_heap_address = nro_address;
|
||||
nro_info->nro_heap_size = nro_size;
|
||||
nro_info->bss_heap_address = bss_address;
|
||||
nro_info->bss_heap_size = bss_size;
|
||||
if (hos::GetVersion() >= hos::Version_23_0_0) {
|
||||
nro_info->code_size = rx_size;
|
||||
nro_info->ro_size = ro_size;
|
||||
} else {
|
||||
nro_info->code_size = rx_size + ro_size;
|
||||
nro_info->ro_size = 0;
|
||||
}
|
||||
nro_info->rw_size = rw_size;
|
||||
nro_info->is_compress = is_compress;
|
||||
*out_address = nro_info->base_address;
|
||||
R_SUCCEED();
|
||||
}
|
||||
@@ -583,6 +700,25 @@ namespace ams::ro::impl {
|
||||
NroInfo *nro_info = nullptr;
|
||||
R_TRY(context->GetNroInfoByAddress(std::addressof(nro_info), nro_address));
|
||||
|
||||
/* Handle compression related mappings. */
|
||||
if (nro_info->is_compress) {
|
||||
const u64 code_address = nro_info->base_address + 0x1000;
|
||||
const u64 code_size = nro_info->code_size - 0x1000;
|
||||
|
||||
/* Remove code region permissions. */
|
||||
R_TRY(os::SetProcessMemoryPermission(context->GetProcessHandle(), code_address, code_size, os::MemoryPermission_None));
|
||||
|
||||
/* Map the code region. */
|
||||
void *mapped_memory = nullptr;
|
||||
R_TRY(os::MapProcessMemory(std::addressof(mapped_memory), context->GetProcessHandle(), code_address, code_size, ro::impl::GenerateSecureRandom));
|
||||
|
||||
/* Clear the memory. */
|
||||
std::memset(mapped_memory, 0, code_size);
|
||||
|
||||
/* Unmap the code region. */
|
||||
os::UnmapProcessMemory(mapped_memory, context->GetProcessHandle(), code_address, code_size);
|
||||
}
|
||||
|
||||
/* Unmap. */
|
||||
const NroInfo nro_backup = *nro_info;
|
||||
{
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace ams::ro {
|
||||
R_RETURN(impl::RegisterProcess(std::addressof(m_context_id), std::move(process_h), client_pid.GetValue()));
|
||||
}
|
||||
|
||||
Result RoService::RegisterProcessModuleInfo(const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size, sf::CopyHandle &&process_h) {
|
||||
Result RoService::RegisterModuleInfoWithUserProcessHandle(const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size, sf::CopyHandle &&process_h) {
|
||||
/* Validate the process. */
|
||||
R_TRY(impl::ValidateProcess(m_context_id, client_pid.GetValue()));
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace ams::ro {
|
||||
Result RegisterModuleInfo(const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size);
|
||||
Result UnregisterModuleInfo(const sf::ClientProcessId &client_pid, u64 nrr_address);
|
||||
Result RegisterProcessHandle(const sf::ClientProcessId &client_pid, sf::CopyHandle &&process_h);
|
||||
Result RegisterProcessModuleInfo(const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size, sf::CopyHandle &&process_h);
|
||||
Result RegisterModuleInfoWithUserProcessHandle(const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size, sf::CopyHandle &&process_h);
|
||||
};
|
||||
static_assert(ro::impl::IsIRoInterface<RoService>);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user