Skip to content

Commit

Permalink
Merge branch 'main' into PR/null-deref-crash-fix
Browse files Browse the repository at this point in the history
  • Loading branch information
Alystrasz authored Dec 4, 2023
2 parents d2ffd6f + ad1b6ae commit e8b99a3
Show file tree
Hide file tree
Showing 10 changed files with 99 additions and 51 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: DoozyX/clang-format-lint-action@v0.13
- uses: DoozyX/clang-format-lint-action@v0.16.2
with:
source: 'NorthstarDLL NorthstarLauncher'
exclude: 'NorthstarDLL/include loader_launcher_proxy loader_wsock32_proxy'
Expand Down
1 change: 0 additions & 1 deletion NorthstarDLL/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,6 @@ add_library(NorthstarDLL SHARED
"util/version.h"
"util/wininfo.cpp"
"util/wininfo.h"
"audio_asm.asm"
"dllmain.cpp"
"dllmain.h"
"ns_version.h"
Expand Down
8 changes: 0 additions & 8 deletions NorthstarDLL/audio_asm.asm

This file was deleted.

33 changes: 11 additions & 22 deletions NorthstarDLL/client/audio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,7 @@

AUTOHOOK_INIT()

extern "C"
{
// should be called only in LoadSampleMetadata_Hook
extern void* __fastcall Audio_GetParentEvent();
}
static const char* pszAudioEventName;

ConVar* Cvar_mileslog_enable;
ConVar* Cvar_ns_print_played_sounds;
Expand Down Expand Up @@ -366,32 +362,16 @@ bool ShouldPlayAudioEvent(const char* eventName, const std::shared_ptr<EventOver
return true; // good to go
}

// forward declare
bool __declspec(noinline) __fastcall LoadSampleMetadata_Internal(
uintptr_t parentEvent, void* sample, void* audioBuffer, unsigned int audioBufferLength, int audioType);

// DO NOT TOUCH THIS FUNCTION
// The actual logic of it in a separate function (forcefully not inlined) to preserve the r12 register, which holds the event pointer.
// clang-format off
AUTOHOOK(LoadSampleMetadata, mileswin64.dll + 0xF110,
bool, __fastcall, (void* sample, void* audioBuffer, unsigned int audioBufferLength, int audioType))
// clang-format on
{
uintptr_t parentEvent = (uintptr_t)Audio_GetParentEvent();

// Raw source, used for voice data only
if (audioType == 0)
return LoadSampleMetadata(sample, audioBuffer, audioBufferLength, audioType);

return LoadSampleMetadata_Internal(parentEvent, sample, audioBuffer, audioBufferLength, audioType);
}

// DO NOT INLINE THIS FUNCTION
// See comment below.
bool __declspec(noinline) __fastcall LoadSampleMetadata_Internal(
uintptr_t parentEvent, void* sample, void* audioBuffer, unsigned int audioBufferLength, int audioType)
{
char* eventName = (char*)parentEvent + 0x110;
const char* eventName = pszAudioEventName;

if (Cvar_ns_print_played_sounds->GetInt() > 0)
spdlog::info("[AUDIO] Playing event {}", eventName);
Expand Down Expand Up @@ -490,6 +470,15 @@ bool __declspec(noinline) __fastcall LoadSampleMetadata_Internal(
return res;
}

// clang-format off
AUTOHOOK(sub_1800294C0, mileswin64.dll + 0x294C0,
void*, __fastcall, (void* a1, void* a2))
// clang-format on
{
pszAudioEventName = reinterpret_cast<const char*>((*((__int64*)a2 + 6)));
return sub_1800294C0(a1, a2);
}

// clang-format off
AUTOHOOK(MilesLog, client.dll + 0x57DAD0,
void, __fastcall, (int level, const char* string))
Expand Down
7 changes: 6 additions & 1 deletion NorthstarDLL/core/hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#include <filesystem>
#include <Psapi.h>

#define XINPUT1_3_DLL "XInput1_3.dll"

AUTOHOOK_INIT()

// called from the ON_DLL_LOAD macros
Expand Down Expand Up @@ -393,8 +395,11 @@ HMODULE, WINAPI, (LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags))
{
HMODULE moduleAddress;

LPCSTR lpLibFileNameEnd = lpLibFileName + strlen(lpLibFileName);
LPCSTR lpLibName = lpLibFileNameEnd - strlen(XINPUT1_3_DLL);

// replace xinput dll with one that has ASLR
if (!strncmp(lpLibFileName, "XInput1_3.dll", 14))
if (lpLibFileName <= lpLibName && !strncmp(lpLibName, XINPUT1_3_DLL, strlen(XINPUT1_3_DLL) + 1))
{
moduleAddress = _LoadLibraryExA("XInput9_1_0.dll", hFile, dwFlags);

Expand Down
41 changes: 29 additions & 12 deletions NorthstarDLL/masterserver/masterserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "shared/misccommands.h"
#include "util/version.h"
#include "server/auth/bansystem.h"
#include "dedicated/dedicated.h"

#include "rapidjson/document.h"
#include "rapidjson/stringbuffer.h"
Expand Down Expand Up @@ -1128,7 +1129,9 @@ void MasterServerPresenceReporter::RunFrame(double flCurrentTime, const ServerPr

if (m_nNumRegistrationAttempts >= MAX_REGISTRATION_ATTEMPTS)
{
spdlog::error("Reached max ms server registration attempts.");
spdlog::log(
IsDedicatedServer() ? spdlog::level::level_enum::err : spdlog::level::level_enum::warn,
"Reached max ms server registration attempts.");
}
}
else if (updateServerFuture.valid())
Expand Down Expand Up @@ -1181,7 +1184,7 @@ void MasterServerPresenceReporter::InternalAddServer(const ServerPresence* pServ

addServerFuture = std::async(
std::launch::async,
[threadedPresence, modInfo, hostname]
[threadedPresence, modInfo, hostname, pServerPresence]
{
CURL* curl = curl_easy_init();
SetCommonHttpClientOptions(curl);
Expand Down Expand Up @@ -1209,6 +1212,11 @@ void MasterServerPresenceReporter::InternalAddServer(const ServerPresence* pServ
return data;
};

// don't log errors if we wouldn't actually show up in the server list anyway (stop tickets)
// except for dedis, for which this error logging is actually pretty important
bool shouldLogError = IsDedicatedServer() || (!strstr(pServerPresence->m_MapName, "mp_lobby") &&
strstr(pServerPresence->m_PlaylistName, "private_match"));

curl_mime_data(part, modInfo.c_str(), modInfo.size());
curl_mime_name(part, "modinfo");
curl_mime_filename(part, "modinfo.json");
Expand Down Expand Up @@ -1258,22 +1266,27 @@ void MasterServerPresenceReporter::InternalAddServer(const ServerPresence* pServ
// No retry.
if (serverAddedJson.HasParseError())
{
spdlog::error(
"Failed reading masterserver authentication response: encountered parse error \"{}\"",
rapidjson::GetParseError_En(serverAddedJson.GetParseError()));
if (shouldLogError)
spdlog::error(
"Failed reading masterserver authentication response: encountered parse error \"{}\"",
rapidjson::GetParseError_En(serverAddedJson.GetParseError()));
return ReturnCleanup(MasterServerReportPresenceResult::FailedNoRetry);
}

if (!serverAddedJson.IsObject())
{
spdlog::error("Failed reading masterserver authentication response: root object is not an object");
if (shouldLogError)
spdlog::error("Failed reading masterserver authentication response: root object is not an object");
return ReturnCleanup(MasterServerReportPresenceResult::FailedNoRetry);
}

if (serverAddedJson.HasMember("error"))
{
spdlog::error("Failed reading masterserver response: got fastify error response");
spdlog::error(readBuffer);
if (shouldLogError)
{
spdlog::error("Failed reading masterserver response: got fastify error response");
spdlog::error(readBuffer);
}

// If this is DUPLICATE_SERVER, we'll retry adding the server every 20 seconds.
// The master server will only update its internal server list and clean up dead servers on certain events.
Expand All @@ -1282,7 +1295,8 @@ void MasterServerPresenceReporter::InternalAddServer(const ServerPresence* pServ
if (serverAddedJson["error"].HasMember("enum") &&
strcmp(serverAddedJson["error"]["enum"].GetString(), "DUPLICATE_SERVER") == 0)
{
spdlog::error("Cooling down while the master server cleans the dead server entry, if any.");
if (shouldLogError)
spdlog::error("Cooling down while the master server cleans the dead server entry, if any.");
return ReturnCleanup(MasterServerReportPresenceResult::FailedDuplicateServer);
}

Expand All @@ -1292,14 +1306,16 @@ void MasterServerPresenceReporter::InternalAddServer(const ServerPresence* pServ

if (!serverAddedJson["success"].IsTrue())
{
spdlog::error("Adding server to masterserver failed: \"success\" is not true");
if (shouldLogError)
spdlog::error("Adding server to masterserver failed: \"success\" is not true");
return ReturnCleanup(MasterServerReportPresenceResult::FailedNoRetry);
}

if (!serverAddedJson.HasMember("id") || !serverAddedJson["id"].IsString() ||
!serverAddedJson.HasMember("serverAuthToken") || !serverAddedJson["serverAuthToken"].IsString())
{
spdlog::error("Failed reading masterserver response: malformed json object");
if (shouldLogError)
spdlog::error("Failed reading masterserver response: malformed json object");
return ReturnCleanup(MasterServerReportPresenceResult::FailedNoRetry);
}

Expand All @@ -1311,7 +1327,8 @@ void MasterServerPresenceReporter::InternalAddServer(const ServerPresence* pServ
}
else
{
spdlog::error("Failed adding self to server list: error {}", curl_easy_strerror(result));
if (shouldLogError)
spdlog::error("Failed adding self to server list: error {}", curl_easy_strerror(result));
return ReturnCleanup(MasterServerReportPresenceResult::FailedNoConnect);
}
});
Expand Down
4 changes: 2 additions & 2 deletions NorthstarDLL/mods/autodownload/moddownloader.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ class ModDownloader
const char* VERIFICATION_FLAG = "-disablemodverification";
const char* CUSTOM_MODS_URL_FLAG = "-customverifiedurl=";
const char* STORE_URL = "https://gcdn.thunderstore.io/live/repository/packages/";
const char* DEFAULT_MODS_LIST_URL = "https://raw.githubusercontent.com/R2Northstar/VerifiedMods/master/mods.json";
const char* DEFAULT_MODS_LIST_URL = "https://raw.githubusercontent.com/R2Northstar/VerifiedMods/master/verified-mods.json";
char* modsListUrl;

struct VerifiedModVersion
Expand Down Expand Up @@ -83,7 +83,7 @@ class ModDownloader
* The Northstar auto-downloading feature does NOT allow automatically installing
* all mods for various (notably security) reasons; mods that are candidate to
* auto-downloading are rather listed on a GitHub repository
* (https://raw.githubusercontent.com/R2Northstar/VerifiedMods/master/mods.json),
* (https://raw.githubusercontent.com/R2Northstar/VerifiedMods/master/verified-mods.json),
* which this method gets via a HTTP call to load into local state.
*
* If list fetching fails, local mods list will be initialized as empty, thus
Expand Down
4 changes: 2 additions & 2 deletions NorthstarDLL/mods/modmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -696,9 +696,9 @@ void ModManager::LoadMods()
if (mod.m_bWasReadSuccessfully)
{
if (mod.m_bEnabled)
spdlog::info("'{}' loaded successfully", mod.Name);
spdlog::info("'{}' loaded successfully, version {}", mod.Name, mod.Version);
else
spdlog::info("'{}' loaded successfully (DISABLED)", mod.Name);
spdlog::info("'{}' loaded successfully, version {} (DISABLED)", mod.Name, mod.Version);

m_LoadedMods.push_back(mod);
}
Expand Down
14 changes: 12 additions & 2 deletions NorthstarDLL/plugins/plugins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ std::optional<Plugin> PluginManager::LoadPlugin(fs::path path, PluginInitFuncs*
}
// Passed all checks, going to actually load it now

HMODULE pluginLib = LoadLibraryW(wpptr); // Load the DLL as a data file
HMODULE pluginLib =
LoadLibraryExW(wpptr, 0, LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); // Load the DLL with lib folders
if (pluginLib == NULL)
{
NS::log::PLUGINSYS->info("Failed to load library '{}': ", std::system_category().message(GetLastError()));
Expand Down Expand Up @@ -197,7 +198,7 @@ inline void FindPlugins(fs::path pluginPath, std::vector<fs::path>& paths)
return;
}

for (const fs::directory_entry& entry : fs::recursive_directory_iterator(pluginPath))
for (const fs::directory_entry& entry : fs::directory_iterator(pluginPath))
{
if (fs::is_regular_file(entry) && entry.path().extension() == ".dll")
paths.emplace_back(entry.path());
Expand Down Expand Up @@ -229,6 +230,10 @@ bool PluginManager::LoadPlugins()
data.version = ns_version.c_str();
data.northstarModule = g_NorthstarModule;

fs::path libPath = fs::absolute(pluginPath + "\\lib");
if (fs::exists(libPath) && fs::is_directory(libPath))
AddDllDirectory(libPath.wstring().c_str());

FindPlugins(pluginPath, paths);

// Special case for Thunderstore mods dir
Expand All @@ -244,6 +249,11 @@ bool PluginManager::LoadPlugins()
spdlog::warn("The following directory did not match 'AUTHOR-MOD-VERSION': {}", dir.path().string());
continue; // skip loading package that doesn't match
}

fs::path libDir = fs::absolute(pluginsDir / "lib");
if (fs::exists(libDir) && fs::is_directory(libDir))
AddDllDirectory(libDir.wstring().c_str());

FindPlugins(pluginsDir, paths);
}

Expand Down
36 changes: 36 additions & 0 deletions NorthstarDLL/util/printmaps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ struct MapVPKInfo
// our current list of maps in the game
std::vector<MapVPKInfo> vMapList;

typedef void (*Host_Map_helperType)(const CCommand&, void*);
typedef void (*Host_Changelevel_fType)(const CCommand&);

Host_Map_helperType Host_Map_helper;
Host_Changelevel_fType Host_Changelevel_f;

void RefreshMapList()
{
// Only update the maps list every 10 seconds max to we avoid constantly reading fs
Expand Down Expand Up @@ -188,10 +194,40 @@ void ConCommand_maps(const CCommand& args)
spdlog::info("({}) {}", PrintMapSource.at(map.source), map.name);
}

// clang-format off
AUTOHOOK(Host_Map_f, engine.dll + 0x15B340, void, __fastcall, (const CCommand& args))
// clang-format on
{
RefreshMapList();

if (args.ArgC() > 1 &&
std::find_if(vMapList.begin(), vMapList.end(), [&](MapVPKInfo map) -> bool { return map.name == args.Arg(1); }) == vMapList.end())
{
spdlog::warn("Map load failed: {} not found or invalid", args.Arg(1));
return;
}
else if (args.ArgC() == 1)
{
spdlog::warn("Map load failed: no map name provided");
return;
}

if (*R2::g_pServerState >= R2::server_state_t::ss_active)
return Host_Changelevel_f(args);
else
return Host_Map_helper(args, nullptr);
}

void InitialiseMapsPrint()
{
AUTOHOOK_DISPATCH()

ConCommand* mapsCommand = R2::g_pCVar->FindCommand("maps");
mapsCommand->m_pCommandCallback = ConCommand_maps;
}

ON_DLL_LOAD("engine.dll", Host_Map_f, (CModule module))
{
Host_Map_helper = module.Offset(0x15AEF0).RCast<Host_Map_helperType>();
Host_Changelevel_f = module.Offset(0x15AAD0).RCast<Host_Changelevel_fType>();
}

0 comments on commit e8b99a3

Please sign in to comment.