From 06c1f463545498d8f4b378d4dcf3171794c28537 Mon Sep 17 00:00:00 2001 From: Adrian Serrano Date: Tue, 9 Jul 2019 18:49:53 +0200 Subject: [PATCH] Windows: Fix crash due to unterminated string (#58) (1.0.2) This fixes a crash when fetching a process arguments. The command-line string read from the target process memory sometimes is not terminated. It can cause bogus characters appended to the command-line or a crash. --- CHANGELOG.md | 9 +++++++-- providers/windows/process_windows.go | 26 +++++++++++++++++++++++--- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 562a3b5d..f1727d20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,10 +16,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed -- Fixed a leak when calling the CommandLineToArgv function. [#51](https://github.com/elastic/go-sysinfo/pull/51) - ### Security +## [1.0.2] - 2019-07-09 + +### Fixed + +- Fixed a leak when calling the CommandLineToArgv function. [#51](https://github.com/elastic/go-sysinfo/pull/51) +- Fixed a crash when calling the CommandLineToArgv function. [#58](https://github.com/elastic/go-sysinfo/pull/58) + ## [1.0.1] - 2019-05-08 ### Fixed diff --git a/providers/windows/process_windows.go b/providers/windows/process_windows.go index 351351de..5dfd0905 100644 --- a/providers/windows/process_windows.go +++ b/providers/windows/process_windows.go @@ -207,8 +207,14 @@ func getUserProcessParams(handle syscall.Handle, pbi windows.ProcessBasicInforma // read an UTF-16 string from another process memory. Result is an []byte // with the UTF-16 data. func readProcessUnicodeString(handle syscall.Handle, s *windows.UnicodeString) ([]byte, error) { - buf := make([]byte, s.Size) - nRead, err := windows.ReadProcessMemory(handle, s.Buffer, buf) + // Allocate an extra UTF-16 null character at the end in case the read string + // is not terminated. + extra := 2 + if s.Size&1 != 0 { + extra = 3 // If size is odd, need 3 nulls to terminate. + } + buf := make([]byte, int(s.Size)+extra) + nRead, err := windows.ReadProcessMemory(handle, s.Buffer, buf[:s.Size]) if err != nil { return nil, err } @@ -221,9 +227,23 @@ func readProcessUnicodeString(handle syscall.Handle, s *windows.UnicodeString) ( // Use Windows' CommandLineToArgv API to split an UTF-16 command line string // into a list of parameters. func splitCommandline(utf16 []byte) ([]string, error) { - if len(utf16) == 0 { + n := len(utf16) + // Discard odd byte + if n&1 != 0 { + n-- + utf16 = utf16[:n] + } + if n == 0 { return nil, nil } + terminated := false + for i := 0; i < n && !terminated; i += 2 { + terminated = utf16[i] == 0 && utf16[i+1] == 0 + } + if !terminated { + // Append a null uint16 at the end if terminator is missing + utf16 = append(utf16, 0, 0) + } var numArgs int32 argsWide, err := syscall.CommandLineToArgv((*uint16)(unsafe.Pointer(&utf16[0])), &numArgs) if err != nil {