Skip to content

Commit

Permalink
Merge branch 'xenia-canary:canary_experimental' into Custom
Browse files Browse the repository at this point in the history
  • Loading branch information
backgamon authored Sep 7, 2024
2 parents 8c66bd1 + 71de564 commit fe4bdac
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 40 deletions.
14 changes: 2 additions & 12 deletions src/xenia/cpu/xex_module.cc
Original file line number Diff line number Diff line change
Expand Up @@ -230,18 +230,6 @@ int XexModule::ApplyPatch(XexModule* module) {
reinterpret_cast<void**>(&patch_header));
assert_not_null(patch_header);

// Compare hash inside delta descriptor to base XEX signature
uint8_t digest[0x14];
sha1::SHA1 s;
s.processBytes(module->xex_security_info()->rsa_signature, 0x100);
s.finalize(digest);

if (memcmp(digest, patch_header->digest_source, 0x14) != 0) {
XELOGW(
"XEX patch signature hash doesn't match base XEX signature hash, patch "
"will likely fail!");
}

uint32_t size = module->xex_header()->header_size;
if (patch_header->delta_headers_source_offset > size) {
XELOGE("XEX header patch source is outside base XEX header area");
Expand Down Expand Up @@ -419,6 +407,8 @@ int XexModule::ApplyPatch(XexModule* module) {
original_image_size - image_target_size);
}

uint8_t digest[0x14];
sha1::SHA1 s;
// Now loop through each block and apply the delta patches inside
while (cur_block->block_size) {
const auto* next_block = (const xex2_compressed_block_info*)p;
Expand Down
132 changes: 105 additions & 27 deletions src/xenia/kernel/kernel_state.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
#include "xenia/kernel/xnotifylistener.h"
#include "xenia/kernel/xobject.h"
#include "xenia/kernel/xthread.h"
#include "xenia/ui/imgui_host_notification.h"

#include "third_party/crypto/TinySHA1.hpp"

DEFINE_bool(apply_title_update, true, "Apply title updates.", "Kernel");

Expand Down Expand Up @@ -550,28 +553,59 @@ X_RESULT KernelState::FinishLoadingUserModule(
return result;
}

X_RESULT KernelState::ApplyTitleUpdate(const object_ref<UserModule> module) {
X_RESULT result = X_STATUS_SUCCESS;
if (!cvars::apply_title_update) {
return result;
X_RESULT KernelState::ApplyTitleUpdate(
const object_ref<UserModule> title_module) {
const auto title_updates = FindTitleUpdate(title_module->title_id());
if (title_updates.empty()) {
return X_STATUS_SUCCESS;
}

std::vector<xam::XCONTENT_AGGREGATE_DATA> tu_list =
content_manager()->ListContent(1, xe::XContentType::kInstaller,
module->title_id());
auto patch_module = LoadTitleUpdate(&title_updates.front(), title_module);
if (!patch_module) {
return X_STATUS_SUCCESS;
}

if (tu_list.empty()) {
return result;
if (!patch_module->xex_module()->is_patch()) {
return X_STATUS_UNSUCCESSFUL;
}

if (!IsPatchSignatureProper(title_module, patch_module)) {
// First module that is loaded is always main executable. That way we can
// prevent random message spam in case of loading/unloading.
if (!GetExecutableModule()) {
emulator_->display_window()->app_context().CallInUIThread([&]() {
new xe::ui::HostNotificationWindow(
emulator_->imgui_drawer(), "Warning!",
"Title Update signature doesn't match. This can cause unexpected "
"issues or crashes!",
0);
});
}
}

return ApplyTitleUpdate(title_module, patch_module);
}

std::vector<xam::XCONTENT_AGGREGATE_DATA> KernelState::FindTitleUpdate(
const uint32_t title_id) const {
if (!cvars::apply_title_update) {
return {};
}

return content_manager()->ListContent(1, xe::XContentType::kInstaller,
title_id);
}

const object_ref<UserModule> KernelState::LoadTitleUpdate(
const xam::XCONTENT_AGGREGATE_DATA* title_update,
const object_ref<UserModule> module) {
uint32_t disc_number = -1;
if (module->is_multi_disc_title()) {
disc_number = module->disc_number();
}
// TODO(Gliniak): Support for selecting from multiple TUs
const xam::XCONTENT_AGGREGATE_DATA& title_update = tu_list.front();

X_RESULT open_status =
content_manager()->OpenContent("UPDATE", title_update, disc_number);
content_manager()->OpenContent("UPDATE", *title_update, disc_number);

// Use the corresponding patch for the launch module
std::filesystem::path patch_xexp;
Expand All @@ -582,7 +616,7 @@ X_RESULT KernelState::ApplyTitleUpdate(const object_ref<UserModule> module) {
auto is_relative = std::filesystem::relative(module->path(), mount_path);

if (is_relative.empty()) {
return X_STATUS_UNSUCCESSFUL;
return nullptr;
}

patch_xexp =
Expand All @@ -593,22 +627,66 @@ X_RESULT KernelState::ApplyTitleUpdate(const object_ref<UserModule> module) {
xe::vfs::Entry* patch_entry = kernel_state()->file_system()->ResolvePath(
resolved_path + patch_xexp.generic_string());

if (patch_entry) {
const std::string patch_path = patch_entry->absolute_path();
XELOGI("Loading XEX patch from {}", patch_path);
auto patch_module = object_ref<UserModule>(new UserModule(this));
if (!patch_entry) {
return nullptr;
}

result = patch_module->LoadFromFile(patch_path);
if (result != X_STATUS_SUCCESS) {
XELOGE("Failed to load XEX patch, code: {}", result);
return X_STATUS_UNSUCCESSFUL;
}
const std::string patch_path = patch_entry->absolute_path();
XELOGI("Loading XEX patch from {}", patch_path);
auto patch_module = object_ref<UserModule>(new UserModule(this));

result = patch_module->xex_module()->ApplyPatch(module->xex_module());
if (result != X_STATUS_SUCCESS) {
XELOGE("Failed to apply XEX patch, code: {}", result);
return X_STATUS_UNSUCCESSFUL;
}
X_RESULT result = patch_module->LoadFromFile(patch_path);
if (result != X_STATUS_SUCCESS) {
XELOGE("Failed to load XEX patch, code: {}", result);
return nullptr;
}

return patch_module;
}

bool KernelState::IsPatchSignatureProper(
const object_ref<UserModule> title_module,
const object_ref<UserModule> patch_module) const {
xex2_opt_delta_patch_descriptor* patch_header = nullptr;
patch_module->GetOptHeader(XEX_HEADER_DELTA_PATCH_DESCRIPTOR,
reinterpret_cast<void**>(&patch_header));

assert_not_null(patch_header);

// Compare hash inside delta descriptor to base XEX signature
uint8_t digest[0x14];
sha1::SHA1 s;
s.processBytes(title_module->xex_module()->xex_security_info()->rsa_signature,
0x100);
s.finalize(digest);

if (memcmp(digest, patch_header->digest_source, 0x14) != 0) {
XELOGW(
"XEX patch signature hash doesn't match base XEX signature hash, patch "
"will likely fail!");

return false;
}
return true;
}

X_RESULT KernelState::ApplyTitleUpdate(
const object_ref<UserModule> title_module,
const object_ref<UserModule> patch_module) {
if (!title_module) {
XELOGE("{}: No title_module provided!", __FUNCTION__);
return X_STATUS_UNSUCCESSFUL;
}

if (!patch_module) {
XELOGE("{}: No patch_module provided!", __FUNCTION__);
return X_STATUS_UNSUCCESSFUL;
}

X_STATUS result =
patch_module->xex_module()->ApplyPatch(title_module->xex_module());
if (result != X_STATUS_SUCCESS) {
XELOGE("Failed to apply XEX patch, code: {}", result);
}
return result;
}
Expand Down
14 changes: 13 additions & 1 deletion src/xenia/kernel/kernel_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ class KernelState {
return object_ref<T>(reinterpret_cast<T*>(module.release()));
}

X_RESULT ApplyTitleUpdate(const object_ref<UserModule> module);
X_RESULT ApplyTitleUpdate(const object_ref<UserModule> title_module);
// Terminates a title: Unloads all modules, and kills all guest threads.
// This DOES NOT RETURN if called from a guest thread!
void TerminateTitle();
Expand Down Expand Up @@ -352,6 +352,18 @@ class KernelState {
void SetProcessTLSVars(X_KPROCESS* process, int num_slots, int tls_data_size,
int tls_static_data_address);
void InitializeKernelGuestGlobals();

std::vector<xam::XCONTENT_AGGREGATE_DATA> FindTitleUpdate(
const uint32_t title_id) const;
const object_ref<UserModule> LoadTitleUpdate(
const xam::XCONTENT_AGGREGATE_DATA* title_update,
const object_ref<UserModule> module);
bool IsPatchSignatureProper(const object_ref<UserModule> title_module,
const object_ref<UserModule> patch_module) const;

X_RESULT ApplyTitleUpdate(const object_ref<UserModule> title_module,
const object_ref<UserModule> patch_module);

Emulator* emulator_;
Memory* memory_;
cpu::Processor* processor_;
Expand Down

0 comments on commit fe4bdac

Please sign in to comment.