Skip to content

Commit

Permalink
Change actions to be an interface
Browse files Browse the repository at this point in the history
  • Loading branch information
AlonZivony committed May 30, 2024
1 parent 8b8a87b commit e582e84
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 58 deletions.
32 changes: 17 additions & 15 deletions pkg/ebpf/tracee.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,24 +244,25 @@ func New(cfg config.Config) (*Tracee, error) {
// before choosing them. There is no reason to choose the event in the New function anyhow.
t.eventsDependencies.SubscribeAdd(
dependencies.EventNodeType,
func(node interface{}) dependencies.Action {
func(node interface{}) []dependencies.Action {
eventNode, ok := node.(*dependencies.EventNode)
if !ok {
logger.Errorw("Got node from type not requested")
return dependencies.NoAction
return nil
}
t.addDependencyEventToState(eventNode.GetID(), eventNode.GetDependents())
return dependencies.NoAction
return nil
})
t.eventsDependencies.SubscribeRemove(
dependencies.EventNodeType,
func(node interface{}) {
func(node interface{}) []dependencies.Action {
eventNode, ok := node.(*dependencies.EventNode)
if !ok {
logger.Errorw("Got node from type not requested")
return
return nil
}
t.removeEventFromState(eventNode.GetID())
return nil
})

// Initialize capabilities rings soon
Expand Down Expand Up @@ -934,16 +935,16 @@ func (t *Tracee) validateKallsymsDependencies() {

t.eventsDependencies.SubscribeAdd(
dependencies.EventNodeType,
func(node interface{}) dependencies.Action {
func(node interface{}) []dependencies.Action {
eventNode, ok := node.(*dependencies.EventNode)
if !ok {
logger.Errorw("Got node from type not requested")
return dependencies.NoAction
return nil
}
if !validateEvent(eventNode.GetID()) {
return dependencies.CancelNodeAdd
return []dependencies.Action{dependencies.NewCancelNodeAddAction(fmt.Errorf("event is missing ksymbols"))}
}
return dependencies.NoAction
return nil
})

for eventId := range t.eventsState {
Expand Down Expand Up @@ -1151,33 +1152,34 @@ func (t *Tracee) attachProbes() error {
// probes upon changes
t.eventsDependencies.SubscribeAdd(
dependencies.ProbeNodeType,
func(node interface{}) dependencies.Action {
func(node interface{}) []dependencies.Action {
probeNode, ok := node.(*dependencies.ProbeNode)
if !ok {
logger.Errorw("Got node from type not requested")
return dependencies.NoAction
return nil
}
err := t.probes.Attach(probeNode.GetHandle(), t.cgroups)
if err != nil {
return dependencies.CancelNodeAdd
return []dependencies.Action{dependencies.NewCancelNodeAddAction(err)}
}
return dependencies.NoAction
return nil
})

t.eventsDependencies.SubscribeRemove(
dependencies.ProbeNodeType,
func(node interface{}) {
func(node interface{}) []dependencies.Action {
probeNode, ok := node.(*dependencies.ProbeNode)
if !ok {
logger.Errorw("Got node from type not requested")
return
return nil
}
err := t.probes.Detach(probeNode.GetHandle())
if err != nil {
logger.Debugw("Failed to detach probe",
"probe", probeNode.GetHandle(),
"error", err)
}
return nil
})

// Attach probes to their respective eBPF programs or cancel events if a required probe is missing.
Expand Down
20 changes: 20 additions & 0 deletions pkg/events/dependencies/actions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package dependencies

// Action is a struct representing an action request for the tree by a watcher function.
// All modification operations on the tree should be done using an Action and not directly
// inside a watchers scope, to avoid bugs with operations order.
type Action interface{}

// CancelNodeAddAction cancel the node add to the manager, and cause all its dependencies to be
// removed as well if they are not needed by any other node (similar to UnselectEvent).
// This action will not prevent other watchers from being called.
// When cancelled, event remove watchers will be called to allow cleaning.
// Please use this action instead of calling UnselectEvent directly to avoid bugs with
// operations order.
type CancelNodeAddAction struct {
Reason error
}

func NewCancelNodeAddAction(reason error) *CancelNodeAddAction {
return &CancelNodeAddAction{Reason: reason}
}
34 changes: 34 additions & 0 deletions pkg/events/dependencies/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package dependencies

import (
"errors"
"fmt"
"strings"
)

// ErrNodeAddCancelled is the error produced when cancelling a node add to the manager
// using the CancelNodeAddAction Action.
type ErrNodeAddCancelled struct {
Reasons []error
}

func NewErrNodeAddCancelled(reasons []error) *ErrNodeAddCancelled {
return &ErrNodeAddCancelled{Reasons: reasons}
}

func (cancelErr *ErrNodeAddCancelled) Error() string {
var errorsStrings []string
for _, err := range cancelErr.Reasons {
errorsStrings = append(errorsStrings, err.Error())
}
return fmt.Sprintf("node add was cancelled, reasons: \"%s\"", strings.Join(errorsStrings, "\", \""))
}

func (cancelErr *ErrNodeAddCancelled) AddReason(reason error) {
cancelErr.Reasons = append(cancelErr.Reasons, reason)
}

var (
ErrNodeType = errors.New("unsupported node type")
ErrNodeNotFound = errors.New("node not found")
)
48 changes: 22 additions & 26 deletions pkg/events/dependencies/manager.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package dependencies

import (
"errors"
"fmt"
"reflect"

Expand All @@ -10,13 +9,6 @@ import (
"github.com/aquasecurity/tracee/pkg/logger"
)

type Action int

const (
NoAction Action = iota
CancelNodeAdd // Remove the node from the manager (will still call other watchers)
)

type NodeType string

const (
Expand All @@ -26,12 +18,6 @@ const (
IllegalNodeType NodeType = "illegal"
)

var (
ErrNodeAddCancelled = errors.New("node add was cancelled")
ErrNodeType = errors.New("unsupported node type")
ErrNodeNotFound = errors.New("node not found")
)

// Manager is a management tree for the current dependencies of events.
// As events can depend on multiple things (e.g events, probes), it manages their connections in the form of a tree.
// The tree supports watcher functions for adding and removing nodes.
Expand All @@ -40,28 +26,28 @@ var (
type Manager struct {
events map[events.ID]*EventNode
probes map[probes.Handle]*ProbeNode
onAdd map[NodeType][]func(node interface{}) Action
onRemove map[NodeType][]func(node interface{})
onAdd map[NodeType][]func(node interface{}) []Action
onRemove map[NodeType][]func(node interface{}) []Action
dependenciesGetter func(events.ID) events.Dependencies
}

func NewDependenciesManager(dependenciesGetter func(events.ID) events.Dependencies) *Manager {
return &Manager{
events: make(map[events.ID]*EventNode),
probes: make(map[probes.Handle]*ProbeNode),
onAdd: make(map[NodeType][]func(node interface{}) Action),
onRemove: make(map[NodeType][]func(node interface{})),
onAdd: make(map[NodeType][]func(node interface{}) []Action),
onRemove: make(map[NodeType][]func(node interface{}) []Action),
dependenciesGetter: dependenciesGetter,
}
}

// SubscribeAdd adds a watcher function called upon the addition of an event to the tree.
func (m *Manager) SubscribeAdd(subscribeType NodeType, onAdd func(node interface{}) Action) {
func (m *Manager) SubscribeAdd(subscribeType NodeType, onAdd func(node interface{}) []Action) {
m.onAdd[subscribeType] = append(m.onAdd[subscribeType], onAdd)
}

// SubscribeRemove adds a watcher function called upon the removal of an event from the tree.
func (m *Manager) SubscribeRemove(subscribeType NodeType, onRemove func(node interface{})) {
func (m *Manager) SubscribeRemove(subscribeType NodeType, onRemove func(node interface{}) []Action) {
m.onRemove[subscribeType] = append(m.onRemove[subscribeType], onRemove)
}

Expand Down Expand Up @@ -257,20 +243,30 @@ func (m *Manager) triggerOnAdd(node interface{}) error {
var actions []Action
addWatchers := m.onAdd[nodeType]
for _, onAdd := range addWatchers {
actions = append(actions, onAdd(node))
actions = append(actions, onAdd(node)...)
}
addWatchers = m.onAdd[AllNodeTypes]
for _, onAdd := range addWatchers {
actions = append(actions, onAdd(node))
actions = append(actions, onAdd(node)...)
}

var cancelNodeAddErr *ErrNodeAddCancelled
shouldCancel := false
for _, action := range actions {
switch action {
case CancelNodeAdd:
err = ErrNodeAddCancelled
switch typedAction := action.(type) {
case *CancelNodeAddAction:
shouldCancel = true
if cancelNodeAddErr == nil {
err = NewErrNodeAddCancelled([]error{typedAction.Reason})
} else {
cancelNodeAddErr.AddReason(typedAction.Reason)
}
}
}
return err
if shouldCancel {
return cancelNodeAddErr
}
return nil
}

// triggerOnRemove triggers all on-remove watchers
Expand Down
Loading

0 comments on commit e582e84

Please sign in to comment.