cmd/tailscaled: add a special command to tailscaled's Windows service for removing WinTun
WinTun is installed lazily by tailscaled while it is running as LocalSystem. Based upon what we're seeing in bug reports and support requests, removing WinTun as a lesser user may fail under certain Windows versions, even when that user is an Administrator. By adding a user-defined command code to tailscaled, we can ask the service to do the removal on our behalf while it is still running as LocalSystem. * The uninstall code is basically the same as it is in corp; * The command code will be sent as a service control request and is protected by the SERVICE_USER_DEFINED_CONTROL access right, which requires Administrator. I'll be adding follow-up patches in corp to engage this functionality. Updates https://github.com/tailscale/tailscale/issues/6433 Signed-off-by: Aaron Klotz <aaron@tailscale.com>
This commit is contained in:
parent
367228ef82
commit
98f21354c6
|
@ -126,7 +126,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
|||
github.com/x448/float16 from github.com/fxamacker/cbor/v2
|
||||
💣 go4.org/mem from tailscale.com/control/controlbase+
|
||||
go4.org/netipx from tailscale.com/ipn/ipnlocal+
|
||||
W 💣 golang.zx2c4.com/wintun from golang.zx2c4.com/wireguard/tun
|
||||
W 💣 golang.zx2c4.com/wintun from golang.zx2c4.com/wireguard/tun+
|
||||
💣 golang.zx2c4.com/wireguard/conn from golang.zx2c4.com/wireguard/device+
|
||||
W 💣 golang.zx2c4.com/wireguard/conn/winrio from golang.zx2c4.com/wireguard/conn
|
||||
💣 golang.zx2c4.com/wireguard/device from tailscale.com/net/tstun+
|
||||
|
|
|
@ -38,6 +38,7 @@ import (
|
|||
"golang.org/x/sys/windows"
|
||||
"golang.org/x/sys/windows/svc"
|
||||
"golang.org/x/sys/windows/svc/eventlog"
|
||||
"golang.zx2c4.com/wintun"
|
||||
"golang.zx2c4.com/wireguard/tun"
|
||||
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
|
||||
"tailscale.com/envknob"
|
||||
|
@ -64,6 +65,12 @@ func init() {
|
|||
|
||||
const serviceName = "Tailscale"
|
||||
|
||||
// Application-defined command codes between 128 and 255
|
||||
// See https://web.archive.org/web/20221007222822/https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-controlservice
|
||||
const (
|
||||
cmdUninstallWinTun = svc.Cmd(128 + iota)
|
||||
)
|
||||
|
||||
func init() {
|
||||
tstunNew = tstunNewWithWindowsRetries
|
||||
}
|
||||
|
@ -184,6 +191,26 @@ func (service *ipnService) Execute(args []string, r <-chan svc.ChangeRequest, ch
|
|||
syslogf("Service session change notification")
|
||||
handleSessionChange(cmd)
|
||||
changes <- cmd.CurrentStatus
|
||||
case cmdUninstallWinTun:
|
||||
syslogf("Stopping tailscaled child process and uninstalling WinTun")
|
||||
// At this point, doneCh is the channel which will be closed when the
|
||||
// tailscaled subprocess exits. We save that to childDoneCh.
|
||||
childDoneCh := doneCh
|
||||
// We reset doneCh to a new channel that will keep the event loop
|
||||
// running until the uninstallation is done.
|
||||
doneCh = make(chan struct{})
|
||||
// Trigger subprocess shutdown.
|
||||
cancel()
|
||||
go func() {
|
||||
// When this goroutine completes, tell the service to break out of its
|
||||
// event loop.
|
||||
defer close(doneCh)
|
||||
// Wait for the subprocess to shutdown.
|
||||
<-childDoneCh
|
||||
// Now uninstall WinTun.
|
||||
uninstallWinTun(log.Printf)
|
||||
}()
|
||||
changes <- svc.Status{State: svc.StopPending}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -221,6 +248,8 @@ func cmdName(c svc.Cmd) string {
|
|||
return "SessionChange"
|
||||
case svc.PreShutdown:
|
||||
return "PreShutdown"
|
||||
case cmdUninstallWinTun:
|
||||
return "(Application Defined) Uninstall WinTun"
|
||||
}
|
||||
return fmt.Sprintf("Unknown-Service-Cmd-%d", c)
|
||||
}
|
||||
|
@ -447,3 +476,15 @@ func babysitProc(ctx context.Context, args []string, logf logger.Logf) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func uninstallWinTun(logf logger.Logf) {
|
||||
dll := windows.NewLazyDLL("wintun.dll")
|
||||
if err := dll.Load(); err != nil {
|
||||
logf("Cannot load wintun.dll for uninstall: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
logf("Removing wintun driver...")
|
||||
err := wintun.Uninstall()
|
||||
logf("Uninstall: %v", err)
|
||||
}
|
||||
|
|
2
go.mod
2
go.mod
|
@ -72,6 +72,7 @@ require (
|
|||
golang.org/x/term v0.1.0
|
||||
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11
|
||||
golang.org/x/tools v0.2.0
|
||||
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224
|
||||
golang.zx2c4.com/wireguard v0.0.0-20220920152132-bb719d3a6e2c
|
||||
golang.zx2c4.com/wireguard/windows v0.5.3
|
||||
gvisor.dev/gvisor v0.0.0-20220817001344-846276b3dbc5
|
||||
|
@ -276,7 +277,6 @@ require (
|
|||
golang.org/x/image v0.0.0-20201208152932-35266b937fa6 // indirect
|
||||
golang.org/x/mod v0.6.0 // indirect
|
||||
golang.org/x/text v0.4.0 // indirect
|
||||
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect
|
||||
google.golang.org/protobuf v1.28.0 // indirect
|
||||
gopkg.in/ini.v1 v1.66.2 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
_ "golang.org/x/sys/windows/svc"
|
||||
_ "golang.org/x/sys/windows/svc/eventlog"
|
||||
_ "golang.org/x/sys/windows/svc/mgr"
|
||||
_ "golang.zx2c4.com/wintun"
|
||||
_ "golang.zx2c4.com/wireguard/tun"
|
||||
_ "golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
|
||||
_ "tailscale.com/cmd/tailscaled/childproc"
|
||||
|
|
Loading…
Reference in New Issue