From 5577ad303caa037124935f996d65d063aa510acd Mon Sep 17 00:00:00 2001 From: Bob Sira Date: Thu, 6 Aug 2026 18:08:28 +0100 Subject: [PATCH] fix(logmonitor): allow absolute /Config paths again Restore support for absolute config paths while preserving relative path hardening for /Config. Fixes regression introduced in 2.2.0 (issue #229). --- LogMonitor/src/LogMonitor/Main.cpp | 71 +++++++++++++++++++----------- 1 file changed, 45 insertions(+), 26 deletions(-) diff --git a/LogMonitor/src/LogMonitor/Main.cpp b/LogMonitor/src/LogMonitor/Main.cpp index 8d94d1d..b8da8b9 100644 --- a/LogMonitor/src/LogMonitor/Main.cpp +++ b/LogMonitor/src/LogMonitor/Main.cpp @@ -249,6 +249,50 @@ void CreateEtwMonitor( } } +bool ResolveConfigPath(const std::wstring& userConfigName, std::wstring& resolvedConfigPath) +{ + // Preserve support for absolute paths passed via /Config. + if (!PathIsRelativeW(userConfigName.c_str())) + { + resolvedConfigPath = userConfigName; + return true; + } + + // Relative paths must be plain file names rooted under the executable directory. + if (userConfigName.find(L"..") != std::wstring::npos || + userConfigName.find(L'/') != std::wstring::npos || + userConfigName.find(L'\\') != std::wstring::npos || + userConfigName.find(L':') != std::wstring::npos) + { + return false; + } + + WCHAR modulePath[MAX_PATH] = {}; + if (GetModuleFileNameW(nullptr, modulePath, _countof(modulePath)) == 0) + { + logWriter.TraceError( + Utility::FormatString(L"Failed to get module path. Error: %d", GetLastError()).c_str() + ); + return false; + } + + if (!PathRemoveFileSpecW(modulePath)) + { + logWriter.TraceError(L"Failed to resolve executable directory."); + return false; + } + + WCHAR combinedPath[MAX_PATH] = {}; + if (PathCombineW(combinedPath, modulePath, userConfigName.c_str()) == nullptr) + { + logWriter.TraceError(L"Failed to resolve configuration file path."); + return false; + } + + resolvedConfigPath = combinedPath; + return true; +} + /// /// Start the monitors by delegating to the helper functions based on log source type /// @@ -378,37 +422,12 @@ int __cdecl wmain(int argc, WCHAR *argv[]) configFileName = argv[2]; std::wstring userConfigName = argv[2]; - // Reject paths with traversal sequences or absolute path indicators - if (userConfigName.find(L"..") != std::wstring::npos || - userConfigName.find(L'/') != std::wstring::npos || - userConfigName.find(L'\\') != std::wstring::npos || - userConfigName.find(L':') != std::wstring::npos) + if (!ResolveConfigPath(userConfigName, resolvedConfigPath)) { logWriter.TraceError(L"Invalid configuration file name."); return 0; } - // Anchor the config file to the executable's directory - WCHAR modulePath[MAX_PATH] = {}; - if (GetModuleFileNameW(nullptr, modulePath, _countof(modulePath)) == 0) - { - logWriter.TraceError( - Utility::FormatString(L"Failed to get module path. Error: %d", GetLastError()).c_str() - ); - return 0; - } - if (!PathRemoveFileSpecW(modulePath)) - { - logWriter.TraceError(L"Failed to resolve executable directory."); - return 0; - } - WCHAR combinedPath[MAX_PATH] = {}; - if (PathCombineW(combinedPath, modulePath, userConfigName.c_str()) == nullptr) - { - logWriter.TraceError(L"Failed to resolve configuration file path."); - return 0; - } - resolvedConfigPath = combinedPath; indexCommandArgument = 3; } }