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 @@ "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") +}