From 47019ce1f174ec33b5d3a801f0bee0e456e268de Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Thu, 2 Nov 2023 09:31:27 -0600 Subject: [PATCH] cmd/tailscaled: pre-load wintun.dll using a fully-qualified path In corp PR #14970 I updated the installer to set a security mitigation that always forces system32 to the front of the Windows dynamic linker's search path. Unfortunately there are other products out there that, partying like it's 1995, drop their own, older version of wintun.dll into system32. Since we look there first, we end up loading that old version. We can fix this by preloading wintun using a fully-qualified path. When wintun-go then loads wintun, the dynamic linker will hand it the module that was previously loaded by us. Fixes #10023, #10025, #10052 Signed-off-by: Aaron Klotz --- cmd/tailscaled/tailscaled_windows.go | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/cmd/tailscaled/tailscaled_windows.go b/cmd/tailscaled/tailscaled_windows.go index e3e08f28a..e8f901a66 100644 --- a/cmd/tailscaled/tailscaled_windows.go +++ b/cmd/tailscaled/tailscaled_windows.go @@ -30,6 +30,7 @@ import ( "os" "os/exec" "os/signal" + "path/filepath" "sync" "syscall" "time" @@ -299,6 +300,14 @@ func beWindowsSubprocess() bool { } }() + // Pre-load wintun.dll using a fully-qualified path so that wintun-go + // loads our copy and not some (possibly outdated) copy dropped in system32. + // (OSS Issue #10023) + fqWintunPath := fullyQualifiedWintunPath(log.Printf) + if _, err := windows.LoadDLL(fqWintunPath); err != nil { + log.Printf("Error pre-loading \"%s\": %v", fqWintunPath, err) + } + sys := new(tsd.System) netMon, err := netmon.New(log.Printf) if err != nil { @@ -507,7 +516,7 @@ func babysitProc(ctx context.Context, args []string, logf logger.Logf) { } func uninstallWinTun(logf logger.Logf) { - dll := windows.NewLazyDLL("wintun.dll") + dll := windows.NewLazyDLL(fullyQualifiedWintunPath(logf)) if err := dll.Load(); err != nil { logf("Cannot load wintun.dll for uninstall: %v", err) return @@ -517,3 +526,16 @@ func uninstallWinTun(logf logger.Logf) { err := wintun.Uninstall() logf("Uninstall: %v", err) } + +func fullyQualifiedWintunPath(logf logger.Logf) string { + var dir string + var buf [windows.MAX_PATH]uint16 + length := uint32(len(buf)) + if err := windows.QueryFullProcessImageName(windows.CurrentProcess(), 0, &buf[0], &length); err != nil { + logf("QueryFullProcessImageName failed: %v", err) + } else { + dir = filepath.Dir(windows.UTF16ToString(buf[:length])) + } + + return filepath.Join(dir, "wintun.dll") +}