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

feat(events): introduce events fallbacks #3965

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pkg/cmd/initialize/sigs.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ func CreateEventsFromSignatures(startId events.ID, sigs []detect.Signature) map[
[]events.Probe{},
[]events.TailCall{},
events.Capabilities{},
[]events.DependenciesFallback{},
),
[]trace.ArgMeta{},
properties,
Expand Down
4 changes: 4 additions & 0 deletions pkg/cmd/initialize/sigs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ func Test_CreateEventsFromSigs(t *testing.T) {
[]events.Probe{},
[]events.TailCall{},
events.Capabilities{},
[]events.DependenciesFallback{},
),
[]trace.ArgMeta{},
nil,
Expand Down Expand Up @@ -84,6 +85,7 @@ func Test_CreateEventsFromSigs(t *testing.T) {
[]events.Probe{},
[]events.TailCall{},
events.Capabilities{},
[]events.DependenciesFallback{},
),
[]trace.ArgMeta{},
nil,
Expand All @@ -107,6 +109,7 @@ func Test_CreateEventsFromSigs(t *testing.T) {
[]events.Probe{},
[]events.TailCall{},
events.Capabilities{},
[]events.DependenciesFallback{},
),
[]trace.ArgMeta{},
nil,
Expand Down Expand Up @@ -145,6 +148,7 @@ func Test_CreateEventsFromSigs(t *testing.T) {
[]events.Probe{},
[]events.TailCall{},
events.Capabilities{},
[]events.DependenciesFallback{},
),
[]trace.ArgMeta{},
nil,
Expand Down
60 changes: 58 additions & 2 deletions pkg/ebpf/tracee.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,33 @@ func (t *Tracee) addDependencyEventToState(evtID events.ID, dependentEvts []even
}
}

// updateDependenciesStateRecursive change all dependencies submit states to match
// their submit states, and current submit state of their dependents.
// This should be called in the case of a fallback dependencies, as the events
// dependencies change, on the older dependencies.
// This should make sure that their submit will match their new dependents and
// emit state.
func (t *Tracee) updateDependenciesStateRecursive(eventNode *dependencies.EventNode) {
for _, dependencyEventID := range eventNode.GetDependencies().GetIDs() {
dependencyNode, err := t.eventsDependencies.GetEvent(dependencyEventID)
if err != nil { // event does not exist anymore in dependencies
t.removeEventFromState(dependencyEventID)
continue
}
dependencyState := t.eventsState[dependencyEventID]
newState := events.EventState{
Emit: dependencyState.Emit,
Submit: dependencyState.Emit,
}
for _, dependantID := range dependencyNode.GetDependents() {
dependantState := t.eventsState[dependantID]
newState.Submit |= dependantState.Submit
}
t.eventsState[dependencyEventID] = newState
t.updateDependenciesStateRecursive(dependencyNode)
}
}

func (t *Tracee) removeEventFromState(evtID events.ID) {
logger.Debugw("Remove event from state", "event", events.Core.GetDefinitionByID(evtID).GetName())
delete(t.eventsState, evtID)
Expand Down Expand Up @@ -270,6 +297,23 @@ func New(cfg config.Config) (*Tracee, error) {
t.removeEventFromState(eventNode.GetID())
return nil
})
t.eventsDependencies.SubscribeChange(
dependencies.EventNodeType,
func(oldNode interface{}, newNode interface{}) []dependencies.Action {
oldEventNode, ok := oldNode.(*dependencies.EventNode)
if !ok {
logger.Errorw("Got node from type not requested")
return nil
}
newEventNode, ok := newNode.(*dependencies.EventNode)
if !ok {
logger.Errorw("Got node from type not requested")
return nil
}
t.updateDependenciesStateRecursive(oldEventNode)
t.addDependenciesToStateRecursive(newEventNode)
return nil
})

// Initialize capabilities rings soon

Expand Down Expand Up @@ -365,6 +409,18 @@ func New(cfg config.Config) (*Tracee, error) {
if err != nil {
return t, errfmt.WrapError(err)
}
// Also add all capabilities required by fallbacks
for _, fallback := range deps.GetFallbacks() {
fallbackCaps := fallback.GetDependencies().GetCapabilities()
err = caps.BaseRingAdd(fallbackCaps.GetBase()...)
if err != nil {
return t, errfmt.WrapError(err)
}
err = caps.BaseRingAdd(fallbackCaps.GetEBPF()...)
if err != nil {
return t, errfmt.WrapError(err)
}
}
}
}

Expand Down Expand Up @@ -1076,7 +1132,7 @@ func (t *Tracee) validateKallsymsDependencies() {
for eventId := range t.eventsState {
if !validateEvent(eventId) {
// Cancel the event, its dependencies and its dependent events
err := t.eventsDependencies.RemoveEvent(eventId)
_, err := t.eventsDependencies.FailEvent(eventId)
if err != nil {
logger.Warnw("Failed to remove event from dependencies manager", "remove reason", "missing ksymbols", "error", err)
}
Expand Down Expand Up @@ -1312,7 +1368,7 @@ func (t *Tracee) attachProbes() error {
for eventID := range t.eventsState {
err := t.attachEvent(eventID)
if err != nil {
err := t.eventsDependencies.RemoveEvent(eventID)
_, err = t.eventsDependencies.FailEvent(eventID)
if err != nil {
logger.Warnw("Failed to remove event from dependencies manager", "remove reason", "failed probes attachment", "error", err)
}
Expand Down
28 changes: 28 additions & 0 deletions pkg/events/definition_dependencies.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type Dependencies struct {
probes []Probe
tailCalls []TailCall
capabilities Capabilities
fallbacks []DependenciesFallback
}

func NewDependencies(
Expand All @@ -21,13 +22,15 @@ func NewDependencies(
givenProbes []Probe,
givenTailCalls []TailCall,
givenCapabilities Capabilities,
fallbacks []DependenciesFallback,
) Dependencies {
return Dependencies{
ids: givenIDs,
kSymbols: givenkSymbols,
probes: givenProbes,
tailCalls: givenTailCalls,
capabilities: givenCapabilities,
fallbacks: fallbacks,
}
}

Expand Down Expand Up @@ -73,6 +76,13 @@ func (d Dependencies) GetCapabilities() Capabilities {
return d.capabilities
}

func (d Dependencies) GetFallbacks() []DependenciesFallback {
if d.fallbacks == nil {
return []DependenciesFallback{}
}
return d.fallbacks
}

// Probe

type Probe struct {
Expand Down Expand Up @@ -176,3 +186,21 @@ func (tc TailCall) GetMapName() string {
func (tc TailCall) GetProgName() string {
return tc.progName
}

// DependenciesFallback is a struct representing a set of fallback dependencies
// to be utilized in case of issues with the event's primary dependencies.
// This struct envelopes the dependencies, providing the flexibility to incorporate
// future logic for determining whether to employ the fallback or not
type DependenciesFallback struct {
dependencies Dependencies
}

func NewDependenciesFallback(dependencies Dependencies) DependenciesFallback {
return DependenciesFallback{
dependencies: dependencies,
}
}

func (df DependenciesFallback) GetDependencies() Dependencies {
return df.dependencies
}
5 changes: 5 additions & 0 deletions pkg/events/dependencies/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ func (cancelErr *ErrNodeAddCancelled) Error() string {
return fmt.Sprintf("node add was cancelled, reasons: \"%s\"", strings.Join(errorsStrings, "\", \""))
}

func (cancelErr *ErrNodeAddCancelled) Is(err error) bool {
_, ok := err.(*ErrNodeAddCancelled)
return ok
}

func (cancelErr *ErrNodeAddCancelled) AddReason(reason error) {
cancelErr.Reasons = append(cancelErr.Reasons, reason)
}
Expand Down
29 changes: 27 additions & 2 deletions pkg/events/dependencies/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ type EventNode struct {
dependencies events.Dependencies
// There won't be more than a couple of dependents, so a slice is better for
// both performance and supporting efficient thread-safe operation in the future
dependents []events.ID
dependents []events.ID
currentFallback int // The index of current fallback dependencies
}

func newDependenciesNode(id events.ID, dependencies events.Dependencies, chosenDirectly bool) *EventNode {
Expand All @@ -23,6 +24,7 @@ func newDependenciesNode(id events.ID, dependencies events.Dependencies, chosenD
explicitlySelected: chosenDirectly,
dependencies: dependencies,
dependents: make([]events.ID, 0),
currentFallback: -1,
}
}

Expand All @@ -31,7 +33,11 @@ func (en *EventNode) GetID() events.ID {
}

func (en *EventNode) GetDependencies() events.Dependencies {
return en.dependencies
if en.currentFallback < 0 {
return en.dependencies
}
fallbacks := en.dependencies.GetFallbacks()
return fallbacks[en.currentFallback].GetDependencies()
}

func (en *EventNode) GetDependents() []events.ID {
Expand Down Expand Up @@ -71,3 +77,22 @@ func (en *EventNode) removeDependent(dependent events.ID) {
}
}
}

func (en *EventNode) fallback() bool {
fallbacks := en.dependencies.GetFallbacks()
if (en.currentFallback + 1) >= len(fallbacks) {
return false
}
en.currentFallback += 1
return true
}

func (en *EventNode) clone() *EventNode {
clone := &EventNode{
id: en.id,
explicitlySelected: en.explicitlySelected,
dependencies: en.dependencies,
dependents: slices.Clone[[]events.ID](en.dependents),
}
return clone
}
Loading
Loading