diff options
| author | David Lönnhager <david.l@mullvad.net> | 2025-09-08 16:14:45 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2025-09-08 16:14:45 +0200 |
| commit | e45a74afacca13bcf0a5e46bd26ea56eb0651477 (patch) | |
| tree | 134057e74a092906b1b0d02de197009c86422ee2 | |
| parent | 5c5f1a18c5ab656fe9b4ec253f71e4b6d3587da3 (diff) | |
| parent | 50882c23a06122c033b1496c12a6819875f416a1 (diff) | |
| download | mullvadvpn-e45a74afacca13bcf0a5e46bd26ea56eb0651477.tar.xz mullvadvpn-e45a74afacca13bcf0a5e46bd26ea56eb0651477.zip | |
Merge branch 'winfw-log-wfp-sessions'
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | windows/winfw/src/winfw/winfw.cpp | 91 |
2 files changed, 91 insertions, 1 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 45086043cc..b76dfc2d1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ Line wrap the file at 100 chars. Th #### Windows - Add additional logging for tunnel devices and split tunneling to problem reports. +- Log WFP sessions when transaction lock timeout occurs. ### Changed #### Windows diff --git a/windows/winfw/src/winfw/winfw.cpp b/windows/winfw/src/winfw/winfw.cpp index d962965a19..064532235c 100644 --- a/windows/winfw/src/winfw/winfw.cpp +++ b/windows/winfw/src/winfw/winfw.cpp @@ -6,10 +6,15 @@ #include "rules/persistent/blockall.h" #include "rules/baseline/blockall.h" #include "libwfp/ipnetwork.h" +#include "libwfp/filterengine.h" +#include "libwfp/objectenumerator.h" #include <windows.h> #include <libcommon/error.h> #include <libcommon/string.h> #include <optional> +#include <psapi.h> +#include <sstream> +#include <set> namespace { @@ -21,6 +26,88 @@ void *g_logSinkContext = nullptr; FwContext *g_fwContext = nullptr; +// Log the filename of active WFP sessions as comma-separated values. Note that the path is not logged. +// If the process can not be opened or its filename can not be obtained, the process ID is logged instead. +void +LogActiveWfpSessions() +{ + if (nullptr == g_logSink) + { + return; + } + + try + { + auto engine = wfp::FilterEngine::DynamicSession(); + std::set<DWORD> sessionPids; + + wfp::ObjectEnumerator::Sessions(*engine, [&sessionPids](const FWPM_SESSION0 &session) -> bool + { + if (session.processId != 0) + { + sessionPids.insert(session.processId); + } + return true; + }); + + if (sessionPids.empty()) + { + g_logSink(MULLVAD_LOG_LEVEL_DEBUG, "No active WFP sessions found", g_logSinkContext); + return; + } + + std::stringstream ss; + ss << "Active WFP sessions from processes: "; + bool first = true; + + for (DWORD pid : sessionPids) + { + if (!first) + { + ss << ", "; + } + first = false; + + HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid); + if (nullptr == hProcess) + { + // Log pid only if we cannot open the process + ss << "PID:" << pid; + continue; + } + + wchar_t processPath[MAX_PATH]; + DWORD pathSize = MAX_PATH; + if (QueryFullProcessImageNameW(hProcess, 0, processPath, &pathSize)) + { + // Extract just the filename + wchar_t *filename = wcsrchr(processPath, L'\\'); + if (nullptr != filename) + { + filename++; + } + else + { + filename = processPath; + } + ss << common::string::ToAnsi(filename); + } + else + { + // Log pid only if we cannot obtain the path + ss << "PID:" << pid; + } + CloseHandle(hProcess); + } + + g_logSink(MULLVAD_LOG_LEVEL_DEBUG, ss.str().c_str(), g_logSinkContext); + } + catch (...) + { + g_logSink(MULLVAD_LOG_LEVEL_ERROR, "Failed to log WFP sessions", g_logSinkContext); + } +} + WINFW_POLICY_STATUS HandlePolicyException(const common::error::WindowsException &err) { @@ -31,7 +118,9 @@ HandlePolicyException(const common::error::WindowsException &err) if (FWP_E_TIMEOUT == err.errorCode()) { - // TODO: Detect software that may cause this + // Log processes potentially holding the transaction lock + LogActiveWfpSessions(); + return WINFW_POLICY_STATUS_LOCK_TIMEOUT; } |
