Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ux/core: Add module verification step for some critical libraries #13017

Merged
merged 6 commits into from
Dec 6, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion rpcs3/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@
#include "Utilities/sema.h"
#include "Crypto/decrypt_binaries.h"
#ifdef _WIN32
#include <windows.h>
#include "module_verifier.hpp"
#include "util/dyn_lib.hpp"


// TODO([email protected])
// When compiling with WIN32_LEAN_AND_MEAN definition
// NTSTATUS is defined in CMake build but not in VS build
Expand Down Expand Up @@ -410,6 +411,13 @@ void fmt_class_string<std::chrono::sys_time<typename std::chrono::system_clock::
out += ss.str();
}

void run_platform_sanity_checks()
{
#ifdef _WIN32
// Check if we loaded modules correctly
WIN32_module_verifier::run();
#endif
}

int main(int argc, char** argv)
{
Expand Down Expand Up @@ -439,6 +447,9 @@ int main(int argc, char** argv)
report_fatal_error(error);
}

// Before we proceed, run some sanity checks
run_platform_sanity_checks();

const std::string lock_name = fs::get_cache_dir() + "RPCS3.buf";

static fs::file instance_lock;
Expand Down
82 changes: 82 additions & 0 deletions rpcs3/module_verifier.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#pragma once
#ifdef _WIN32

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include <Windows.h>

#include <util/types.hpp>
#include <Utilities/StrUtil.h>
#include <Utilities/StrFmt.h>

[[noreturn]] void report_fatal_error(std::string_view);

// Validates that system modules are properly installed
// Only relevant for WIN32
class WIN32_module_verifier
{
struct module_info_t
{
std::wstring_view name;
std::string_view package_name;
std::string_view dl_link;
};

const std::vector<module_info_t> special_module_infos = {
{ L"vulkan-1.dll", "Vulkan Runtime", "https://sdk.lunarg.com/sdk/download/latest/windows/vulkan-runtime.exe" },
{ L"msvcp140.dll", "C++ Redistributable for Visual Studio 2015", "https://www.microsoft.com/en-us/download/details.aspx?id=48145" },
kd-11 marked this conversation as resolved.
Show resolved Hide resolved
{ L"vcruntime140.dll", "C++ Redistributable for Visual Studio 2015", "https://www.microsoft.com/en-us/download/details.aspx?id=48145" },
{ L"msvcp140_1.dll", "C++ Redistributable for Visual Studio 2015", "https://www.microsoft.com/en-us/download/details.aspx?id=48145" },
{ L"vcruntime140_1.dll", "C++ Redistributable for Visual Studio 2015", "https://www.microsoft.com/en-us/download/details.aspx?id=48145" }
};

// Unless we support ReactOS in future, this is a constant
const std::wstring_view system_root = L"C:\\WINDOWS\\";

// Inline impl. This class is only referenced once.
void run_module_verification()
{
for (const auto& module : special_module_infos)
{
const auto hModule = GetModuleHandle(module.name.data());
if (hModule == NULL)
{
continue;
}

WCHAR path[MAX_PATH];
if (const auto len = GetModuleFileName(hModule, path, MAX_PATH))
{
const std::wstring_view s = path;
if (s.find(system_root) != 0)
{
const auto error_message = fmt::format(
"The module '%s' was incorrectly installed.\n"
"This module is part of the '%s' package.\n"
"You can install this package from this URL:\n"
"<a href='%s'>%s</a>",
wchar_to_utf8(module.name),
module.package_name,
module.dl_link,
module.dl_link
);
report_fatal_error(error_message);
}
}
}
}

WIN32_module_verifier() = default;

public:

static void run()
{
WIN32_module_verifier verifier{};
verifier.run_module_verification();
}
};

#endif // _WIN32
1 change: 1 addition & 0 deletions rpcs3/rpcs3.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -884,6 +884,7 @@
</CustomBuild>
<ClInclude Include="Input\pad_thread.h" />
<ClInclude Include="Input\product_info.h" />
<ClInclude Include="module_verifier.hpp" />
<ClInclude Include="QTGeneratedFiles\ui_about_dialog.h" />
<ClInclude Include="QTGeneratedFiles\ui_camera_settings_dialog.h" />
<ClInclude Include="QTGeneratedFiles\ui_main_window.h" />
Expand Down
3 changes: 3 additions & 0 deletions rpcs3/rpcs3.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -1037,6 +1037,9 @@
<ClInclude Include="Input\evdev_gun_handler.h">
<Filter>Io\evdev</Filter>
</ClInclude>
<ClInclude Include="module_verifier.hpp">
<Filter>rpcs3</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="debug\moc_predefs.h.cbt">
Expand Down
13 changes: 12 additions & 1 deletion rpcs3/rpcs3qt/fatal_error_dialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,17 @@
#include <QTextDocument>
#include <QIcon>

static QString process_dialog_text(std::string_view text)
{
auto html = Qt::convertFromPlainText(QString::fromUtf8(text.data(), text.size()));

// Let's preserve some html elements destroyed by convertFromPlainText
const QRegExp link_re{ R"(&lt;a\shref='([a-z0-9?=&#:\/\.\-]+)'&gt;([a-z0-9?=&#:\/\.\-]+)&lt;\/a&gt;)", Qt::CaseSensitive, QRegExp::RegExp2};
kd-11 marked this conversation as resolved.
Show resolved Hide resolved
html = html.replace(link_re, "<a href=\\1>\\2</a>");

return html;
}

fatal_error_dialog::fatal_error_dialog(std::string_view text) : QMessageBox()
{
#ifndef __APPLE__
Expand All @@ -20,7 +31,7 @@ fatal_error_dialog::fatal_error_dialog(std::string_view text) : QMessageBox()
%3<br>
</p>
)")
.arg(Qt::convertFromPlainText(QString::fromUtf8(text.data(), text.size())))
.arg(process_dialog_text(text))
.arg(tr("HOW TO REPORT ERRORS:"))
.arg(tr("Please, don't send incorrect reports. Thanks for understanding.")));
layout()->setSizeConstraint(QLayout::SetFixedSize);
Expand Down