Skip to content

Commit 2fc8de4

Browse files
committed
net/netstat: document the Windows netstat code a bit more
And defensively bound allocation. Updates tailscale/corp#8878 Change-Id: Iaa07479ea2ea28ee1ac3326ab025046d6d785b00 Signed-off-by: Brad Fitzpatrick <[email protected]>
1 parent 8c20da2 commit 2fc8de4

File tree

1 file changed

+29
-8
lines changed

1 file changed

+29
-8
lines changed

net/netstat/netstat_windows.go

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@ import (
2020
// OSMetadata includes any additional OS-specific information that may be
2121
// obtained during the retrieval of a given Entry.
2222
type OSMetadata interface {
23+
// GetModule returns the entry's module name.
24+
//
25+
// It returns ("", nil) if no entry is found. As of 2023-01-27, any returned
26+
// error is silently discarded by its sole caller in portlist_windows.go and
27+
// treated equivalently as returning ("", nil), but this may change in the
28+
// future. An error should only be returned in casees that are worthy of
29+
// being logged at least.
2330
GetModule() (string, error)
2431
}
2532

@@ -224,7 +231,13 @@ type moduleInfoConstraint interface {
224231
_MIB_TCPROW_OWNER_MODULE | _MIB_TCP6ROW_OWNER_MODULE
225232
}
226233

227-
// moduleInfo may return "", nil indicating a successful call but with empty data
234+
// moduleInfo implements OSMetadata.GetModule. It calls
235+
// getOwnerModuleFromTcpEntry or getOwnerModuleFromTcp6Entry.
236+
//
237+
// See
238+
// https://learn.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-getownermodulefromtcpentry
239+
//
240+
// It may return "", nil indicating a successful call but with empty data.
228241
func moduleInfo[entryType moduleInfoConstraint](entry *entryType, proc *windows.LazyProc) (string, error) {
229242
var buf []byte
230243
var desiredLen uint32
@@ -241,28 +254,36 @@ func moduleInfo[entryType moduleInfoConstraint](entry *entryType, proc *windows.
241254
if err == windows.ERROR_SUCCESS {
242255
break
243256
}
257+
if err == windows.ERROR_NOT_FOUND {
258+
return "", nil
259+
}
244260
if err != windows.ERROR_INSUFFICIENT_BUFFER {
245261
return "", err
246262
}
247-
263+
if desiredLen > 1<<20 {
264+
// Sanity check before allocating too much.
265+
return "", nil
266+
}
248267
buf = make([]byte, desiredLen)
249268
addr = unsafe.Pointer(&buf[0])
250269
}
251-
252-
basicInfo := (*_TCPIP_OWNER_MODULE_BASIC_INFO)(addr)
253-
// GetOwnerModuleFromTcp*Entry is apparently using nil as an empty result
254-
// under certain circumstances, so we check all the things.
255-
if basicInfo == nil || basicInfo.moduleName == nil {
270+
if addr == nil {
271+
// GetOwnerModuleFromTcp*Entry can apparently return ERROR_SUCCESS
272+
// (NO_ERROR) on the first call without the usual first
273+
// ERROR_INSUFFICIENT_BUFFER result. Windows said success, so interpret
274+
// that was sucessfully not having data.
256275
return "", nil
257276
}
258-
277+
basicInfo := (*_TCPIP_OWNER_MODULE_BASIC_INFO)(addr)
259278
return windows.UTF16PtrToString(basicInfo.moduleName), nil
260279
}
261280

281+
// GetModule implements OSMetadata.
262282
func (m *_MIB_TCPROW_OWNER_MODULE) GetModule() (string, error) {
263283
return moduleInfo(m, getOwnerModuleFromTcpEntry)
264284
}
265285

286+
// GetModule implements OSMetadata.
266287
func (m *_MIB_TCP6ROW_OWNER_MODULE) GetModule() (string, error) {
267288
return moduleInfo(m, getOwnerModuleFromTcp6Entry)
268289
}

0 commit comments

Comments
 (0)