fix(inputs.win_eventlog): Handle remote events more robustly. (#12375)

This commit is contained in:
Sven Rebhan 2023-01-10 11:06:58 +01:00 committed by GitHub
parent d476018705
commit 7b5b342432
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 82 additions and 26 deletions

View File

@ -2,7 +2,7 @@ ifneq (,$(filter $(OS),Windows_NT Windows))
EXEEXT=.exe
endif
next_version := $(shell cat build_version.txt)
next_version := $(file < build_version.txt)
tag := $(shell git describe --exact-match --tags 2>/dev/null)
branch := $(shell git rev-parse --abbrev-ref HEAD)

View File

@ -10,26 +10,28 @@ package win_eventlog
// More info on schema, if there will be need to add more:
// https://docs.microsoft.com/en-us/windows/win32/wes/eventschema-elements
type Event struct {
Source Provider `xml:"System>Provider"`
EventID int `xml:"System>EventID"`
Version int `xml:"System>Version"`
Level int `xml:"System>Level"`
Task int `xml:"System>Task"`
Opcode int `xml:"System>Opcode"`
Keywords string `xml:"System>Keywords"`
TimeCreated TimeCreated `xml:"System>TimeCreated"`
EventRecordID int `xml:"System>EventRecordID"`
Correlation Correlation `xml:"System>Correlation"`
Execution Execution `xml:"System>Execution"`
Channel string `xml:"System>Channel"`
Computer string `xml:"System>Computer"`
Security Security `xml:"System>Security"`
UserData UserData `xml:"UserData"`
EventData EventData `xml:"EventData"`
Message string
LevelText string
TaskText string
OpcodeText string
Source Provider `xml:"System>Provider"`
EventID int `xml:"System>EventID"`
Version int `xml:"System>Version"`
Level int `xml:"System>Level"`
Task int `xml:"System>Task"`
Opcode int `xml:"System>Opcode"`
Keywords string `xml:"System>Keywords"`
TimeCreated TimeCreated `xml:"System>TimeCreated"`
EventRecordID int `xml:"System>EventRecordID"`
Correlation Correlation `xml:"System>Correlation"`
Execution Execution `xml:"System>Execution"`
Channel string `xml:"System>Channel"`
Computer string `xml:"System>Computer"`
Security Security `xml:"System>Security"`
UserData UserData `xml:"UserData"`
EventData EventData `xml:"EventData"`
RenderingInfo *RenderingInfo `xml:"RenderingInfo"`
Message string
LevelText string
TaskText string
OpcodeText string
}
// UserData Application-provided XML data
@ -69,3 +71,15 @@ type Security struct {
type TimeCreated struct {
SystemTime string `xml:"SystemTime,attr"`
}
// RenderingInfo is provided for events forwarded by Windows Event Collector
// see https://learn.microsoft.com/en-us/windows/win32/api/winevt/nf-winevt-evtformatmessage#parameters
type RenderingInfo struct {
Message string `xml:"Message"`
Level string `xml:"Level"`
Task string `xml:"Task"`
Opcode string `xml:"Opcode"`
Channel string `xml:"Channel"`
Provider string `xml:"Provider"`
Keywords []string `xml:"Keywords>Keyword"`
}

View File

@ -48,8 +48,6 @@ type WinEventLog struct {
var bufferSize = 1 << 14
var description = "Input plugin to collect Windows Event Log messages"
func (*WinEventLog) SampleConfig() string {
return sampleConfig
}
@ -61,7 +59,7 @@ func (w *WinEventLog) Gather(acc telegraf.Accumulator) error {
if w.subscription == 0 {
w.subscription, err = w.evtSubscribe(w.EventlogName, w.Query)
if err != nil {
return fmt.Errorf("Windows Event Log subscription error: %v", err.Error())
return fmt.Errorf("subscription of Windows Event Log failed: %w", err)
}
}
w.Log.Debug("Subscription handle id:", w.subscription)
@ -74,7 +72,7 @@ loop:
case err == ERROR_NO_MORE_ITEMS:
break loop
case err != nil:
w.Log.Error("Error getting events:", err.Error())
w.Log.Errorf("Error getting events: %v", err)
return err
}
}
@ -305,7 +303,6 @@ func (w *WinEventLog) fetchEvents(subsHandle EvtHandle) ([]Event, error) {
if eventHandle != 0 {
event, err := w.renderEvent(eventHandle)
if err == nil {
// w.Log.Debugf("Got event: %v", event)
events = append(events, event)
}
}
@ -333,6 +330,7 @@ func (w *WinEventLog) renderEvent(eventHandle EvtHandle) (Event, error) {
if err != nil {
return event, err
}
err = xml.Unmarshal([]byte(eventXML), &event)
if err != nil {
// We can return event without most text values,
@ -341,6 +339,19 @@ func (w *WinEventLog) renderEvent(eventHandle EvtHandle) (Event, error) {
return event, nil
}
// Do resolve local messages the usual way, while using built-in information for events forwarded by WEC.
// This is a safety measure as the underlying Windows-internal EvtFormatMessage might segfault in cases
// where the publisher (i.e. the remote machine which forwared the event) is unavailable e.g. due to
// a reboot. See https://github.com/influxdata/telegraf/issues/12328 for the full story.
if event.RenderingInfo == nil {
return w.renderLocalMessage(event, eventHandle)
}
// We got 'RenderInfo' elements, so try to apply them in the following function
return w.renderRemoteMessage(event)
}
func (w *WinEventLog) renderLocalMessage(event Event, eventHandle EvtHandle) (Event, error) {
publisherHandle, err := openPublisherMetadata(0, event.Source.Name, w.Locale)
if err != nil {
return event, nil
@ -376,6 +387,32 @@ func (w *WinEventLog) renderEvent(eventHandle EvtHandle) (Event, error) {
return event, nil
}
func (w *WinEventLog) renderRemoteMessage(event Event) (Event, error) {
// Populating text values from RenderingInfo part of the XML
if len(event.RenderingInfo.Keywords) > 0 {
event.Keywords = strings.Join(event.RenderingInfo.Keywords, ",")
}
if event.RenderingInfo.Message != "" {
message := event.RenderingInfo.Message
if w.OnlyFirstLineOfMessage {
scanner := bufio.NewScanner(strings.NewReader(message))
scanner.Scan()
message = scanner.Text()
}
event.Message = message
}
if event.RenderingInfo.Level != "" {
event.LevelText = event.RenderingInfo.Level
}
if event.RenderingInfo.Task != "" {
event.TaskText = event.RenderingInfo.Task
}
if event.RenderingInfo.Opcode != "" {
event.OpcodeText = event.RenderingInfo.Opcode
}
return event, nil
}
func formatEventString(
messageFlag EvtFormatMessageFlag,
eventHandle EvtHandle,
@ -388,6 +425,11 @@ func formatEventString(
return "", err
}
// Handle empty elements
if bufferUsed < 1 {
return "", nil
}
bufferUsed *= 2
buffer := make([]byte, bufferUsed)
bufferUsed = 0