From 3140086c60118834fb673bc0b07bcda007520f62 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=A9o=20Lam?= <leo@leolam.fr>
Date: Sat, 21 Dec 2019 13:31:34 +0100
Subject: [PATCH] file_sys: Handle patch applying failures

This changes ApplyCodePatch to return a ResultStatus, which makes it
possible to determine whether patch applying has failed. Previously,
only a boolean was returned, and false was returned when no patch
was found OR when a patch was found but applying it failed.

This also changes AppLoader_NCCH to return an error if patching fails
because the executable is likely to be left in an inconsistent state
and we should not proceed booting in that case.
---
 src/core/file_sys/ncch_container.cpp | 12 +++++++-----
 src/core/file_sys/ncch_container.h   |  4 ++--
 src/core/loader/ncch.cpp             |  6 ++++--
 3 files changed, 13 insertions(+), 9 deletions(-)

diff --git a/src/core/file_sys/ncch_container.cpp b/src/core/file_sys/ncch_container.cpp
index 0412fa288..ec6bb3827 100644
--- a/src/core/file_sys/ncch_container.cpp
+++ b/src/core/file_sys/ncch_container.cpp
@@ -507,20 +507,22 @@ Loader::ResultStatus NCCHContainer::LoadSectionExeFS(const char* name, std::vect
     return Loader::ResultStatus::ErrorNotUsed;
 }
 
-bool NCCHContainer::ApplyCodePatch(std::vector<u8>& code) const {
+Loader::ResultStatus NCCHContainer::ApplyCodePatch(std::vector<u8>& code) const {
     const std::string override_ips = filepath + ".exefsdir/code.ips";
 
     FileUtil::IOFile ips_file{override_ips, "rb"};
     if (!ips_file)
-        return false;
+        return Loader::ResultStatus::ErrorNotUsed;
 
     std::vector<u8> ips(ips_file.GetSize());
     if (ips_file.ReadBytes(ips.data(), ips.size()) != ips.size())
-        return false;
+        return Loader::ResultStatus::Error;
 
     LOG_INFO(Service_FS, "File {} patching code.bin", override_ips);
-    Patch::ApplyIpsPatch(ips, code);
-    return true;
+    if (!Patch::ApplyIpsPatch(ips, code))
+        return Loader::ResultStatus::Error;
+
+    return Loader::ResultStatus::Success;
 }
 
 Loader::ResultStatus NCCHContainer::LoadOverrideExeFSSection(const char* name,
diff --git a/src/core/file_sys/ncch_container.h b/src/core/file_sys/ncch_container.h
index 8752ffe39..f06ee8ef6 100644
--- a/src/core/file_sys/ncch_container.h
+++ b/src/core/file_sys/ncch_container.h
@@ -274,9 +274,9 @@ public:
     /**
      * Apply a patch for .code (if it exists).
      * This should only be called after allocating .bss.
-     * @return bool true if a patch was applied, false otherwise
+     * @return ResultStatus success if a patch was applied, ErrorNotUsed if no patch was found
      */
-    bool ApplyCodePatch(std::vector<u8>& code) const;
+    Loader::ResultStatus ApplyCodePatch(std::vector<u8>& code) const;
 
     /**
      * Checks whether the NCCH container contains an ExeFS
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index 07edad796..2e688e011 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -100,8 +100,10 @@ ResultStatus AppLoader_NCCH::LoadExec(std::shared_ptr<Kernel::Process>& process)
             overlay_ncch->exheader_header.codeset_info.data.num_max_pages * Memory::PAGE_SIZE +
             bss_page_size;
 
-        // Apply any IPS patch now that the entire codeset (including .bss) has been allocated
-        overlay_ncch->ApplyCodePatch(code);
+        // Apply patches now that the entire codeset (including .bss) has been allocated
+        const ResultStatus patch_result = overlay_ncch->ApplyCodePatch(code);
+        if (patch_result != ResultStatus::Success && patch_result != ResultStatus::ErrorNotUsed)
+            return patch_result;
 
         codeset->entrypoint = codeset->CodeSegment().addr;
         codeset->memory = std::move(code);