Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: filter dispatching to signatures #3729

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/tracee/cmd/analyze.go
Expand Up @@ -123,7 +123,7 @@ tracee analyze --events anti_debugging events.json`,

fmt.Printf("Loading %d signature events\n", len(sigs))

initialize.CreateEventsFromSignatures(events.StartSignatureID, sigs)
_ = initialize.CreateEventsFromSignatures(events.StartSignatureID, sigs)

engineConfig := engine.Config{
Signatures: sigs,
Expand Down
7 changes: 4 additions & 3 deletions pkg/cmd/cobra/cobra.go
Expand Up @@ -69,7 +69,7 @@ func GetTraceeRunner(c *cobra.Command, version string) (cmd.Runner, error) {
return runner, err
}

initialize.CreateEventsFromSignatures(events.StartSignatureID, sigs)
sigNameToEventId := initialize.CreateEventsFromSignatures(events.StartSignatureID, sigs)

// Initialize a tracee config structure

Expand Down Expand Up @@ -322,8 +322,9 @@ func GetTraceeRunner(c *cobra.Command, version string) (cmd.Runner, error) {
runner.TraceeConfig.Output.ParseArguments = true

runner.TraceeConfig.EngineConfig = engine.Config{
Enabled: true,
Signatures: sigs,
Enabled: true,
SigNameToEventID: sigNameToEventId,
Signatures: sigs,
// This used to be a flag, we have removed the flag from this binary to test
// if users do use it or not.
SignatureBufferSize: 1000,
Expand Down
13 changes: 11 additions & 2 deletions pkg/cmd/initialize/sigs.go
Expand Up @@ -9,9 +9,9 @@ import (
"github.com/aquasecurity/tracee/types/trace"
)

func CreateEventsFromSignatures(startId events.ID, sigs []detect.Signature) {
func CreateEventsFromSignatures(startId events.ID, sigs []detect.Signature) map[string]int32 {
newEventDefID := startId

res := make(map[string]int32)
for _, s := range sigs {
m, err := s.GetMetadata()
if err != nil {
Expand All @@ -28,6 +28,13 @@ func CreateEventsFromSignatures(startId events.ID, sigs []detect.Signature) {
evtDependency := make([]events.ID, 0)

for _, s := range selectedEvents {
if s.Source != "tracee" {
// A legacy solution we supported was for external sources to push events
// into signatures. They would declare their source to be a different name instead
// of "tracee".
// As such, actual event dependencies should only be sourced from "tracee" selectors.
continue
}
eventDefID, found := events.Core.GetDefinitionIDByName(s.Name)
if !found {
logger.Errorw("Failed to load event dependency", "event", s.Name)
Expand Down Expand Up @@ -78,6 +85,8 @@ func CreateEventsFromSignatures(startId events.ID, sigs []detect.Signature) {
continue
}

res[m.EventName] = int32(newEventDefID)
newEventDefID++
}
return res
}
2 changes: 1 addition & 1 deletion pkg/cmd/initialize/sigs_test.go
Expand Up @@ -192,7 +192,7 @@ func newFakeSignature(name string, deps []string) detect.Signature {
selectedEvents := make([]detect.SignatureEventSelector, 0, len(deps))

for _, d := range deps {
eventSelector := detect.SignatureEventSelector{Name: d}
eventSelector := detect.SignatureEventSelector{Name: d, Source: "tracee", Origin: "*"}
selectedEvents = append(selectedEvents, eventSelector)
}

Expand Down
6 changes: 6 additions & 0 deletions pkg/ebpf/signature_engine.go
Expand Up @@ -27,6 +27,12 @@ func (t *Tracee) engineEvents(ctx context.Context, in <-chan *trace.Event) (<-ch
// Prepare built in data sources
t.config.EngineConfig.DataSources = t.PrepareBuiltinDataSources()

// Share event states (by reference)
t.config.EngineConfig.ShouldDispatchEvent = func(eventIdInt32 int32) bool {
_, ok := t.eventsState[events.ID(eventIdInt32)]
return ok
}

sigEngine, err := engine.NewEngine(t.config.EngineConfig, source, engineOutput)
if err != nil {
logger.Fatalw("failed to start signature engine in \"everything is an event\" mode", "error", err)
Expand Down
37 changes: 35 additions & 2 deletions pkg/signatures/engine/engine.go
Expand Up @@ -18,8 +18,18 @@ const ALL_EVENT_TYPES = "*"

// Config defines the engine's configurable values
type Config struct {
// Enables the signatures engine to run in the events pipeline
Enabled bool
// Engine-in-Pipeline related configuration
Enabled bool // Enables the signatures engine to run in the events pipeline
SigNameToEventID map[string]int32 // Cache of loaded signature event names to event ids, used to filter in dispatching

// Callback from tracee to determine if event should be dispatched to signature.
// This is done as a callback becaues importing the events package breaks compilation for the
// tracee-rules binary.
// When tracee-rules is removed, and the policy coordinator is implemented (PR #3305)
// this solution should be abandoned in favor of using it alongside the engine.
ShouldDispatchEvent func(eventIdInt32 int32) bool

// General engine configuration
SignatureBufferSize uint
Signatures []detect.Signature
DataSources []detect.DataSource
Expand Down Expand Up @@ -248,9 +258,32 @@ drain:
}

func (engine *Engine) dispatchEvent(s detect.Signature, event protocol.Event) {
if engine.config.Enabled {
// Do this test only if engine runs as part of the event pipeline
if ok := engine.filterDispatchInPipeline(s, event); !ok {
return
}
}

engine.signatures[s] <- event
}

func (engine *Engine) filterDispatchInPipeline(s detect.Signature, event protocol.Event) bool {
md, err := s.GetMetadata()
if err != nil {
logger.Warnw(fmt.Sprintf("event %s not dispatched to signature: no metadata", event.Selector().Name))
return false
}
evtName := md.EventName
id, ok := engine.config.SigNameToEventID[evtName] // use specialized cache to avoid definiton lookup
if !ok {
logger.Warnw(fmt.Sprintf("event %s not dispatched to signature: no eventname declared for siganture %s", event.Selector().Name, md.ID))
return false
}

return engine.config.ShouldDispatchEvent(id)
}

// TODO: This method seems not to be used, let's confirm inside the team and remove it if not needed
// LoadSignature will call the internal signature loading logic and activate its handling business logics.
// It will return the signature ID as well as error.
Expand Down