Skip to content

Commit 45e9dba

Browse files
committed
perf(rule-engine, eventsource): Event existence checks against bitmask
1 parent 71aa832 commit 45e9dba

File tree

10 files changed

+121
-25
lines changed

10 files changed

+121
-25
lines changed

internal/etw/consumer.go

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,22 +74,21 @@ func (c *Consumer) ProcessEvent(ev *etw.EventRecord) error {
7474
if c.isClosing {
7575
return nil
7676
}
77-
if event.IsCurrentProcDropped(ev.Header.ProcessID) {
77+
78+
if !c.config.EventSource.EventExists(ev.ID()) {
79+
eventsUnknown.Add(1)
7880
return nil
7981
}
80-
if c.config.EventSource.ExcludeEvent(ev.Header.ProviderID, ev.HookID()) {
81-
eventsExcluded.Add(1)
82+
if event.IsCurrentProcDropped(ev.Header.ProcessID) {
8283
return nil
8384
}
84-
85-
etype := event.NewFromEventRecord(ev)
86-
if !etype.Exists() {
87-
eventsUnknown.Add(1)
85+
if c.config.EventSource.ExcludeEvent(ev.ID()) {
86+
eventsExcluded.Add(1)
8887
return nil
8988
}
9089

9190
eventsProcessed.Add(1)
92-
evt := event.New(c.sequencer.Get(), etype, ev)
91+
evt := event.New(c.sequencer.Get(), ev)
9392

9493
// Dispatch each event to the processor chain.
9594
// Processors may further augment the event with

internal/etw/source_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ func TestEventSourceStartTraces(t *testing.T) {
123123

124124
for _, tt := range tests {
125125
t.Run(tt.name, func(t *testing.T) {
126+
tt.cfg.EventSource.Init()
126127
evs := NewEventSource(psnap, hsnap, tt.cfg, nil)
127128
require.NoError(t, evs.Open(tt.cfg))
128129
defer evs.Close()
@@ -193,6 +194,7 @@ func TestEventSourceEnableFlagsDynamically(t *testing.T) {
193194
Filters: &config.Filters{},
194195
}
195196

197+
cfg.EventSource.Init()
196198
evs := NewEventSource(psnap, hsnap, cfg, r)
197199
require.NoError(t, evs.Open(cfg))
198200
defer evs.Close()
@@ -277,6 +279,7 @@ func TestEventSourceEnableFlagsDynamicallyWithYaraEnabled(t *testing.T) {
277279
},
278280
}
279281

282+
cfg.EventSource.Init()
280283
evs := NewEventSource(psnap, hsnap, cfg, r)
281284
require.NoError(t, evs.Open(cfg))
282285
defer evs.Close()
@@ -328,6 +331,7 @@ func TestEventSourceRundownEvents(t *testing.T) {
328331
Filters: &config.Filters{},
329332
}
330333

334+
cfg.EventSource.Init()
331335
evs := NewEventSource(psnap, hsnap, cfg, nil)
332336

333337
l := &MockListener{}
@@ -741,6 +745,7 @@ func TestEventSourceAllEvents(t *testing.T) {
741745
StackEnrichment: false,
742746
}
743747

748+
evsConfig.Init()
744749
cfg := &config.Config{EventSource: evsConfig, Filters: &config.Filters{}}
745750
evs := NewEventSource(psnap, hsnap, cfg, nil)
746751

@@ -1226,6 +1231,8 @@ func testCallstackEnrichment(t *testing.T, hsnap handle.Snapshotter, psnap ps.Sn
12261231
FlushTimer: 1,
12271232
}
12281233

1234+
evsConfig.Init()
1235+
12291236
cfg := &config.Config{
12301237
EventSource: evsConfig,
12311238
Filters: &config.Filters{},

internal/etw/stackext_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ func TestStackExtensions(t *testing.T) {
3838
FlushTimer: time.Millisecond * 2300,
3939
},
4040
}
41+
42+
cfg.EventSource.Init()
43+
4144
exts := NewStackExtensions(cfg.EventSource)
4245
assert.Len(t, exts.EventIds(), 0)
4346

internal/etw/trace_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ func TestStartTrace(t *testing.T) {
3636
},
3737
}
3838

39+
cfg.EventSource.Init()
40+
3941
trace := NewKernelTrace(cfg)
4042
require.NoError(t, trace.Start())
4143
require.True(t, trace.IsStarted())

pkg/config/eventsource.go

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ package config
2323

2424
import (
2525
"github.com/rabbitstack/fibratus/pkg/event"
26-
"golang.org/x/sys/windows"
26+
"github.com/rabbitstack/fibratus/pkg/util/bitmask"
2727
"runtime"
2828
"time"
2929

@@ -102,7 +102,8 @@ type EventSourceConfig struct {
102102
// ExcludedImages are process image names that will be rejected if they generate a kernel event.
103103
ExcludedImages []string `json:"blacklist.images" yaml:"blacklist.images"`
104104

105-
dropMasks event.EventsetMasks
105+
dropMasks *bitmask.Bitmask
106+
allMasks *bitmask.Bitmask
106107

107108
excludedImages map[string]bool
108109
}
@@ -127,13 +128,21 @@ func (c *EventSourceConfig) initFromViper(v *viper.Viper) {
127128
c.ExcludedEvents = v.GetStringSlice(excludedEvents)
128129
c.ExcludedImages = v.GetStringSlice(excludedImages)
129130

131+
c.dropMasks = bitmask.New()
132+
c.allMasks = bitmask.New()
133+
130134
c.excludedImages = make(map[string]bool)
131135

132136
for _, name := range c.ExcludedEvents {
133137
if typ := event.NameToType(name); typ != event.UnknownType {
134-
c.dropMasks.Set(typ)
138+
c.dropMasks.Set(typ.ID())
135139
}
136140
}
141+
142+
for _, typ := range event.AllWithState() {
143+
c.allMasks.Set(typ.ID())
144+
}
145+
137146
for _, name := range c.ExcludedImages {
138147
c.excludedImages[name] = true
139148
}
@@ -142,35 +151,54 @@ func (c *EventSourceConfig) initFromViper(v *viper.Viper) {
142151
// Init is an exported method to allow initializing exclusion maps from external modules.
143152
func (c *EventSourceConfig) Init() {
144153
c.excludedImages = make(map[string]bool)
154+
155+
if c.dropMasks == nil {
156+
c.dropMasks = bitmask.New()
157+
}
145158
for _, name := range c.ExcludedEvents {
146159
for _, typ := range event.NameToTypes(name) {
147160
if typ != event.UnknownType {
148-
c.dropMasks.Set(typ)
161+
c.dropMasks.Set(typ.ID())
149162
}
150163
}
151164
}
165+
152166
for _, name := range c.ExcludedImages {
153167
c.excludedImages[name] = true
154168
}
169+
170+
if c.allMasks == nil {
171+
c.allMasks = bitmask.New()
172+
}
173+
for _, typ := range event.AllWithState() {
174+
c.allMasks.Set(typ.ID())
175+
}
155176
}
156177

157178
// SetDropMask inserts the event mask in the bitset to
158179
// instruct the given event type should be dropped from
159180
// the event stream.
160-
func (c *EventSourceConfig) SetDropMask(Type event.Type) {
161-
c.dropMasks.Set(Type)
181+
func (c *EventSourceConfig) SetDropMask(typ event.Type) {
182+
c.dropMasks.Set(typ.ID())
162183
}
163184

164185
// TestDropMask checks if the specified event type has
165186
// the drop mask in the bitset.
166-
func (c *EventSourceConfig) TestDropMask(Type event.Type) bool {
167-
return c.dropMasks.Test(Type.GUID(), Type.HookID())
187+
func (c *EventSourceConfig) TestDropMask(typ event.Type) bool {
188+
return c.dropMasks.IsSet(typ.ID())
189+
}
190+
191+
// ExcludeEvent determines whether the supplied short
192+
// event ID exists in the bitset of excluded events.
193+
func (c *EventSourceConfig) ExcludeEvent(id uint) bool {
194+
return c.dropMasks.IsSet(id)
168195
}
169196

170-
// ExcludeEvent determines whether the supplied provider GUID
171-
// and the hook identifier are in the bitset of excluded events.
172-
func (c *EventSourceConfig) ExcludeEvent(guid windows.GUID, hookID uint16) bool {
173-
return c.dropMasks.Test(guid, hookID)
197+
// EventExists determines if the provided event ID exists
198+
// in the internal event catalog by checking the event ID
199+
// bitmask.
200+
func (c *EventSourceConfig) EventExists(id uint) bool {
201+
return c.allMasks.IsSet(id)
174202
}
175203

176204
// ExcludeImage determines whether the process generating event is present in the

pkg/config/eventsource_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ func TestEventSourceConfig(t *testing.T) {
5555
assert.False(t, c.EventSource.EnableImageEvents)
5656
assert.False(t, c.EventSource.EnableFileIOEvents)
5757

58-
assert.True(t, c.EventSource.ExcludeEvent(event.CloseHandle.GUID(), event.CloseHandle.HookID()))
59-
assert.False(t, c.EventSource.ExcludeEvent(event.CreateProcess.GUID(), event.CreateProcess.HookID()))
58+
assert.True(t, c.EventSource.ExcludeEvent(event.CloseHandle.ID()))
59+
assert.False(t, c.EventSource.ExcludeEvent(event.CreateProcess.ID()))
6060

6161
assert.True(t, c.EventSource.ExcludeImage(&pstypes.PS{Name: "svchost.exe"}))
6262
assert.False(t, c.EventSource.ExcludeImage(&pstypes.PS{Name: "explorer.exe"}))

pkg/event/event_windows.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,15 @@ var (
4747

4848
// New constructs a fresh event instance with basic fields and parameters
4949
// from the raw ETW event record.
50-
func New(seq uint64, typ Type, evt *etw.EventRecord) *Event {
50+
func New(seq uint64, evt *etw.EventRecord) *Event {
5151
var (
5252
pid = evt.Header.ProcessID
5353
tid = evt.Header.ThreadID
5454
cpu = *(*uint8)(unsafe.Pointer(&evt.BufferContext.ProcessorIndex[0]))
5555
ts = filetime.ToEpoch(evt.Header.Timestamp)
56+
typ = NewTypeFromEventRecord(evt)
5657
)
58+
5759
e := &Event{
5860
Seq: seq,
5961
PID: pid,
@@ -68,8 +70,10 @@ func New(seq uint64, typ Type, evt *etw.EventRecord) *Event {
6870
Metadata: make(map[MetadataKey]any),
6971
Host: hostname.Get(),
7072
}
73+
7174
e.produceParams(evt)
7275
e.adjustPID()
76+
7377
return e
7478
}
7579

pkg/event/metainfo_windows.go

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,12 +216,42 @@ var indexedEvents = []Info{
216216
// All returns all event types.
217217
func All() []Type {
218218
s := make([]Type, 0, len(types))
219-
for _, Type := range types {
220-
s = append(s, Type)
219+
for _, typ := range types {
220+
s = append(s, typ)
221221
}
222222
return s
223223
}
224224

225+
// AllWithState returns all event types +
226+
// event types used for state management.
227+
func AllWithState() []Type {
228+
s := All()
229+
230+
s = append(s, ProcessRundown)
231+
s = append(s, ThreadRundown)
232+
s = append(s, ImageRundown)
233+
s = append(s, FileRundown)
234+
s = append(s, RegKCBRundown)
235+
s = append(s, RegCreateKCB)
236+
s = append(s, RegDeleteKCB)
237+
s = append(s, FileOpEnd)
238+
s = append(s, ReleaseFile)
239+
s = append(s, MapFileRundown)
240+
s = append(s, StackWalk)
241+
242+
return s
243+
}
244+
245+
// MaxTypeID returns the maximum event type (hook id) value.
246+
func MaxTypeID() uint16 {
247+
types := AllWithState()
248+
ids := make([]uint16, len(types))
249+
for i, t := range types {
250+
ids[i] = t.HookID()
251+
}
252+
return slices.Max(ids)
253+
}
254+
225255
// TypeToEventInfo maps the event type to the structure storing detailed information about the event.
226256
func TypeToEventInfo(typ Type) Info {
227257
if info, ok := events[typ]; ok {

pkg/sys/etw/types.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,24 @@ func (e *EventRecord) HookID() uint16 {
564564
return e.Header.EventDescriptor.ID
565565
}
566566

567+
// ID is an unsigned integer that uniquely
568+
// identifies the event. Handy for bitmask
569+
// operations.
570+
func (e *EventRecord) ID() uint {
571+
d1 := e.Header.ProviderID.Data1
572+
d2 := e.Header.ProviderID.Data2
573+
574+
id := uint(byte(d1>>24))<<56 |
575+
uint(byte(d1>>16))<<48 |
576+
uint(byte(d1>>8))<<40 |
577+
uint(byte(d1))<<32 |
578+
uint(byte(d2>>8))<<24 |
579+
uint(byte(d2))<<16 |
580+
uint(e.HookID())
581+
582+
return id
583+
}
584+
567585
// ReadByte reads the byte from the buffer at the specified offset.
568586
func (e *EventRecord) ReadByte(offset uint16) byte {
569587
if offset > e.BufferLen {

pkg/sys/etw/types_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,8 @@ func TestReadBuffer(t *testing.T) {
9898
tt.assertions(t, ev)
9999
}
100100
}
101+
102+
func TestID(t *testing.T) {
103+
ev := &EventRecord{Header: EventHeader{ProviderID: ThreadpoolGUID, EventDescriptor: EventDescriptor{ID: 44}}}
104+
assert.Equal(t, uint(14439051552138264620), ev.ID())
105+
}

0 commit comments

Comments
 (0)