Skip to content

Commit 11ab687

Browse files
committed
fix(filter): Provide accessor default value
When the accessor fails or return a nil value, populate the valuer map with a default value. This is important to avoid rule matching misbehaviours.
1 parent e68f46d commit 11ab687

File tree

4 files changed

+70
-7
lines changed

4 files changed

+70
-7
lines changed

pkg/filter/accessor.go

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ import (
2323
"github.com/rabbitstack/fibratus/pkg/event"
2424
"github.com/rabbitstack/fibratus/pkg/event/params"
2525
"github.com/rabbitstack/fibratus/pkg/filter/fields"
26+
"net"
2627
"reflect"
28+
"time"
2729
)
2830

2931
var (
@@ -62,7 +64,7 @@ func newEventAccessor() Accessor {
6264
const timeFmt = "15:04:05"
6365
const dateFmt = "2006-01-02"
6466

65-
func (k *evtAccessor) Get(f Field, evt *event.Event) (params.Value, error) {
67+
func (*evtAccessor) Get(f Field, evt *event.Event) (params.Value, error) {
6668
switch f.Name {
6769
case fields.EvtSeq, fields.KevtSeq:
6870
return evt.Seq, nil
@@ -238,3 +240,30 @@ func (f *filter) removeAccessor(removed Accessor) {
238240
}
239241
}
240242
}
243+
244+
// defaultAccessorValue provides the default value for the field.
245+
// This value is typically assigned when the accessor returns an
246+
// error or nil value, but the map valuer must contain the resolved
247+
// field name in case of filters using the not operator.
248+
func defaultAccessorValue(field Field) any {
249+
switch field.Name.Type() {
250+
case params.Uint8, params.Int64, params.Int8, params.Int32, params.Int16,
251+
params.Uint16, params.Port, params.Uint32, params.Uint64, params.PID,
252+
params.TID, params.Flags, params.Flags64:
253+
return 0
254+
case params.Float, params.Double:
255+
return 0.0
256+
case params.Time:
257+
return time.Now()
258+
case params.Bool:
259+
return false
260+
case params.IP, params.IPv4, params.IPv6:
261+
return net.IP{}
262+
case params.Binary:
263+
return []byte{}
264+
case params.Slice:
265+
return []string{}
266+
default:
267+
return ""
268+
}
269+
}

pkg/filter/fields/fields_windows.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,9 @@ const (
609609
// String casts the field type to string.
610610
func (f Field) String() string { return string(f) }
611611

612+
// Type returns the data type that this field contains.
613+
func (f Field) Type() params.Type { return fields[f].Type }
614+
612615
func (f Field) IsPsField() bool { return strings.HasPrefix(string(f), "ps.") }
613616
func (f Field) IsKevtField() bool { return strings.HasPrefix(string(f), "evt.") }
614617
func (f Field) IsThreadField() bool { return strings.HasPrefix(string(f), "thread.") }

pkg/filter/filter.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -423,14 +423,15 @@ func (f *filter) mapValuer(evt *event.Event) map[string]interface{} {
423423
continue
424424
}
425425
v, err := accessor.Get(field, evt)
426-
if err != nil && !errs.IsParamNotFound(err) {
427-
accessorErrors.Add(err.Error(), 1)
426+
if v == nil || err != nil {
427+
valuer[field.Value] = defaultAccessorValue(field)
428+
if err != nil && !errs.IsParamNotFound(err) {
429+
accessorErrors.Add(err.Error(), 1)
430+
}
428431
continue
429432
}
430-
if v != nil {
431-
valuer[field.Value] = v
432-
break
433-
}
433+
valuer[field.Value] = v
434+
break
434435
}
435436
}
436437
return valuer

pkg/filter/filter_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,16 @@ func TestProcFilter(t *testing.T) {
201201
},
202202
}
203203

204+
evt2 := &event.Event{
205+
Type: event.OpenProcess,
206+
Category: event.Process,
207+
Params: event.Params{
208+
params.DesiredAccess: {Name: params.DesiredAccess, Type: params.Flags, Value: uint32(0x1400), Flags: event.PsAccessRightFlags},
209+
},
210+
Name: "OpenProcess",
211+
PID: 1023,
212+
}
213+
204214
var tests = []struct {
205215
filter string
206216
matches bool
@@ -340,6 +350,26 @@ func TestProcFilter(t *testing.T) {
340350
t.Errorf("%d. %q ps filter mismatch: exp=%t got=%t", i, tt.filter, tt.matches, matches)
341351
}
342352
}
353+
354+
var tests2 = []struct {
355+
filter string
356+
matches bool
357+
}{
358+
359+
{`ps.exe = ''`, true},
360+
}
361+
362+
for i, tt := range tests2 {
363+
f := New(tt.filter, cfg)
364+
err := f.Compile()
365+
if err != nil {
366+
t.Fatal(err)
367+
}
368+
matches := f.Run(evt2)
369+
if matches != tt.matches {
370+
t.Errorf("%d. %q ps filter mismatch: exp=%t got=%t", i, tt.filter, tt.matches, matches)
371+
}
372+
}
343373
}
344374

345375
func TestThreadFilter(t *testing.T) {

0 commit comments

Comments
 (0)