Skip to content

Commit

Permalink
winlogbeat/sys/wineventlog: don't use claimed buffer use value (#35437)
Browse files Browse the repository at this point in the history
EvtFormatMessage appears to sometimes claim that more buffer was used
during a rendering call than was or exists, so do not use this value
except in the query to get the needed buffer size.
  • Loading branch information
efd6 authored and chrisberkhout committed Jun 1, 2023
1 parent e27b755 commit 1c3b7a5
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 24 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.next.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ automatic splitting at root level, if root level element is an array. {pull}3415
- Clarify query term limits warning and remove link to missing Microsoft doc page. {pull}34715[34715]
- Improve documentation for event_logs.name configuration. {pull}34931[34931]
- Move repeated channel not found errors to debug level. {issue}35314[35314] {pull}35317[35317]
- Fix panic due to misrepresented buffer use. {pull}35437[35437]

*Functionbeat*

Expand Down
42 changes: 18 additions & 24 deletions winlogbeat/sys/wineventlog/wineventlog_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ func RenderEvent(

// Only a single string is returned when rendering XML.
err = FormatEventString(EvtFormatMessageXml,
eventHandle, providerName, EvtHandle(publisherHandle), lang, renderBuf, out)
eventHandle, providerName, EvtHandle(publisherHandle), lang, out)
// Recover by rendering the XML without the RenderingInfo (message string).
if err != nil {
// Do not try to recover from InsufficientBufferErrors because these
Expand Down Expand Up @@ -388,20 +388,17 @@ func Close(h EvtHandle) error {
// publisherHandle is a handle to the publisher's metadata as provided by
// EvtOpenPublisherMetadata.
// lang is the language ID.
// buffer is optional and if not provided it will be allocated. If the provided
// buffer is not large enough then an InsufficientBufferError will be returned.
func FormatEventString(
messageFlag EvtFormatMessageFlag,
eventHandle EvtHandle,
publisher string,
publisherHandle EvtHandle,
lang uint32,
buffer []byte,
out io.Writer,
) error {
// Open a publisher handle if one was not provided.
ph := publisherHandle
if ph == 0 {
if ph == NilHandle {
var err error
ph, err = OpenPublisherMetadata(0, publisher, lang)
if err != nil {
Expand All @@ -410,33 +407,30 @@ func FormatEventString(
defer _EvtClose(ph) //nolint:errcheck // This is just a resource release.
}

// Create a buffer if one was not provided.
// Determine the buffer size needed (given in WCHARs).
var bufferUsed uint32
if buffer == nil {
err := _EvtFormatMessage(ph, eventHandle, 0, 0, 0, messageFlag,
0, nil, &bufferUsed)
if err != nil && err != ERROR_INSUFFICIENT_BUFFER { //nolint:errorlint // This is an errno or nil.
return err
}

bufferUsed *= 2
buffer = make([]byte, bufferUsed)
bufferUsed = 0
err := _EvtFormatMessage(ph, eventHandle, 0, 0, 0, messageFlag, 0, nil, &bufferUsed)
if err != windows.ERROR_INSUFFICIENT_BUFFER { //nolint:errorlint // This is an errno.
return fmt.Errorf("failed in EvtFormatMessage: %w", err)
}

err := _EvtFormatMessage(ph, eventHandle, 0, 0, 0, messageFlag,
uint32(len(buffer)/2), &buffer[0], &bufferUsed)
bufferUsed *= 2
if err == ERROR_INSUFFICIENT_BUFFER { //nolint:errorlint // This is an errno or nil.
return sys.InsufficientBufferError{Cause: err, RequiredSize: int(bufferUsed)}
}
// Get a buffer from the pool and adjust its length.
bb := sys.NewPooledByteBuffer()
defer bb.Free()
// The documentation for EvtFormatMessage specifies that the buffer is
// requested "in characters", and the buffer itself is LPWSTR, meaning the
// characters are WCHAR so double the value.
// https://docs.microsoft.com/en-us/windows/win32/api/winevt/nf-winevt-evtformatmessage
bb.Reserve(int(bufferUsed * 2))

err = _EvtFormatMessage(ph, eventHandle, 0, 0, 0, messageFlag, bufferUsed, bb.PtrAt(0), &bufferUsed)
if err != nil {
return err
return fmt.Errorf("failed in EvtFormatMessage: %w", err)
}

// This assumes there is only a single string value to read. This will
// not work to read keys (when messageFlag == EvtFormatMessageKeyword).
return common.UTF16ToUTF8Bytes(buffer[:bufferUsed], out)
return common.UTF16ToUTF8Bytes(bb.Bytes(), out)
}

// Publishers returns a sort list of event publishers on the local computer.
Expand Down

0 comments on commit 1c3b7a5

Please sign in to comment.