From fff538e5637bd15eb5c47b50c48dabe1b1dbbdf2 Mon Sep 17 00:00:00 2001
From: "Admiral H. Curtiss" <pikachu025@gmail.com>
Date: Tue, 5 Dec 2023 22:34:35 +0100
Subject: [PATCH] Core/Boot: Check bounds in Load_BS2().

---
 Source/Core/Core/Boot/Boot.cpp | 36 ++++++++++++++++++++++++++--------
 1 file changed, 28 insertions(+), 8 deletions(-)

diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp
index 5fc52585e0..324bc5de22 100644
--- a/Source/Core/Core/Boot/Boot.cpp
+++ b/Source/Core/Core/Boot/Boot.cpp
@@ -5,6 +5,7 @@
 
 #include <algorithm>
 #include <array>
+#include <cmath>
 #include <cstring>
 #include <memory>
 #include <numeric>
@@ -399,12 +400,20 @@ bool CBoot::Load_BS2(Core::System& system, const std::string& boot_rom_filename)
   constexpr u32 PAL_v1_0 = 0x4F319F43;
   constexpr u32 PAL_v1_2 = 0xAD1B7F16;
 
-  // Load the whole ROM dump
-  std::string data;
-  if (!File::ReadFileToString(boot_rom_filename, data))
-    return false;
+  // Load the IPL ROM dump, limited to 2MiB which is the size of the official IPLs.
+  constexpr size_t max_ipl_size = 2 * 1024 * 1024;
+  std::vector<u8> data;
+  {
+    File::IOFile file(boot_rom_filename, "rb");
+    if (!file)
+      return false;
 
-  const u32 ipl_hash = Common::ComputeCRC32(data);
+    data.resize(static_cast<size_t>(std::min<u64>(file.GetSize(), max_ipl_size)));
+    if (!file.ReadArray(data.data(), data.size()))
+      return false;
+  }
+
+  const u32 ipl_hash = Common::ComputeCRC32(data.data(), data.size());
   bool known_ipl = false;
   bool pal_ipl = false;
   switch (ipl_hash)
@@ -433,15 +442,26 @@ bool CBoot::Load_BS2(Core::System& system, const std::string& boot_rom_filename)
   }
 
   // Run the descrambler over the encrypted section containing BS1/BS2
-  ExpansionInterface::CEXIIPL::Descrambler((u8*)data.data() + 0x100, 0x1AFE00);
+  if (data.size() > 0x100)
+  {
+    ExpansionInterface::CEXIIPL::Descrambler(
+        data.data() + 0x100, static_cast<u32>(std::min<size_t>(data.size() - 0x100, 0x1AFE00)));
+  }
 
   // TODO: Execution is supposed to start at 0xFFF00000, not 0x81200000;
   // copying the initial boot code to 0x81200000 is a hack.
   // For now, HLE the first few instructions and start at 0x81200150
   // to work around this.
   auto& memory = system.GetMemory();
-  memory.CopyToEmu(0x01200000, data.data() + 0x100, 0x700);
-  memory.CopyToEmu(0x01300000, data.data() + 0x820, 0x1AFE00);
+  if (data.size() > 0x100)
+  {
+    memory.CopyToEmu(0x01200000, data.data() + 0x100, std::min<size_t>(data.size() - 0x100, 0x700));
+  }
+  if (data.size() > 0x820)
+  {
+    memory.CopyToEmu(0x01300000, data.data() + 0x820,
+                     std::min<size_t>(data.size() - 0x820, 0x1AFE00));
+  }
 
   auto& ppc_state = system.GetPPCState();
   ppc_state.gpr[3] = 0xfff0001f;