[Kernel] Cleanup in TU applying code.
Externally it is still applied via: ApplyTitleUpdate But internally it is splitted into: - FindTitleUpdate - LoadTitleUpdate - IsPatchSignatureProper - ApplyTitleUpdate Added host window with warning about TU incompatibility
This commit is contained in:
parent
0ee6c77d91
commit
71de56416d
|
@ -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");
|
||||
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
@ -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;
|
||||
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;
|
||||
}
|
||||
|
||||
auto patch_module = LoadTitleUpdate(&title_updates.front(), title_module);
|
||||
if (!patch_module) {
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
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 result;
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<xam::XCONTENT_AGGREGATE_DATA> tu_list =
|
||||
content_manager()->ListContent(1, xe::XContentType::kInstaller,
|
||||
module->title_id());
|
||||
|
||||
if (tu_list.empty()) {
|
||||
return result;
|
||||
}
|
||||
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;
|
||||
|
@ -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 =
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
@ -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_;
|
||||
|
|
Loading…
Reference in New Issue