Skip to content

Commit 9d1c11e

Browse files
committed
windivert: lazy driver install + re-enable on DISABLED
Match upstream WinDivertOpen: try CreateFile first, install only when the device node is missing. Also recover from ERROR_SERVICE_DISABLED, which SCM reports while a prior DeleteService'd service hasn't fully unregistered yet — re-enable START_TYPE and retry StartService.
1 parent 2c4004c commit 9d1c11e

2 files changed

Lines changed: 54 additions & 22 deletions

File tree

common/windivert/driver_windows.go

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,17 @@ const (
2121
)
2222

2323
var (
24-
driverOnce sync.Once
25-
driverErr error
26-
driverDevName *uint16
24+
driverOnce sync.Once
25+
driverErr error
26+
// driverDevName is ASCII-safe and must be available before ensureDriver
27+
// so Open can try CreateFile first and only install on FILE_NOT_FOUND.
28+
driverDevName, _ = windows.UTF16PtrFromString(driverDeviceName)
2729
)
2830

2931
// Requires SeLoadDriverPrivilege (Administrator). Running the 386 build
3032
// under WOW64 on a 64-bit kernel is rejected — use the amd64 build.
3133
func ensureDriver() error {
3234
driverOnce.Do(func() {
33-
driverDevName, driverErr = windows.UTF16PtrFromString(driverDeviceName)
34-
if driverErr != nil {
35-
return
36-
}
3735
driverErr = installDriver()
3836
})
3937
return driverErr
@@ -103,6 +101,23 @@ func installDriver() error {
103101
defer windows.CloseServiceHandle(service)
104102

105103
err = windows.StartService(service, 0, nil)
104+
if err != nil && errors.Is(err, windows.ERROR_SERVICE_DISABLED) {
105+
// A prior process called DeleteService on a still-running kernel
106+
// driver: SCM marks the record for deletion and flips START_TYPE
107+
// to DISABLED until the last handle closes. Re-enable so we can
108+
// start it instead of waiting for a reboot.
109+
err = windows.ChangeServiceConfig(
110+
service,
111+
windows.SERVICE_NO_CHANGE,
112+
windows.SERVICE_DEMAND_START,
113+
windows.SERVICE_NO_CHANGE,
114+
nil, nil, nil, nil, nil, nil, nil,
115+
)
116+
if err != nil {
117+
return E.Cause(err, "windivert: re-enable disabled service")
118+
}
119+
err = windows.StartService(service, 0, nil)
120+
}
106121
if err == nil {
107122
// Mark for deletion so the driver unregisters when the last handle
108123
// closes or on next reboot. Matches the upstream DLL's behavior:

common/windivert/handle_windows.go

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -48,23 +48,29 @@ func Open(filter *Filter, layer Layer, priority int16, flags Flag) (*Handle, err
4848
if err != nil {
4949
return nil, err
5050
}
51-
err = ensureDriver()
51+
device, err := openDevice()
5252
if err != nil {
53-
return nil, err
54-
}
55-
device, err := windows.CreateFile(
56-
driverDevName,
57-
windows.GENERIC_READ|windows.GENERIC_WRITE,
58-
0, nil,
59-
windows.OPEN_EXISTING,
60-
windows.FILE_ATTRIBUTE_NORMAL|windows.FILE_FLAG_OVERLAPPED,
61-
0,
62-
)
63-
if err != nil {
64-
if errors.Is(err, windows.ERROR_ACCESS_DENIED) {
65-
return nil, E.Cause(err, "windivert: open device (administrator required)")
53+
if !errors.Is(err, windows.ERROR_FILE_NOT_FOUND) &&
54+
!errors.Is(err, windows.ERROR_PATH_NOT_FOUND) {
55+
if errors.Is(err, windows.ERROR_ACCESS_DENIED) {
56+
return nil, E.Cause(err, "windivert: open device (administrator required)")
57+
}
58+
return nil, E.Cause(err, "windivert: open device")
59+
}
60+
// Device node missing: kernel driver not loaded. Install + retry.
61+
// Matches WinDivertOpen's lazy-install path; avoids racing StartService
62+
// against a still-loaded driver whose SCM record is marked for deletion.
63+
err = ensureDriver()
64+
if err != nil {
65+
return nil, err
66+
}
67+
device, err = openDevice()
68+
if err != nil {
69+
if errors.Is(err, windows.ERROR_ACCESS_DENIED) {
70+
return nil, E.Cause(err, "windivert: open device (administrator required)")
71+
}
72+
return nil, E.Cause(err, "windivert: open device")
6673
}
67-
return nil, E.Cause(err, "windivert: open device")
6874
}
6975
event, err := windows.CreateEvent(nil, 1, 0, nil) // manual reset, unsignaled
7076
if err != nil {
@@ -86,6 +92,17 @@ func Open(filter *Filter, layer Layer, priority int16, flags Flag) (*Handle, err
8692
return h, nil
8793
}
8894

95+
func openDevice() (windows.Handle, error) {
96+
return windows.CreateFile(
97+
driverDevName,
98+
windows.GENERIC_READ|windows.GENERIC_WRITE,
99+
0, nil,
100+
windows.OPEN_EXISTING,
101+
windows.FILE_ATTRIBUTE_NORMAL|windows.FILE_FLAG_OVERLAPPED,
102+
0,
103+
)
104+
}
105+
89106
func validateOpenArgs(layer Layer, priority int16, flags Flag) error {
90107
if layer != LayerNetwork {
91108
return E.New("windivert: invalid layer ", uint32(layer))

0 commit comments

Comments
 (0)