summaryrefslogtreecommitdiffhomepage
path: root/windows
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2025-09-01 21:53:37 +0200
committerDavid Lönnhager <david.l@mullvad.net>2025-09-08 16:13:40 +0200
commitf49ad36f034dfd8eb719a25c9d55d80d69f63bfa (patch)
tree9c622ffdd3ae8b7611ad0222cca4a97571d4dd03 /windows
parent5c5f1a18c5ab656fe9b4ec253f71e4b6d3587da3 (diff)
downloadmullvadvpn-f49ad36f034dfd8eb719a25c9d55d80d69f63bfa.tar.xz
mullvadvpn-f49ad36f034dfd8eb719a25c9d55d80d69f63bfa.zip
Log active WFP sessions on transaction lock timeout
Diffstat (limited to 'windows')
-rw-r--r--windows/winfw/src/winfw/winfw.cpp91
1 files changed, 90 insertions, 1 deletions
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;
}