Skip to content

Commit

Permalink
move windows string code in ports_windows.go to winstrings.go, move s…
Browse files Browse the repository at this point in the history
…hared code in process.go to winstrings.go, remove datadog-agent and agent.exe from agentNames
  • Loading branch information
mwdd146980 committed Dec 31, 2024
1 parent 92101f3 commit 9f51b20
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 55 deletions.
11 changes: 2 additions & 9 deletions pkg/diagnose/ports/ports.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ package ports

import (
"fmt"
"runtime"
"strings"

pkgconfigsetup "github.com/DataDog/datadog-agent/pkg/config/setup"
Expand All @@ -17,9 +16,8 @@ import (
)

var agentNames = map[string]struct{}{
"datadog-agent": {}, "agent": {}, "trace-agent": {},
"process-agent": {}, "system-probe": {}, "security-agent": {},
"dogstatsd": {}, "agent.exe": {},
"agent": {}, "trace-agent": {}, "process-agent": {},
"system-probe": {}, "security-agent": {}, "dogstatsd": {},
}

// DiagnosePortSuite displays information about the ports used in the agent configuration
Expand All @@ -40,11 +38,6 @@ func DiagnosePortSuite() []diagnosis.Diagnosis {

var diagnoses []diagnosis.Diagnosis
for _, key := range pkgconfigsetup.Datadog().AllKeysLowercased() {
// on windows, we skip the ports used by apm agent and process agent because the core agent does not have permissions to retrieve proc name
if runtime.GOOS == "windows" && (strings.HasPrefix(key, "apm_config") || strings.HasPrefix(key, "process_config")) {
continue
}

splitKey := strings.Split(key, ".")
keyName := splitKey[len(splitKey)-1]
if keyName != "port" && !strings.HasPrefix(keyName, "port_") && !strings.HasSuffix(keyName, "_port") {
Expand Down
39 changes: 9 additions & 30 deletions pkg/diagnose/ports/ports_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ package ports

import (
"fmt"
"path/filepath"
"strings"
"syscall"
"unicode/utf16"
"unsafe"

"github.com/DataDog/datadog-agent/pkg/util/winutil"
)

// NTSTATUS is the return type used by many native Windows functions.
Expand All @@ -25,17 +27,10 @@ const (
SystemProcessIDInformationClass = 88 // SystemProcessIDInformationClass gives access to process names without elevated privileges on Windows.
)

// unicodeString mirrors the Windows unicodeString struct.
type unicodeString struct {
Length uint16
MaximumLength uint16
Buffer *uint16
}

// SystemProcessIDInformation mirrors the SystemProcessIdInformation struct used by NtQuerySystemInformation.
type SystemProcessIDInformation struct {
ProcessID uintptr
ImageName unicodeString
ImageName winutil.UnicodeString
}

// Loading NtQuerySystemInformation
Expand Down Expand Up @@ -67,19 +62,6 @@ func NtQuerySystemInformation(
return NTSTATUS(r0)
}

// unicodeStringToString is a helper function to convert a unicodeString to a Go string
func unicodeStringToString(u unicodeString) string {
// Length is in bytes; divide by 2 for number of uint16 chars
length := int(u.Length / 2)
if length == 0 || u.Buffer == nil {
return ""
}
// Convert from a pointer to a slice of uint16
buf := (*[1 << 20]uint16)(unsafe.Pointer(u.Buffer))[:length:length]
// Convert UTF-16 to Go string
return string(utf16.Decode(buf))
}

// RetrieveProcessName fetches the process name on Windows using NtQuerySystemInformation
// with SystemProcessIDInformationClass, which does not require elevated privileges.
func RetrieveProcessName(pid int, _ string) (string, error) {
Expand All @@ -91,8 +73,8 @@ func RetrieveProcessName(pid int, _ string) (string, error) {
var info SystemProcessIDInformation
info.ProcessID = uintptr(pid)
info.ImageName.Length = 0
info.ImageName.MaximumLength = 256 * 2
info.ImageName.Buffer = &buf[0]
info.ImageName.MaxLength = 256 * 2
info.ImageName.Buffer = uintptr(unsafe.Pointer(&buf[0]))

// Call NtQuerySystemInformation
var returnLength uint32
Expand All @@ -108,14 +90,11 @@ func RetrieveProcessName(pid int, _ string) (string, error) {
return "", fmt.Errorf("NtQuerySystemInformation failed with NTSTATUS 0x%X", status)
}

// Convert unicodeString to Go string
imageName := unicodeStringToString(info.ImageName)
// Convert imageName, which is a UnicodeString, to Go string
imageName := winutil.UnicodeStringToString(info.ImageName)

// Extract the base name of the process, remove .exe extension if present
idx := strings.LastIndex(imageName, `\`)
if idx != -1 {
imageName = imageName[idx+1:]
}
imageName = filepath.Base(imageName)
imageName = strings.TrimSuffix(imageName, ".exe")

return imageName, nil
Expand Down
25 changes: 9 additions & 16 deletions pkg/util/winutil/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,18 +216,11 @@ func readUnicodeString32(h windows.Handle, u unicodeString32) (string, error) {
return ConvertWindowsString(buf), nil
}

// this definition taken from Winternl.h
type unicodeString struct {
length uint16
maxLength uint16
buffer uintptr
}

type _rtlUserProcessParameters struct {
Reserved1 [16]byte
Reserved2 [10]uintptr
imagePathName unicodeString
commandLine unicodeString
imagePathName UnicodeString
commandLine UnicodeString
}
type _peb struct {
Reserved1 [2]byte
Expand Down Expand Up @@ -299,19 +292,19 @@ func getCommandParamsForProcess64(h windows.Handle, includeImagePath bool) (*Pro
return procCommandParams, nil
}

func readUnicodeString(h windows.Handle, u unicodeString) (string, error) {
if u.length > u.maxLength {
return "", fmt.Errorf("Invalid unicodeString, maxLength %v < length %v", u.maxLength, u.length)
func readUnicodeString(h windows.Handle, u UnicodeString) (string, error) {
if u.Length > u.MaxLength {
return "", fmt.Errorf("Invalid UnicodeString, maxLength %v < length %v", u.MaxLength, u.Length)
}
// length does not include null terminator, if it exists
// allocate two extra bytes so we can add it ourself
buf := make([]uint8, u.length+2)
read, err := ReadProcessMemory(h, uintptr(u.buffer), uintptr(unsafe.Pointer(&buf[0])), uint32(u.length))
buf := make([]uint8, u.Length+2)
read, err := ReadProcessMemory(h, uintptr(u.Buffer), uintptr(unsafe.Pointer(&buf[0])), uint32(u.Length))
if err != nil {
return "", err
}
if read != uint64(u.length) {
return "", fmt.Errorf("Wrong amount of bytes read (unicodeString) %v != %v", read, u.length)
if read != uint64(u.Length) {
return "", fmt.Errorf("Wrong amount of bytes read (UnicodeString) %v != %v", read, u.Length)
}
// null terminate string
buf = append(buf, 0, 0)
Expand Down
21 changes: 21 additions & 0 deletions pkg/util/winutil/winstrings.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,24 @@ func UTF16PtrOrNilFromString(s string) (*uint16, error) {
}
return windows.UTF16PtrFromString(s)
}

// this definition taken from Winternl.h
// Used in process.go and pkg/diagnose/ports/ports_windows.go
type UnicodeString struct {
Length uint16
MaxLength uint16
Buffer uintptr
}

// UnicodeStringToString is a helper function to convert a UnicodeString to a Go string
func UnicodeStringToString(u UnicodeString) string {
// Length is in bytes; divide by 2 for number of uint16 chars
length := int(u.Length / 2)
if length == 0 || u.Buffer == 0 {
return ""
}
// Convert from a pointer to a slice of uint16
buf := (*[1 << 20]uint16)(unsafe.Pointer(u.Buffer))[:length:length]
// Convert UTF-16 to Go string
return ConvertWindowsString16(buf)
}

0 comments on commit 9f51b20

Please sign in to comment.