瀏覽代碼

loader: provide default arguments (zero byte) to NSOs

Certain newer unity games (Terraria, Pokemon Mystery Dungeon) require
that the argument region be populated. Failure to do so results in
an integer underflow in argument count, and eventually an unmapped
read at 0x800000000. Providing this default fixes this.

Note that the behavior of official software is as yet unverified,
arguments-wise.
Michael Scire 6 年之前
父節點
當前提交
5a7eecc3ad
共有 2 個文件被更改,包括 10 次插入3 次删除
  1. 8 3
      src/core/loader/nso.cpp
  2. 2 0
      src/core/loader/nso.h

+ 8 - 3
src/core/loader/nso.cpp

@@ -97,7 +97,8 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process,
         if (nso_header.IsSegmentCompressed(i)) {
             data = DecompressSegment(data, nso_header.segments[i]);
         }
-        program_image.resize(nso_header.segments[i].location + data.size());
+        program_image.resize(nso_header.segments[i].location +
+                             PageAlignSize(static_cast<u32>(data.size())));
         std::memcpy(program_image.data() + nso_header.segments[i].location, data.data(),
                     data.size());
         codeset.segments[i].addr = nso_header.segments[i].location;
@@ -105,8 +106,12 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process,
         codeset.segments[i].size = PageAlignSize(static_cast<u32>(data.size()));
     }
 
-    if (should_pass_arguments && !Settings::values.program_args.empty()) {
-        const auto arg_data = Settings::values.program_args;
+    if (should_pass_arguments) {
+        std::vector<u8> arg_data{Settings::values.program_args.begin(),
+                                 Settings::values.program_args.end()};
+        if (arg_data.empty()) {
+            arg_data.resize(NSO_ARGUMENT_DEFAULT_SIZE);
+        }
         codeset.DataSegment().size += NSO_ARGUMENT_DATA_ALLOCATION_SIZE;
         NSOArgumentHeader args_header{
             NSO_ARGUMENT_DATA_ALLOCATION_SIZE, static_cast<u32_le>(arg_data.size()), {}};

+ 2 - 0
src/core/loader/nso.h

@@ -56,6 +56,8 @@ static_assert(sizeof(NSOHeader) == 0x100, "NSOHeader has incorrect size.");
 static_assert(std::is_trivially_copyable_v<NSOHeader>, "NSOHeader must be trivially copyable.");
 
 constexpr u64 NSO_ARGUMENT_DATA_ALLOCATION_SIZE = 0x9000;
+// NOTE: Official software default argument state is unverified.
+constexpr u64 NSO_ARGUMENT_DEFAULT_SIZE = 1;
 
 struct NSOArgumentHeader {
     u32_le allocated_size;