From ff5a06b4335a6ed83c30526f0a5726d032e91182 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Momar=20TOUR=C3=89?= Date: Mon, 16 Dec 2024 18:07:31 +0100 Subject: [PATCH 1/6] moved some logics from the probe to the process resover, refactor tests to reflect new approach --- pkg/security/probe/probe_ebpf.go | 45 +- .../resolvers/process/resolver_ebpf.go | 56 +- .../resolvers/process/resolver_test.go | 741 +++++++++--------- 3 files changed, 431 insertions(+), 411 deletions(-) diff --git a/pkg/security/probe/probe_ebpf.go b/pkg/security/probe/probe_ebpf.go index f06cbe8fa45ae..a75b3d3491e6a 100644 --- a/pkg/security/probe/probe_ebpf.go +++ b/pkg/security/probe/probe_ebpf.go @@ -720,7 +720,7 @@ func (p *EBPFProbe) setProcessContext(eventType model.EventType, event *model.Ev } } - // flush exited process + // flush exited processpe p.Resolvers.ProcessResolver.DequeueExited() return true @@ -886,14 +886,7 @@ func (p *EBPFProbe) handleEvent(CPU int, data []byte) { return } - if process.IsKThread(event.ProcessCacheEntry.PPid, event.ProcessCacheEntry.Pid) { - return - } - - p.Resolvers.ProcessResolver.ApplyBootTime(event.ProcessCacheEntry) - event.ProcessCacheEntry.SetSpan(event.SpanContext.SpanID, event.SpanContext.TraceID) - - p.Resolvers.ProcessResolver.AddForkEntry(event.ProcessCacheEntry, event.PIDContext.ExecInode, newEntryCb) + p.Resolvers.ProcessResolver.AddForkEntry(event, newEntryCb) case model.ExecEventType: // unmarshal and fill event.processCacheEntry if _, err = p.unmarshalProcessCacheEntry(event, data[offset:]); err != nil { @@ -901,18 +894,17 @@ func (p *EBPFProbe) handleEvent(CPU int, data []byte) { return } - if err = p.Resolvers.ProcessResolver.ResolveNewProcessCacheEntry(event.ProcessCacheEntry, event.ContainerContext); err != nil { - seclog.Debugf("failed to resolve new process cache entry context for pid %d: %s", event.PIDContext.Pid, err) - + err = p.Resolvers.ProcessResolver.AddExecEntry(event) + if err != nil { var errResolution *path.ErrPathResolution if errors.As(err, &errResolution) { event.SetPathResolutionError(&event.ProcessCacheEntry.FileEvent, err) + } else { + seclog.Errorf("failed to insert exec event: %s (offset %d, len %d)", err, offset, len(data)) + return } - } else { - p.Resolvers.ProcessResolver.AddExecEntry(event.ProcessCacheEntry, event.PIDContext.ExecInode) } - event.Exec.Process = &event.ProcessCacheEntry.Process } if !p.setProcessContext(eventType, event, newEntryCb) { @@ -1023,26 +1015,13 @@ func (p *EBPFProbe) handleEvent(CPU int, data []byte) { seclog.Errorf("failed to decode exit event: %s (offset %d, len %d)", err, offset, len(data)) return } - - var exists bool - event.ProcessCacheEntry, exists = p.fieldHandlers.GetProcessCacheEntry(event, newEntryCb) + exists := p.Resolvers.ProcessResolver.AddExitEntry(event, newEntryCb) if !exists { - // no need to dispatch an exit event that don't have the corresponding cache entry - return + p.Resolvers.MountResolver.DelPid(event.Exit.Pid) + // update action reports + p.processKiller.HandleProcessExited(event) + p.fileHasher.HandleProcessExited(event) } - - // Use the event timestamp as exit time - // The local process cache hasn't been updated yet with the exit time when the exit event is first seen - // The pid_cache kernel map has the exit_time but it's only accessed if there's a local miss - event.ProcessCacheEntry.Process.ExitTime = p.fieldHandlers.ResolveEventTime(event, &event.BaseEvent) - event.Exit.Process = &event.ProcessCacheEntry.Process - - // update mount pid mapping - p.Resolvers.MountResolver.DelPid(event.Exit.Pid) - - // update action reports - p.processKiller.HandleProcessExited(event) - p.fileHasher.HandleProcessExited(event) case model.SetuidEventType: // the process context may be incorrect, do not modify it if event.Error != nil { diff --git a/pkg/security/resolvers/process/resolver_ebpf.go b/pkg/security/resolvers/process/resolver_ebpf.go index dc5694dd55647..e517dc6549505 100644 --- a/pkg/security/resolvers/process/resolver_ebpf.go +++ b/pkg/security/resolvers/process/resolver_ebpf.go @@ -290,27 +290,58 @@ func (p *EBPFResolver) UpdateArgsEnvs(event *model.ArgsEnvsEvent) { } // AddForkEntry adds an entry to the local cache and returns the newly created entry -func (p *EBPFResolver) AddForkEntry(entry *model.ProcessCacheEntry, inode uint64, newEntryCb func(*model.ProcessCacheEntry, error)) { - if entry.Pid == 0 { +func (p *EBPFResolver) AddForkEntry(event *model.Event, newEntryCb func(*model.ProcessCacheEntry, error)) { + if IsKThread(event.ProcessCacheEntry.PPid, event.ProcessCacheEntry.Pid) { + return + } + + p.ApplyBootTime(event.ProcessCacheEntry) + event.ProcessCacheEntry.SetSpan(event.SpanContext.SpanID, event.SpanContext.TraceID) + + if event.ProcessCacheEntry.Pid == 0 { return } p.Lock() defer p.Unlock() - - p.insertForkEntry(entry, inode, model.ProcessCacheEntryFromEvent, newEntryCb) + p.insertForkEntry(event.ProcessCacheEntry, event.PIDContext.ExecInode, model.ProcessCacheEntryFromEvent, newEntryCb) } // AddExecEntry adds an entry to the local cache and returns the newly created entry -func (p *EBPFResolver) AddExecEntry(entry *model.ProcessCacheEntry, inode uint64) { - if entry.Pid == 0 { - return +func (p *EBPFResolver) AddExecEntry(event *model.Event) error { + + if event.ProcessCacheEntry.Pid == 0 { + return errors.New("no pid context") } + err := p.ResolveNewProcessCacheEntry(event.ProcessCacheEntry, event.ContainerContext) + if err != nil { + return err + } + + event.Exec.Process = &event.ProcessCacheEntry.Process + p.Lock() defer p.Unlock() + p.insertExecEntry(event.ProcessCacheEntry, event.PIDContext.ExecInode, model.ProcessCacheEntryFromEvent) + return nil +} + +// AddExitEntry delete entry from the local cache if present +func (p *EBPFResolver) AddExitEntry(event *model.Event, newEntryCb func(*model.ProcessCacheEntry, error)) bool { + event.ProcessCacheEntry = p.resolve(event.PIDContext.Pid, event.PIDContext.Tid, event.PIDContext.ExecInode, false, newEntryCb) + if event.ProcessCacheEntry == nil { + // no need to dispatch an exit event that don't have the corresponding cache entry + return false + } + + // Use the event timestamp as exit time + // The local process cache hasn't been updated yet with the exit time when the exit event is first seen + // The pid_cache kernel map has the exit_time but it's only accessed if there's a local miss + event.ProcessCacheEntry.ExitTime = event.FieldHandlers.ResolveEventTime(event, &event.BaseEvent) + event.Exit.Process = &event.ProcessCacheEntry.Process + return true - p.insertExecEntry(entry, inode, model.ProcessCacheEntryFromEvent) } // enrichEventFromProc uses /proc to enrich a ProcessCacheEntry with additional metadata @@ -520,6 +551,7 @@ func (p *EBPFResolver) insertEntry(entry, prev *model.ProcessCacheEntry, source } func (p *EBPFResolver) insertForkEntry(entry *model.ProcessCacheEntry, inode uint64, source uint64, newEntryCb func(*model.ProcessCacheEntry, error)) { + if entry.Pid == 0 { return } @@ -529,9 +561,12 @@ func (p *EBPFResolver) insertForkEntry(entry *model.ProcessCacheEntry, inode uin // this shouldn't happen but it is better to exit the prev and let the new one replace it prev.Exit(entry.ForkTime) } - if entry.Pid != 1 { parent := p.entryCache[entry.PPid] + if parent != nil { + fmt.Println(parent.FileEvent.Inode, inode) + } + if entry.PPid >= 1 && inode != 0 && (parent == nil || parent.FileEvent.Inode != inode) { if candidate := p.resolve(entry.PPid, entry.PPid, inode, true, newEntryCb); candidate != nil { parent = candidate @@ -568,7 +603,6 @@ func (p *EBPFResolver) insertExecEntry(entry *model.ProcessCacheEntry, inode uin prev.ApplyExecTimeOf(entry) return } - prev.Exec(entry) } else { entry.IsParentMissing = true @@ -654,7 +688,6 @@ func (p *EBPFResolver) resolveFileFieldsPath(e *model.FileFields, pce *model.Pro err error maxDepthRetry = 3 ) - for maxDepthRetry > 0 { pathnameStr, mountPath, source, origin, err = p.pathResolver.ResolveFileFieldsPath(e, &pce.PIDContext, ctrCtx) if err == nil { @@ -686,7 +719,6 @@ func (p *EBPFResolver) SetProcessPath(fileEvent *model.FileEvent, pce *model.Pro if fileEvent.Inode == 0 { return onError("", &model.ErrInvalidKeyPath{Inode: fileEvent.Inode, MountID: fileEvent.MountID}) } - pathnameStr, mountPath, source, origin, err := p.resolveFileFieldsPath(&fileEvent.FileFields, pce, ctrCtx) if err != nil { return onError(pathnameStr, err) diff --git a/pkg/security/resolvers/process/resolver_test.go b/pkg/security/resolvers/process/resolver_test.go index c2febee639beb..6f3226ec534bd 100644 --- a/pkg/security/resolvers/process/resolver_test.go +++ b/pkg/security/resolvers/process/resolver_test.go @@ -16,10 +16,44 @@ import ( "github.com/avast/retry-go/v4" "github.com/stretchr/testify/assert" + "github.com/DataDog/datadog-agent/pkg/security/resolvers/cgroup" + "github.com/DataDog/datadog-agent/pkg/security/resolvers/path" + "github.com/DataDog/datadog-agent/pkg/security/resolvers/usergroup" "github.com/DataDog/datadog-agent/pkg/security/secl/model" + "github.com/DataDog/datadog-agent/pkg/util/ktime" "github.com/DataDog/datadog-go/v5/statsd" ) +func newFakeForkEvent(ppid, pid int, inode uint64, resolver *EBPFResolver) *model.Event { + e := model.NewFakeEvent() + e.Type = uint32(model.ForkEventType) + e.ProcessCacheEntry = resolver.NewProcessCacheEntry(model.PIDContext{Pid: uint32(pid), Tid: uint32(pid)}) + e.PIDContext = e.ProcessCacheEntry.PIDContext + e.ProcessContext = &e.ProcessCacheEntry.ProcessContext + e.ProcessCacheEntry.ForkTime = time.Now() + e.ProcessCacheEntry.PPid = uint32(ppid) + e.ProcessCacheEntry.Pid = uint32(pid) + e.ProcessCacheEntry.FileEvent.Inode = inode + return e +} + +func newFakeExecEvent(ppid, pid int, inode uint64, resolver *EBPFResolver) *model.Event { + e := model.NewFakeEvent() + e.Type = uint32(model.ExecEventType) + e.ProcessCacheEntry = resolver.NewProcessCacheEntry(model.PIDContext{Pid: uint32(pid), Tid: uint32(pid)}) + e.PIDContext = e.ProcessCacheEntry.PIDContext + e.ProcessContext = &e.ProcessCacheEntry.ProcessContext + e.ProcessCacheEntry.ExecTime = time.Now() + e.ProcessCacheEntry.PPid = uint32(ppid) + e.ProcessCacheEntry.Pid = uint32(pid) + e.ProcessCacheEntry.FileEvent.Inode = inode + return e +} + +func exit(event *model.Event) { + event.Type = uint32(model.ExitEventType) +} + func testCacheSize(t *testing.T, resolver *EBPFResolver) { err := retry.Do( func() error { @@ -33,701 +67,676 @@ func testCacheSize(t *testing.T, resolver *EBPFResolver) { assert.NoError(t, err) } -func TestFork1st(t *testing.T) { - resolver, err := NewEBPFResolver(nil, nil, &statsd.NoOpClient{}, nil, nil, nil, nil, nil, nil, nil, nil, NewResolverOpts()) +func newResolver() (*EBPFResolver, error) { + timeResolver, err := ktime.NewResolver() if err != nil { - t.Fatal(err) + return nil, err } - parent := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 1, Tid: 1}) - parent.ForkTime = time.Now() + cgroupsResolver, err := cgroup.NewResolver() + if err != nil { + return nil, err + } - child := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 2, Tid: 2}) - child.PPid = parent.Pid - child.ForkTime = time.Now() + userGroupResolver, err := usergroup.NewResolver(cgroupsResolver) + if err != nil { + return nil, err + } + + resolver, err := NewEBPFResolver(nil, nil, &statsd.NoOpClient{}, nil, nil, nil, cgroupsResolver, userGroupResolver, timeResolver, &path.NoOpResolver{}, nil, NewResolverOpts()) + if err != nil { + return nil, err + } + + return resolver, nil +} + +func TestFork1st(t *testing.T) { + + resolver, err := newResolver() + if err != nil { + t.Fatal() + } + + parent := newFakeForkEvent(0, 3, 123, resolver) + child := newFakeForkEvent(3, 4, 123, resolver) // parent - resolver.AddForkEntry(parent, 0, nil) - assert.Equal(t, parent, resolver.entryCache[parent.Pid]) + resolver.AddForkEntry(parent, nil) + assert.Equal(t, parent.ProcessCacheEntry, resolver.entryCache[parent.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) assert.EqualValues(t, 1, resolver.cacheSize.Load()) // parent // \ child - resolver.AddForkEntry(child, 0, nil) - assert.Equal(t, child, resolver.entryCache[child.Pid]) + resolver.AddForkEntry(child, nil) + assert.Equal(t, child.ProcessCacheEntry, resolver.entryCache[child.ProcessCacheEntry.Pid]) assert.Equal(t, 2, len(resolver.entryCache)) - assert.Equal(t, parent, child.Ancestor) + assert.Equal(t, parent.ProcessCacheEntry, child.ProcessCacheEntry.Ancestor) assert.EqualValues(t, 2, resolver.cacheSize.Load()) // parent - resolver.DeleteEntry(child.Pid, time.Now()) - assert.Nil(t, resolver.entryCache[child.Pid]) + exit(child) + resolver.AddExitEntry(child, nil) + resolver.DeleteEntry(child.ProcessCacheEntry.Pid, child.ResolveEventTime()) + + assert.Nil(t, resolver.entryCache[child.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) // nothing - resolver.DeleteEntry(parent.Pid, time.Now()) - assert.Zero(t, len(resolver.entryCache)) + exit(parent) + resolver.AddExitEntry(parent, nil) + resolver.DeleteEntry(parent.ProcessCacheEntry.Pid, parent.ResolveEventTime()) + assert.Nil(t, resolver.entryCache[parent.ProcessCacheEntry.Pid]) + assert.Equal(t, 0, len(resolver.entryCache)) testCacheSize(t, resolver) } func TestFork2nd(t *testing.T) { - resolver, err := NewEBPFResolver(nil, nil, &statsd.NoOpClient{}, nil, nil, nil, nil, nil, nil, nil, nil, NewResolverOpts()) + + resolver, err := newResolver() if err != nil { - t.Fatal(err) + t.Fatal() } - parent := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 1, Tid: 1}) - parent.ForkTime = time.Now() - - child := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 2, Tid: 2}) - child.PPid = parent.Pid - child.ForkTime = time.Now() + parent := newFakeForkEvent(0, 3, 123, resolver) + child := newFakeForkEvent(3, 4, 123, resolver) // parent - resolver.AddForkEntry(parent, 0, nil) - assert.Equal(t, parent, resolver.entryCache[parent.Pid]) + resolver.AddForkEntry(parent, nil) + assert.Equal(t, parent.ProcessCacheEntry, resolver.entryCache[parent.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) assert.EqualValues(t, 1, resolver.cacheSize.Load()) // parent // \ child - resolver.AddForkEntry(child, 0, nil) - assert.Equal(t, child, resolver.entryCache[child.Pid]) + resolver.AddForkEntry(child, nil) + assert.Equal(t, child.ProcessCacheEntry, resolver.entryCache[child.ProcessCacheEntry.Pid]) assert.Equal(t, 2, len(resolver.entryCache)) - assert.Equal(t, parent, child.Ancestor) + assert.Equal(t, parent.ProcessCacheEntry, child.ProcessCacheEntry.Ancestor) assert.EqualValues(t, 2, resolver.cacheSize.Load()) // [parent] // \ child - resolver.DeleteEntry(parent.Pid, time.Now()) - assert.Nil(t, resolver.entryCache[parent.Pid]) + + exit(parent) + resolver.AddExitEntry(parent, nil) + resolver.DeleteEntry(parent.ProcessContext.Pid, parent.ResolveEventTime()) + assert.Nil(t, resolver.entryCache[parent.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) - assert.Equal(t, parent, child.Ancestor) + assert.Equal(t, parent.ProcessCacheEntry, child.ProcessCacheEntry.Ancestor) // nothing - resolver.DeleteEntry(child.Pid, time.Now()) - assert.Zero(t, len(resolver.entryCache)) + exit(child) + resolver.AddExitEntry(child, nil) + resolver.DeleteEntry(child.ProcessContext.Pid, child.ResolveEventTime()) + assert.Nil(t, resolver.entryCache[child.ProcessCacheEntry.Pid]) + assert.Equal(t, 0, len(resolver.entryCache)) testCacheSize(t, resolver) } func TestForkExec(t *testing.T) { - resolver, err := NewEBPFResolver(nil, nil, &statsd.NoOpClient{}, nil, nil, nil, nil, nil, nil, nil, nil, NewResolverOpts()) + resolver, err := newResolver() if err != nil { - t.Fatal(err) + t.Fatal() } - parent := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 1, Tid: 1}) - parent.ForkTime = time.Now() - - child := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 2, Tid: 2}) - child.PPid = parent.Pid - child.ForkTime = time.Now() - - exec := resolver.NewProcessCacheEntry(model.PIDContext{Pid: child.Pid, Tid: child.Pid}) - exec.PPid = child.PPid - exec.FileEvent.Inode = 123 - exec.ExecTime = time.Now() + parent := newFakeForkEvent(0, 3, 123, resolver) + child := newFakeForkEvent(3, 4, 123, resolver) + exec := newFakeExecEvent(3, 4, 456, resolver) // parent - resolver.AddForkEntry(parent, 0, nil) - assert.Equal(t, parent, resolver.entryCache[parent.Pid]) + resolver.AddForkEntry(parent, nil) + assert.Equal(t, parent.ProcessCacheEntry, resolver.entryCache[parent.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) assert.EqualValues(t, 1, resolver.cacheSize.Load()) // parent // \ child - resolver.AddForkEntry(child, 0, nil) - assert.Equal(t, child, resolver.entryCache[child.Pid]) + resolver.AddForkEntry(child, nil) + assert.Equal(t, child.ProcessCacheEntry, resolver.entryCache[child.ProcessCacheEntry.Pid]) assert.Equal(t, 2, len(resolver.entryCache)) - assert.Equal(t, parent, child.Ancestor) + assert.Equal(t, parent.ProcessCacheEntry, child.ProcessCacheEntry.Ancestor) assert.EqualValues(t, 2, resolver.cacheSize.Load()) // parent - // \ [child] -> exec - resolver.AddExecEntry(exec, 0) - assert.Equal(t, exec, resolver.entryCache[exec.Pid]) + // \ child -> exec + resolver.AddExecEntry(exec) + assert.Equal(t, exec.ProcessCacheEntry, resolver.entryCache[exec.ProcessCacheEntry.Pid]) assert.Equal(t, 2, len(resolver.entryCache)) - assert.Equal(t, child, exec.Ancestor) - assert.Equal(t, parent, exec.Ancestor.Ancestor) + assert.Equal(t, child.ProcessCacheEntry, exec.ProcessCacheEntry.Ancestor) + assert.Equal(t, parent.ProcessCacheEntry, exec.ProcessCacheEntry.Ancestor.Ancestor) assert.EqualValues(t, 3, resolver.cacheSize.Load()) // [parent] // \ [child] -> exec - resolver.DeleteEntry(parent.Pid, time.Now()) - assert.Nil(t, resolver.entryCache[parent.Pid]) + exit(parent) + resolver.AddExitEntry(parent, nil) + resolver.DeleteEntry(parent.ProcessContext.Pid, parent.ResolveEventTime()) + assert.Nil(t, resolver.entryCache[parent.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) - assert.Equal(t, child, exec.Ancestor) - assert.Equal(t, parent, exec.Ancestor.Ancestor) + assert.Equal(t, child.ProcessCacheEntry, exec.ProcessCacheEntry.Ancestor) + assert.Equal(t, parent.ProcessCacheEntry, exec.ProcessCacheEntry.Ancestor.Ancestor) // nothing - resolver.DeleteEntry(exec.Pid, time.Now()) + exit(child) + resolver.AddExitEntry(child, nil) + resolver.DeleteEntry(child.ProcessContext.Pid, child.ResolveEventTime()) assert.Zero(t, len(resolver.entryCache)) testCacheSize(t, resolver) } func TestOrphanExec(t *testing.T) { - resolver, err := NewEBPFResolver(nil, nil, &statsd.NoOpClient{}, nil, nil, nil, nil, nil, nil, nil, nil, NewResolverOpts()) + resolver, err := newResolver() if err != nil { - t.Fatal(err) + t.Fatal() } - parent := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 1, Tid: 1}) - parent.ForkTime = time.Now() - - child := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 2, Tid: 2}) - child.PPid = parent.Pid - child.ForkTime = time.Now() - - exec := resolver.NewProcessCacheEntry(model.PIDContext{Pid: child.Pid, Tid: child.Pid}) - exec.Pid = child.Pid - exec.PPid = child.PPid - exec.FileEvent.Inode = 123 - exec.ExecTime = time.Now() + parent := newFakeForkEvent(0, 3, 123, resolver) + child := newFakeForkEvent(3, 4, 123, resolver) + exec := newFakeExecEvent(3, 4, 456, resolver) // parent - resolver.AddForkEntry(parent, 0, nil) - assert.Equal(t, parent, resolver.entryCache[parent.Pid]) + resolver.AddForkEntry(parent, nil) + assert.Equal(t, parent.ProcessCacheEntry, resolver.entryCache[parent.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) assert.EqualValues(t, 1, resolver.cacheSize.Load()) // parent // \ child - resolver.AddForkEntry(child, 0, nil) - assert.Equal(t, child, resolver.entryCache[child.Pid]) + resolver.AddForkEntry(child, nil) + assert.Equal(t, child.ProcessCacheEntry, resolver.entryCache[child.ProcessCacheEntry.Pid]) assert.Equal(t, 2, len(resolver.entryCache)) - assert.Equal(t, parent, child.Ancestor) + assert.Equal(t, parent.ProcessCacheEntry, child.ProcessCacheEntry.Ancestor) assert.EqualValues(t, 2, resolver.cacheSize.Load()) // [parent] // \ child - resolver.DeleteEntry(parent.Pid, time.Now()) - assert.Nil(t, resolver.entryCache[parent.Pid]) + exit(parent) + resolver.AddExitEntry(parent, nil) + resolver.DeleteEntry(parent.ProcessContext.Pid, parent.ResolveEventTime()) + assert.Nil(t, resolver.entryCache[parent.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) - assert.Equal(t, parent, child.Ancestor) + assert.Equal(t, parent.ProcessCacheEntry, child.ProcessCacheEntry.Ancestor) // [parent] // \ [child] -> exec - resolver.AddExecEntry(exec, 0) - assert.Equal(t, exec, resolver.entryCache[exec.Pid]) + resolver.AddExecEntry(exec) + assert.Equal(t, exec.ProcessCacheEntry, resolver.entryCache[exec.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) - assert.Equal(t, child, exec.Ancestor) - assert.Equal(t, parent, exec.Ancestor.Ancestor) + assert.Equal(t, child.ProcessCacheEntry, exec.ProcessCacheEntry.Ancestor) + assert.Equal(t, parent.ProcessCacheEntry, exec.ProcessCacheEntry.Ancestor.Ancestor) assert.EqualValues(t, 3, resolver.cacheSize.Load()) // nothing - resolver.DeleteEntry(exec.Pid, time.Now()) + exit(exec) + resolver.AddExitEntry(exec, nil) + resolver.DeleteEntry(exec.ProcessCacheEntry.Pid, time.Now()) assert.Zero(t, len(resolver.entryCache)) testCacheSize(t, resolver) } func TestForkExecExec(t *testing.T) { - resolver, err := NewEBPFResolver(nil, nil, &statsd.NoOpClient{}, nil, nil, nil, nil, nil, nil, nil, nil, NewResolverOpts()) + resolver, err := newResolver() if err != nil { - t.Fatal(err) + t.Fatal() } - parent := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 1, Tid: 1}) - parent.ForkTime = time.Now() - - child := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 2, Tid: 2}) - child.PPid = parent.Pid - child.ForkTime = time.Now() - - exec1 := resolver.NewProcessCacheEntry(model.PIDContext{Pid: child.Pid, Tid: child.Pid}) - exec1.PPid = child.PPid - exec1.FileEvent.Inode = 123 - exec1.ExecTime = time.Now() - - exec2 := resolver.NewProcessCacheEntry(model.PIDContext{Pid: child.Pid, Tid: child.Pid}) - exec2.Pid = child.Pid - exec2.PPid = child.PPid - exec2.FileEvent.Inode = 456 - exec2.ExecTime = time.Now() + parent := newFakeForkEvent(0, 3, 123, resolver) + child := newFakeForkEvent(3, 4, 123, resolver) + exec1 := newFakeExecEvent(3, 4, 456, resolver) + exec2 := newFakeExecEvent(3, 4, 789, resolver) // parent - resolver.AddForkEntry(parent, 0, nil) - assert.Equal(t, parent, resolver.entryCache[parent.Pid]) + resolver.AddForkEntry(parent, nil) + assert.Equal(t, parent.ProcessCacheEntry, resolver.entryCache[parent.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) assert.EqualValues(t, 1, resolver.cacheSize.Load()) // parent // \ child - resolver.AddForkEntry(child, 0, nil) - assert.Equal(t, child, resolver.entryCache[child.Pid]) + resolver.AddForkEntry(child, nil) + assert.Equal(t, child.ProcessCacheEntry, resolver.entryCache[child.ProcessCacheEntry.Pid]) assert.Equal(t, 2, len(resolver.entryCache)) - assert.Equal(t, parent, child.Ancestor) + assert.Equal(t, parent.ProcessCacheEntry, child.ProcessCacheEntry.Ancestor) assert.EqualValues(t, 2, resolver.cacheSize.Load()) // [parent] // \ child - resolver.DeleteEntry(parent.Pid, time.Now()) - assert.Nil(t, resolver.entryCache[parent.Pid]) + exit(parent) + resolver.AddExitEntry(parent, nil) + resolver.DeleteEntry(parent.ProcessContext.Pid, parent.ResolveEventTime()) + assert.Nil(t, resolver.entryCache[parent.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) - assert.Equal(t, parent, child.Ancestor) + assert.Equal(t, parent.ProcessCacheEntry, child.ProcessCacheEntry.Ancestor) // [parent] // \ [child] -> exec1 - resolver.AddExecEntry(exec1, 0) - assert.Equal(t, exec1, resolver.entryCache[exec1.Pid]) + resolver.AddExecEntry(exec1) + assert.Equal(t, exec1.ProcessCacheEntry, resolver.entryCache[exec1.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) - assert.Equal(t, child, exec1.Ancestor) - assert.Equal(t, parent, exec1.Ancestor.Ancestor) + assert.Equal(t, child.ProcessCacheEntry, exec1.ProcessCacheEntry.Ancestor) + assert.Equal(t, parent.ProcessCacheEntry, exec1.ProcessCacheEntry.Ancestor.Ancestor) assert.EqualValues(t, 3, resolver.cacheSize.Load()) // [parent] - // \ [child] -> [exec1] -> exec2 - resolver.AddExecEntry(exec2, 0) - assert.Equal(t, exec2, resolver.entryCache[exec2.Pid]) + // \ [child] -> exec1 -> exec2 + resolver.AddExecEntry(exec2) + assert.Equal(t, exec2.ProcessCacheEntry, resolver.entryCache[exec2.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) - assert.Equal(t, exec1, exec2.Ancestor) - assert.Equal(t, child, exec2.Ancestor.Ancestor) - assert.Equal(t, parent, exec2.Ancestor.Ancestor.Ancestor) + assert.Equal(t, exec1.ProcessCacheEntry, exec2.ProcessCacheEntry.Ancestor) + assert.Equal(t, child.ProcessCacheEntry, exec2.ProcessCacheEntry.Ancestor.Ancestor) + assert.Equal(t, parent.ProcessCacheEntry, exec2.ProcessCacheEntry.Ancestor.Ancestor.Ancestor) assert.EqualValues(t, 4, resolver.cacheSize.Load()) // nothing - resolver.DeleteEntry(exec2.Pid, time.Now()) + exit(exec2) + resolver.AddExitEntry(exec2, nil) + resolver.DeleteEntry(exec1.ProcessCacheEntry.Pid, time.Now()) assert.Zero(t, len(resolver.entryCache)) testCacheSize(t, resolver) } func TestForkReuse(t *testing.T) { - resolver, err := NewEBPFResolver(nil, nil, &statsd.NoOpClient{}, nil, nil, nil, nil, nil, nil, nil, nil, NewResolverOpts()) + resolver, err := newResolver() if err != nil { - t.Fatal(err) + t.Fatal() } - parent1 := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 1, Tid: 1}) - parent1.ForkTime = time.Now() - - child1 := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 2, Tid: 2}) - child1.PPid = parent1.Pid - child1.ForkTime = time.Now() - - exec1 := resolver.NewProcessCacheEntry(model.PIDContext{Pid: child1.Pid, Tid: child1.Pid}) - exec1.PPid = child1.PPid - exec1.FileEvent.Inode = 123 - exec1.ExecTime = time.Now() - - parent2 := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 1, Tid: 1}) - parent2.ForkTime = time.Now() - - child2 := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 3, Tid: 3}) - child2.PPid = parent2.Pid - child2.ForkTime = time.Now() + parent1 := newFakeForkEvent(0, 3, 123, resolver) + child1 := newFakeForkEvent(3, 4, 123, resolver) + exec1 := newFakeExecEvent(3, 4, 456, resolver) + parent2 := newFakeForkEvent(0, 3, 123, resolver) + child2 := newFakeForkEvent(3, 5, 123, resolver) // parent1 - resolver.AddForkEntry(parent1, 0, nil) - assert.Equal(t, parent1, resolver.entryCache[parent1.Pid]) + resolver.AddForkEntry(parent1, nil) + assert.Equal(t, parent1.ProcessCacheEntry, resolver.entryCache[parent1.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) assert.EqualValues(t, 1, resolver.cacheSize.Load()) // parent1 // \ child1 - resolver.AddForkEntry(child1, 0, nil) - assert.Equal(t, child1, resolver.entryCache[child1.Pid]) + resolver.AddForkEntry(child1, nil) + assert.Equal(t, child1.ProcessCacheEntry, resolver.entryCache[child1.ProcessCacheEntry.Pid]) assert.Equal(t, 2, len(resolver.entryCache)) - assert.Equal(t, parent1, child1.Ancestor) + assert.Equal(t, parent1.ProcessCacheEntry, child1.ProcessCacheEntry.Ancestor) assert.EqualValues(t, 2, resolver.cacheSize.Load()) // [parent1] // \ child1 - resolver.DeleteEntry(parent1.Pid, time.Now()) - assert.Nil(t, resolver.entryCache[parent1.Pid]) + exit(parent1) + resolver.AddExitEntry(parent1, nil) + resolver.DeleteEntry(parent1.ProcessContext.Pid, parent1.ResolveEventTime()) + assert.Nil(t, resolver.entryCache[parent1.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) - assert.Equal(t, parent1, child1.Ancestor) + assert.Equal(t, parent1.ProcessCacheEntry, child1.ProcessCacheEntry.Ancestor) // [parent1] // \ [child1] -> exec1 - resolver.AddExecEntry(exec1, 0) - assert.Equal(t, exec1, resolver.entryCache[exec1.Pid]) + resolver.AddExecEntry(exec1) + assert.Equal(t, exec1.ProcessCacheEntry, resolver.entryCache[exec1.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) - assert.Equal(t, child1, exec1.Ancestor) - assert.Equal(t, parent1, exec1.Ancestor.Ancestor) + assert.Equal(t, child1.ProcessCacheEntry, exec1.ProcessCacheEntry.Ancestor) + assert.Equal(t, parent1.ProcessCacheEntry, exec1.ProcessCacheEntry.Ancestor.Ancestor) assert.EqualValues(t, 3, resolver.cacheSize.Load()) // [parent1:pid1] // \ [child1] -> exec1 // // parent2:pid1 - resolver.AddForkEntry(parent2, 0, nil) - assert.Equal(t, parent2, resolver.entryCache[parent2.Pid]) + resolver.AddForkEntry(parent2, nil) + assert.Equal(t, parent2.ProcessCacheEntry, resolver.entryCache[parent2.ProcessCacheEntry.Pid]) assert.Equal(t, 2, len(resolver.entryCache)) assert.EqualValues(t, 4, resolver.cacheSize.Load()) - // [parent1:pid1] + // // [parent1:pid1] // \ [child1] -> exec1 // // parent2:pid1 // \ child2 - resolver.AddForkEntry(child2, 0, nil) - assert.Equal(t, child2, resolver.entryCache[child2.Pid]) + resolver.AddForkEntry(child2, nil) + assert.Equal(t, child2.ProcessCacheEntry, resolver.entryCache[child2.ProcessCacheEntry.Pid]) assert.Equal(t, 3, len(resolver.entryCache)) - assert.Equal(t, parent2, child2.Ancestor) + assert.Equal(t, parent2.ProcessCacheEntry, child2.ProcessCacheEntry.Ancestor) assert.EqualValues(t, 5, resolver.cacheSize.Load()) // parent2:pid1 // \ child2 - resolver.DeleteEntry(exec1.Pid, time.Now()) - assert.Nil(t, resolver.entryCache[exec1.Pid]) + exit(exec1) + resolver.AddExitEntry(exec1, nil) + resolver.DeleteEntry(exec1.ProcessContext.Pid, exec1.ResolveEventTime()) + assert.Nil(t, resolver.entryCache[exec1.ProcessCacheEntry.Pid]) assert.Equal(t, 2, len(resolver.entryCache)) // [parent2:pid1] // \ child2 - resolver.DeleteEntry(parent2.Pid, time.Now()) - assert.Nil(t, resolver.entryCache[parent2.Pid]) + exit(parent2) + resolver.AddExitEntry(parent2, nil) + resolver.DeleteEntry(parent2.ProcessContext.Pid, parent2.ResolveEventTime()) + assert.Nil(t, resolver.entryCache[parent2.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) - assert.Equal(t, parent2, child2.Ancestor) + assert.Equal(t, parent2.ProcessCacheEntry, child2.ProcessCacheEntry.Ancestor) // nothing - resolver.DeleteEntry(child2.Pid, time.Now()) + exit(child2) + resolver.AddExitEntry(child2, nil) + resolver.DeleteEntry(child2.ProcessCacheEntry.Pid, child2.ResolveEventTime()) assert.Zero(t, len(resolver.entryCache)) testCacheSize(t, resolver) } func TestForkForkExec(t *testing.T) { - resolver, err := NewEBPFResolver(nil, nil, &statsd.NoOpClient{}, nil, nil, nil, nil, nil, nil, nil, nil, NewResolverOpts()) + resolver, err := newResolver() if err != nil { - t.Fatal(err) + t.Fatal() } - parent := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 1, Tid: 1}) - parent.ForkTime = time.Now() - - child := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 2, Tid: 2}) - child.PPid = parent.Pid - child.ForkTime = time.Now() - - grandChild := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 3, Tid: 3}) - grandChild.PPid = child.Pid - grandChild.ForkTime = time.Now() - - childExec := resolver.NewProcessCacheEntry(model.PIDContext{Pid: child.Pid, Tid: child.Pid}) - childExec.Pid = child.Pid - childExec.PPid = child.PPid - childExec.FileEvent.Inode = 123 - childExec.ExecTime = time.Now() + parent := newFakeForkEvent(0, 3, 123, resolver) + child := newFakeForkEvent(3, 4, 123, resolver) + grandChild := newFakeForkEvent(4, 5, 123, resolver) + childExec := newFakeExecEvent(3, 4, 456, resolver) // parent - resolver.AddForkEntry(parent, 0, nil) - assert.Equal(t, parent, resolver.entryCache[parent.Pid]) + resolver.AddForkEntry(parent, nil) + assert.Equal(t, parent.ProcessCacheEntry, resolver.entryCache[parent.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) // parent // \ child - resolver.AddForkEntry(child, 0, nil) - assert.Equal(t, child, resolver.entryCache[child.Pid]) + resolver.AddForkEntry(child, nil) + assert.Equal(t, child.ProcessCacheEntry, resolver.entryCache[child.ProcessCacheEntry.Pid]) assert.Equal(t, 2, len(resolver.entryCache)) - assert.Equal(t, parent, child.Ancestor) + assert.Equal(t, parent.ProcessCacheEntry, child.ProcessCacheEntry.Ancestor) // parent // \ child // \ grandChild - resolver.AddForkEntry(grandChild, 0, nil) - assert.Equal(t, grandChild, resolver.entryCache[grandChild.Pid]) + resolver.AddForkEntry(grandChild, nil) + assert.Equal(t, grandChild.ProcessCacheEntry, resolver.entryCache[grandChild.ProcessCacheEntry.Pid]) assert.Equal(t, 3, len(resolver.entryCache)) - assert.Equal(t, child, grandChild.Ancestor) - assert.Equal(t, parent, grandChild.Ancestor.Ancestor) + assert.Equal(t, child.ProcessCacheEntry, grandChild.ProcessCacheEntry.Ancestor) + assert.Equal(t, parent.ProcessCacheEntry, grandChild.ProcessCacheEntry.Ancestor.Ancestor) // parent // \ [child] -> childExec // \ grandChild - resolver.AddExecEntry(childExec, 0) - assert.Equal(t, childExec, resolver.entryCache[childExec.Pid]) + resolver.AddExecEntry(childExec) + assert.Equal(t, childExec.ProcessCacheEntry, resolver.entryCache[childExec.ProcessCacheEntry.Pid]) assert.Equal(t, 3, len(resolver.entryCache)) - assert.Equal(t, child, childExec.Ancestor) - assert.Equal(t, parent, childExec.Ancestor.Ancestor) - assert.Equal(t, child, grandChild.Ancestor) - assert.Equal(t, parent, grandChild.Ancestor.Ancestor) + assert.Equal(t, child.ProcessCacheEntry, childExec.ProcessCacheEntry.Ancestor) + assert.Equal(t, parent.ProcessCacheEntry, childExec.ProcessCacheEntry.Ancestor.Ancestor) + assert.Equal(t, child.ProcessCacheEntry, grandChild.ProcessCacheEntry.Ancestor) + assert.Equal(t, parent.ProcessCacheEntry, grandChild.ProcessCacheEntry.Ancestor.Ancestor) // [parent] // \ [child] -> childExec // \ grandChild - resolver.DeleteEntry(parent.Pid, time.Now()) - assert.Nil(t, resolver.entryCache[parent.Pid]) + exit(parent) + resolver.AddExitEntry(parent, nil) + resolver.DeleteEntry(parent.ProcessContext.Pid, parent.ResolveEventTime()) + assert.Nil(t, resolver.entryCache[parent.ProcessCacheEntry.Pid]) + assert.Nil(t, resolver.entryCache[parent.ProcessCacheEntry.Pid]) assert.Equal(t, 2, len(resolver.entryCache)) // [parent] // \ [child] // \ grandChild - resolver.DeleteEntry(childExec.Pid, time.Now()) - assert.Nil(t, resolver.entryCache[childExec.Pid]) + exit(childExec) + resolver.AddExitEntry(childExec, nil) + resolver.DeleteEntry(childExec.ProcessContext.Pid, childExec.ResolveEventTime()) + assert.Nil(t, resolver.entryCache[childExec.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) // nothing - resolver.DeleteEntry(grandChild.Pid, time.Now()) + exit(grandChild) + resolver.AddExitEntry(grandChild, nil) + resolver.DeleteEntry(grandChild.ProcessContext.Pid, grandChild.ResolveEventTime()) assert.Zero(t, len(resolver.entryCache)) testCacheSize(t, resolver) } func TestExecBomb(t *testing.T) { - resolver, err := NewEBPFResolver(nil, nil, &statsd.NoOpClient{}, nil, nil, nil, nil, nil, nil, nil, nil, NewResolverOpts()) + + resolver, err := newResolver() if err != nil { - t.Fatal(err) + t.Fatal() } - parent := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 1, Tid: 1}) - parent.ForkTime = time.Now() - - child := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 2, Tid: 2}) - child.PPid = parent.Pid - child.ForkTime = time.Now() - - exec1 := resolver.NewProcessCacheEntry(model.PIDContext{Pid: child.Pid, Tid: child.Pid}) - exec1.PPid = child.PPid - exec1.FileEvent.Inode = 123 - exec1.ExecTime = time.Now() - - exec2 := resolver.NewProcessCacheEntry(model.PIDContext{Pid: child.Pid, Tid: child.Pid}) - exec2.Pid = child.Pid - exec2.PPid = child.PPid - exec2.FileEvent.Inode = 123 - exec2.ExecTime = time.Now() + parent := newFakeForkEvent(0, 3, 123, resolver) + child := newFakeForkEvent(3, 4, 123, resolver) + exec1 := newFakeExecEvent(3, 4, 456, resolver) + exec2 := newFakeExecEvent(3, 4, 456, resolver) // parent - resolver.AddForkEntry(parent, 0, nil) - assert.Equal(t, parent, resolver.entryCache[parent.Pid]) + resolver.AddForkEntry(parent, nil) + assert.Equal(t, parent.ProcessCacheEntry, resolver.entryCache[parent.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) - assert.EqualValues(t, 1, resolver.cacheSize.Load()) // parent // \ child - resolver.AddForkEntry(child, 0, nil) - assert.Equal(t, child, resolver.entryCache[child.Pid]) + resolver.AddForkEntry(child, nil) + assert.Equal(t, child.ProcessCacheEntry, resolver.entryCache[child.ProcessCacheEntry.Pid]) assert.Equal(t, 2, len(resolver.entryCache)) - assert.Equal(t, parent, child.Ancestor) + assert.Equal(t, parent.ProcessCacheEntry, child.ProcessCacheEntry.Ancestor) assert.EqualValues(t, 2, resolver.cacheSize.Load()) // [parent] // \ child - resolver.DeleteEntry(parent.Pid, time.Now()) - assert.Nil(t, resolver.entryCache[parent.Pid]) + exit(parent) + resolver.AddExitEntry(parent, nil) + resolver.DeleteEntry(parent.ProcessContext.Pid, parent.ResolveEventTime()) + assert.Nil(t, resolver.entryCache[parent.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) - assert.Equal(t, parent, child.Ancestor) + assert.Equal(t, parent.ProcessCacheEntry, child.ProcessCacheEntry.Ancestor) // [parent] - // \ [child] -> exec1 - resolver.AddExecEntry(exec1, 0) - assert.Equal(t, exec1, resolver.entryCache[exec1.Pid]) + // \ [child] -> exec + resolver.AddExecEntry(exec1) + assert.Equal(t, exec1.ProcessCacheEntry, resolver.entryCache[exec1.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) - assert.Equal(t, child, exec1.Ancestor) - assert.Equal(t, parent, exec1.Ancestor.Ancestor) + assert.Equal(t, child.ProcessCacheEntry, exec1.ProcessCacheEntry.Ancestor) + assert.Equal(t, parent.ProcessCacheEntry, exec1.ProcessCacheEntry.Ancestor.Ancestor) assert.EqualValues(t, 3, resolver.cacheSize.Load()) // [parent] // \ [child] -> [exec1] -> exec2 - resolver.AddExecEntry(exec2, 0) - assert.Equal(t, exec1, resolver.entryCache[exec2.Pid]) + resolver.AddExecEntry(exec2) + assert.Equal(t, exec1.ProcessCacheEntry, resolver.entryCache[exec2.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) - assert.Equal(t, exec1.ExecTime, exec2.ExecTime) + assert.Equal(t, exec1.ProcessCacheEntry.ExecTime, exec2.ProcessCacheEntry.ExecTime) assert.EqualValues(t, 3, resolver.cacheSize.Load()) // nothing - resolver.DeleteEntry(exec1.Pid, time.Now()) + exit(exec1) + resolver.AddExitEntry(exec1, nil) + resolver.DeleteEntry(exec1.ProcessContext.Pid, exec1.ResolveEventTime()) assert.Zero(t, len(resolver.entryCache)) testCacheSize(t, resolver) } func TestExecLostFork(t *testing.T) { - resolver, err := NewEBPFResolver(nil, nil, &statsd.NoOpClient{}, nil, nil, nil, nil, nil, nil, nil, nil, NewResolverOpts()) + + resolver, err := newResolver() if err != nil { - t.Fatal(err) + t.Fatal() } - parent := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 11, Tid: 11}) - parent.FileEvent.BasenameStr = "agent" - parent.ForkTime = time.Now() - parent.FileEvent.Inode = 1 - parent.ExecInode = 1 + parent := newFakeForkEvent(0, 3, 123, resolver) + parent.ProcessCacheEntry.FileEvent.BasenameStr = "agent" + child := newFakeForkEvent(3, 4, 123, resolver) + child.PIDContext.ExecInode = 123 // ExecInode == Inode Parent + child1 := newFakeForkEvent(4, 5, 123, resolver) + child1.ProcessCacheEntry.FileEvent.BasenameStr = "sh" + child1.PIDContext.ExecInode = 456 // ExecInode != Inode parent // parent - resolver.AddForkEntry(parent, 0, nil) - - child := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 22, Tid: 22}) - child.PPid = parent.Pid - child.FileEvent.Inode = 1 + resolver.AddForkEntry(parent, nil) + assert.Equal(t, parent.ProcessCacheEntry, resolver.entryCache[parent.ProcessCacheEntry.Pid]) + assert.Equal(t, 1, len(resolver.entryCache)) // parent // \ child - resolver.AddForkEntry(child, parent.ExecInode, nil) - - assert.Equal(t, "agent", child.FileEvent.BasenameStr) - assert.False(t, child.IsParentMissing) - - // exec loss with inode 2 - - child1 := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 33, Tid: 33}) - child1.FileEvent.BasenameStr = "sh" - child1.PPid = child.Pid - child1.ExecInode = 2 + resolver.AddForkEntry(child, nil) + assert.Equal(t, child.ProcessCacheEntry, resolver.entryCache[child.ProcessCacheEntry.Pid]) + assert.Equal(t, 2, len(resolver.entryCache)) + assert.Equal(t, parent.ProcessCacheEntry, child.ProcessCacheEntry.Ancestor) + assert.Equal(t, "agent", child.ProcessCacheEntry.FileEvent.BasenameStr) + assert.False(t, child.ProcessCacheEntry.IsParentMissing) // parent // \ child // \ child1 - resolver.AddForkEntry(child1, child1.ExecInode, nil) - - assert.Equal(t, "agent", child1.FileEvent.BasenameStr) - assert.True(t, child1.IsParentMissing) + resolver.AddForkEntry(child1, nil) + assert.Equal(t, "agent", child1.ProcessCacheEntry.FileEvent.BasenameStr) + assert.True(t, child1.ProcessCacheEntry.IsParentMissing) } func TestExecLostExec(t *testing.T) { - resolver, err := NewEBPFResolver(nil, nil, &statsd.NoOpClient{}, nil, nil, nil, nil, nil, nil, nil, nil, NewResolverOpts()) + + resolver, err := newResolver() if err != nil { - t.Fatal(err) + t.Fatal() } - parent := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 11, Tid: 11}) - parent.FileEvent.BasenameStr = "agent" - parent.ForkTime = time.Now() - parent.FileEvent.Inode = 1 - parent.ExecInode = 1 + parent := newFakeForkEvent(0, 3, 123, resolver) + parent.ProcessCacheEntry.FileEvent.BasenameStr = "agent" + child1 := newFakeForkEvent(3, 4, 123, resolver) + child1.PIDContext.ExecInode = 123 // ExecInode == Inode Parent + child2 := newFakeExecEvent(3, 4, 456, resolver) + child2.ProcessCacheEntry.FileEvent.BasenameStr = "sh" + child2.PIDContext.ExecInode = 456 // ExecInode != Inode Ancestor // parent - resolver.AddForkEntry(parent, 0, nil) - - child1 := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 22, Tid: 22}) - child1.PPid = parent.Pid - child1.FileEvent.Inode = 1 - child1.ExecInode = 1 + resolver.AddForkEntry(parent, nil) + assert.Equal(t, parent.ProcessCacheEntry, resolver.entryCache[parent.ProcessCacheEntry.Pid]) + assert.Equal(t, 1, len(resolver.entryCache)) // parent // \ child1 - resolver.AddForkEntry(child1, parent.ExecInode, nil) - - assert.Equal(t, "agent", child1.FileEvent.BasenameStr) - assert.False(t, child1.IsParentMissing) - - // exec loss with inode 2 and pid 22 - - child2 := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 33, Tid: 33}) - child2.FileEvent.BasenameStr = "sh" - child2.PPid = child1.Pid - child2.ExecInode = 2 + resolver.AddForkEntry(child1, nil) + assert.Equal(t, child1.ProcessCacheEntry, resolver.entryCache[child1.ProcessCacheEntry.Pid]) + assert.Equal(t, 2, len(resolver.entryCache)) + assert.Equal(t, parent.ProcessCacheEntry, child1.ProcessCacheEntry.Ancestor) + assert.Equal(t, "agent", child1.ProcessCacheEntry.FileEvent.BasenameStr) + assert.False(t, child1.ProcessCacheEntry.IsParentMissing) // parent // \ child1 // \ child2 - resolver.AddForkEntry(child2, child2.ExecInode, nil) - - assert.Equal(t, "agent", child2.FileEvent.BasenameStr) - assert.True(t, child2.IsParentMissing) + resolver.AddForkEntry(child2, nil) + assert.Equal(t, "agent", child2.ProcessCacheEntry.FileEvent.BasenameStr) + assert.True(t, child2.ProcessCacheEntry.IsParentMissing) } func TestIsExecExecRuntime(t *testing.T) { - resolver, err := NewEBPFResolver(nil, nil, &statsd.NoOpClient{}, nil, nil, nil, nil, nil, nil, nil, nil, NewResolverOpts()) + resolver, err := newResolver() if err != nil { - t.Fatal(err) + t.Fatal() } - parent := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 1, Tid: 1}) - parent.ForkTime = time.Now() - parent.FileEvent.Inode = 1 + parent := newFakeForkEvent(0, 3, 123, resolver) + child := newFakeForkEvent(3, 4, 123, resolver) + child2 := newFakeExecEvent(3, 4, 456, resolver) + child3 := newFakeExecEvent(3, 4, 789, resolver) + child4 := newFakeExecEvent(3, 4, 101112, resolver) // parent - resolver.AddForkEntry(parent, 0, nil) - - child := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 2, Tid: 2}) - child.PPid = parent.Pid - child.FileEvent.Inode = 1 + resolver.AddForkEntry(parent, nil) + assert.Equal(t, parent.ProcessCacheEntry, resolver.entryCache[parent.ProcessCacheEntry.Pid]) + assert.Equal(t, 1, len(resolver.entryCache)) // parent // \ child - resolver.AddForkEntry(child, 0, nil) + resolver.AddForkEntry(child, nil) + assert.Equal(t, child.ProcessCacheEntry, resolver.entryCache[child.ProcessCacheEntry.Pid]) + assert.Equal(t, 2, len(resolver.entryCache)) + assert.Equal(t, parent.ProcessCacheEntry, child.ProcessCacheEntry.Ancestor) // parent // \ child // \ child2 - - child2 := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 2, Tid: 2}) - child2.FileEvent.Inode = 2 - child2.PPid = child.Pid - resolver.AddExecEntry(child2, 0) + resolver.AddExecEntry(child2) // parent // \ child // \ child2 // \ child3 + resolver.AddExecEntry(child3) - child3 := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 2, Tid: 2}) - child3.FileEvent.Inode = 3 - child3.PPid = child2.Pid - resolver.AddExecEntry(child3, 0) + // parent + // \ child + // \ child2 + // \ child3 + // \ child4 + resolver.AddExecEntry(child4) - assert.False(t, parent.IsExecExec) - assert.False(t, parent.IsExec) + assert.False(t, parent.ProcessCacheEntry.IsExecExec) + assert.False(t, parent.ProcessCacheEntry.IsExec) - assert.False(t, child.IsExecExec) - assert.False(t, child.IsExec) + assert.False(t, child.ProcessCacheEntry.IsExecExec) + assert.False(t, child.ProcessCacheEntry.IsExec) - assert.False(t, child2.IsExecExec) - assert.True(t, child2.IsExec) + assert.False(t, child2.ProcessCacheEntry.IsExecExec) + assert.True(t, child2.ProcessCacheEntry.IsExec) - assert.True(t, child3.IsExecExec) - assert.True(t, child3.IsExec) + assert.True(t, child3.ProcessCacheEntry.IsExecExec) + assert.True(t, child3.ProcessCacheEntry.IsExec) - child4 := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 2, Tid: 2}) - child4.FileEvent.Inode = 3 - child4.PPid = child3.Pid - resolver.AddExecEntry(child4, 0) + assert.True(t, child4.ProcessCacheEntry.IsExecExec) + assert.True(t, child4.ProcessCacheEntry.IsExec) - assert.True(t, child3.IsExecExec) - assert.True(t, child3.IsExec) } func TestIsExecExecSnapshot(t *testing.T) { - resolver, err := NewEBPFResolver(nil, nil, &statsd.NoOpClient{}, nil, nil, nil, nil, nil, nil, nil, nil, NewResolverOpts()) + + resolver, err := newResolver() if err != nil { - t.Fatal(err) + t.Fatal() } - parent := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 1, Tid: 1}) - parent.ForkTime = time.Now() - parent.FileEvent.Inode = 1 + parent := newFakeForkEvent(0, 3, 123, resolver) + child := newFakeForkEvent(3, 4, 123, resolver) + child2 := newFakeExecEvent(3, 4, 456, resolver) + child3 := newFakeExecEvent(3, 4, 769, resolver) // parent - resolver.insertEntry(parent, nil, model.ProcessCacheEntryFromSnapshot) - - child := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 2, Tid: 2}) - child.PPid = parent.Pid - child.FileEvent.Inode = 2 + resolver.insertEntry(parent.ProcessCacheEntry, nil, model.ProcessCacheEntryFromSnapshot) + assert.Equal(t, parent.ProcessCacheEntry, resolver.entryCache[parent.ProcessCacheEntry.Pid]) + assert.Equal(t, 1, len(resolver.entryCache)) // parent // \ child + resolver.setAncestor(child.ProcessCacheEntry) + resolver.insertEntry(child.ProcessCacheEntry, nil, model.ProcessCacheEntryFromSnapshot) + assert.Equal(t, child.ProcessCacheEntry, resolver.entryCache[child.ProcessCacheEntry.Pid]) + assert.Equal(t, 2, len(resolver.entryCache)) + assert.Equal(t, parent.ProcessCacheEntry, child.ProcessCacheEntry.Ancestor) - resolver.setAncestor(child) - resolver.insertEntry(child, nil, model.ProcessCacheEntryFromSnapshot) - - assert.False(t, parent.IsExecExec) - assert.False(t, parent.IsExec) + assert.False(t, parent.ProcessCacheEntry.IsExecExec) + assert.False(t, parent.ProcessCacheEntry.IsExec) - assert.False(t, child.IsExecExec) - assert.False(t, child.IsExec) + assert.False(t, child.ProcessCacheEntry.IsExecExec) + assert.False(t, child.ProcessCacheEntry.IsExec) // parent // \ child // \ child2 + resolver.AddExecEntry(child2) - child2 := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 2, Tid: 2}) - child2.FileEvent.Inode = 3 - child2.PPid = child.Pid - resolver.AddExecEntry(child2, 0) - - assert.False(t, child2.IsExecExec) - assert.True(t, child2.IsExec) + assert.False(t, child2.ProcessCacheEntry.IsExecExec) + assert.True(t, child2.ProcessCacheEntry.IsExec) - child3 := resolver.NewProcessCacheEntry(model.PIDContext{Pid: 2, Tid: 2}) - child3.FileEvent.Inode = 4 - child3.PPid = child2.Pid - resolver.AddExecEntry(child3, 0) + resolver.AddExecEntry(child3) - assert.True(t, child3.IsExecExec) - assert.True(t, child3.IsExec) + assert.True(t, child3.ProcessCacheEntry.IsExecExec) + assert.True(t, child3.ProcessCacheEntry.IsExec) } From ba1189477a48de26c72f0f153050c9e42475c459 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Momar=20TOUR=C3=89?= Date: Tue, 17 Dec 2024 15:54:57 +0100 Subject: [PATCH 2/6] use new ascii art --- pkg/security/probe/probe_ebpf.go | 2 +- .../resolvers/process/resolver_test.go | 275 ++++++++++-------- 2 files changed, 159 insertions(+), 118 deletions(-) diff --git a/pkg/security/probe/probe_ebpf.go b/pkg/security/probe/probe_ebpf.go index a75b3d3491e6a..7fb1f79751b67 100644 --- a/pkg/security/probe/probe_ebpf.go +++ b/pkg/security/probe/probe_ebpf.go @@ -720,7 +720,7 @@ func (p *EBPFProbe) setProcessContext(eventType model.EventType, event *model.Ev } } - // flush exited processpe + // flush exited process p.Resolvers.ProcessResolver.DequeueExited() return true diff --git a/pkg/security/resolvers/process/resolver_test.go b/pkg/security/resolvers/process/resolver_test.go index 6f3226ec534bd..4fff949db3a3a 100644 --- a/pkg/security/resolvers/process/resolver_test.go +++ b/pkg/security/resolvers/process/resolver_test.go @@ -101,21 +101,22 @@ func TestFork1st(t *testing.T) { parent := newFakeForkEvent(0, 3, 123, resolver) child := newFakeForkEvent(3, 4, 123, resolver) - // parent + // X(pid:3) resolver.AddForkEntry(parent, nil) assert.Equal(t, parent.ProcessCacheEntry, resolver.entryCache[parent.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) assert.EqualValues(t, 1, resolver.cacheSize.Load()) - // parent - // \ child + // X(pid:3) + // | + // X(pid:4) resolver.AddForkEntry(child, nil) assert.Equal(t, child.ProcessCacheEntry, resolver.entryCache[child.ProcessCacheEntry.Pid]) assert.Equal(t, 2, len(resolver.entryCache)) assert.Equal(t, parent.ProcessCacheEntry, child.ProcessCacheEntry.Ancestor) assert.EqualValues(t, 2, resolver.cacheSize.Load()) - // parent + // X(pid:3) exit(child) resolver.AddExitEntry(child, nil) resolver.DeleteEntry(child.ProcessCacheEntry.Pid, child.ResolveEventTime()) @@ -123,13 +124,12 @@ func TestFork1st(t *testing.T) { assert.Nil(t, resolver.entryCache[child.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) - // nothing + // nothing in the entryCache exit(parent) resolver.AddExitEntry(parent, nil) resolver.DeleteEntry(parent.ProcessCacheEntry.Pid, parent.ResolveEventTime()) assert.Nil(t, resolver.entryCache[parent.ProcessCacheEntry.Pid]) assert.Equal(t, 0, len(resolver.entryCache)) - testCacheSize(t, resolver) } @@ -143,23 +143,24 @@ func TestFork2nd(t *testing.T) { parent := newFakeForkEvent(0, 3, 123, resolver) child := newFakeForkEvent(3, 4, 123, resolver) - // parent + // X(pid:3) resolver.AddForkEntry(parent, nil) assert.Equal(t, parent.ProcessCacheEntry, resolver.entryCache[parent.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) assert.EqualValues(t, 1, resolver.cacheSize.Load()) - // parent - // \ child + // X(pid:3) + // | + // X(pid:4) resolver.AddForkEntry(child, nil) assert.Equal(t, child.ProcessCacheEntry, resolver.entryCache[child.ProcessCacheEntry.Pid]) assert.Equal(t, 2, len(resolver.entryCache)) assert.Equal(t, parent.ProcessCacheEntry, child.ProcessCacheEntry.Ancestor) assert.EqualValues(t, 2, resolver.cacheSize.Load()) - // [parent] - // \ child - + // [X(pid:3)] + // | + // X(pid:4) exit(parent) resolver.AddExitEntry(parent, nil) resolver.DeleteEntry(parent.ProcessContext.Pid, parent.ResolveEventTime()) @@ -167,7 +168,7 @@ func TestFork2nd(t *testing.T) { assert.Equal(t, 1, len(resolver.entryCache)) assert.Equal(t, parent.ProcessCacheEntry, child.ProcessCacheEntry.Ancestor) - // nothing + // nothing in the entryCache exit(child) resolver.AddExitEntry(child, nil) resolver.DeleteEntry(child.ProcessContext.Pid, child.ResolveEventTime()) @@ -187,22 +188,24 @@ func TestForkExec(t *testing.T) { child := newFakeForkEvent(3, 4, 123, resolver) exec := newFakeExecEvent(3, 4, 456, resolver) - // parent + // X(pid:3) resolver.AddForkEntry(parent, nil) assert.Equal(t, parent.ProcessCacheEntry, resolver.entryCache[parent.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) assert.EqualValues(t, 1, resolver.cacheSize.Load()) - // parent - // \ child + // X(pid:3) + // | + // X(pid:4) resolver.AddForkEntry(child, nil) assert.Equal(t, child.ProcessCacheEntry, resolver.entryCache[child.ProcessCacheEntry.Pid]) assert.Equal(t, 2, len(resolver.entryCache)) assert.Equal(t, parent.ProcessCacheEntry, child.ProcessCacheEntry.Ancestor) assert.EqualValues(t, 2, resolver.cacheSize.Load()) - // parent - // \ child -> exec + // X(pid:3) + // | + // X(pid:4) -- Y(pid:4) resolver.AddExecEntry(exec) assert.Equal(t, exec.ProcessCacheEntry, resolver.entryCache[exec.ProcessCacheEntry.Pid]) assert.Equal(t, 2, len(resolver.entryCache)) @@ -210,8 +213,9 @@ func TestForkExec(t *testing.T) { assert.Equal(t, parent.ProcessCacheEntry, exec.ProcessCacheEntry.Ancestor.Ancestor) assert.EqualValues(t, 3, resolver.cacheSize.Load()) - // [parent] - // \ [child] -> exec + // [X(pid:3)] + // | + // X(pid:4) -- Y(pid:4) exit(parent) resolver.AddExitEntry(parent, nil) resolver.DeleteEntry(parent.ProcessContext.Pid, parent.ResolveEventTime()) @@ -220,12 +224,11 @@ func TestForkExec(t *testing.T) { assert.Equal(t, child.ProcessCacheEntry, exec.ProcessCacheEntry.Ancestor) assert.Equal(t, parent.ProcessCacheEntry, exec.ProcessCacheEntry.Ancestor.Ancestor) - // nothing + // nothing in the entryCache exit(child) resolver.AddExitEntry(child, nil) resolver.DeleteEntry(child.ProcessContext.Pid, child.ResolveEventTime()) assert.Zero(t, len(resolver.entryCache)) - testCacheSize(t, resolver) } @@ -239,22 +242,24 @@ func TestOrphanExec(t *testing.T) { child := newFakeForkEvent(3, 4, 123, resolver) exec := newFakeExecEvent(3, 4, 456, resolver) - // parent + // X(pid:3) resolver.AddForkEntry(parent, nil) assert.Equal(t, parent.ProcessCacheEntry, resolver.entryCache[parent.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) assert.EqualValues(t, 1, resolver.cacheSize.Load()) - // parent - // \ child + // X(pid:3) + // | + // X(pid:4) resolver.AddForkEntry(child, nil) assert.Equal(t, child.ProcessCacheEntry, resolver.entryCache[child.ProcessCacheEntry.Pid]) assert.Equal(t, 2, len(resolver.entryCache)) assert.Equal(t, parent.ProcessCacheEntry, child.ProcessCacheEntry.Ancestor) assert.EqualValues(t, 2, resolver.cacheSize.Load()) - // [parent] - // \ child + // [X(pid:3)] + // | + // X(pid:4) exit(parent) resolver.AddExitEntry(parent, nil) resolver.DeleteEntry(parent.ProcessContext.Pid, parent.ResolveEventTime()) @@ -262,8 +267,9 @@ func TestOrphanExec(t *testing.T) { assert.Equal(t, 1, len(resolver.entryCache)) assert.Equal(t, parent.ProcessCacheEntry, child.ProcessCacheEntry.Ancestor) - // [parent] - // \ [child] -> exec + // [X(pid:3)] + // | + // X(pid:4) --> Y(pid:4) resolver.AddExecEntry(exec) assert.Equal(t, exec.ProcessCacheEntry, resolver.entryCache[exec.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) @@ -271,7 +277,7 @@ func TestOrphanExec(t *testing.T) { assert.Equal(t, parent.ProcessCacheEntry, exec.ProcessCacheEntry.Ancestor.Ancestor) assert.EqualValues(t, 3, resolver.cacheSize.Load()) - // nothing + // nothing in the entryCache exit(exec) resolver.AddExitEntry(exec, nil) resolver.DeleteEntry(exec.ProcessCacheEntry.Pid, time.Now()) @@ -291,22 +297,24 @@ func TestForkExecExec(t *testing.T) { exec1 := newFakeExecEvent(3, 4, 456, resolver) exec2 := newFakeExecEvent(3, 4, 789, resolver) - // parent + // X(pid:3) resolver.AddForkEntry(parent, nil) assert.Equal(t, parent.ProcessCacheEntry, resolver.entryCache[parent.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) assert.EqualValues(t, 1, resolver.cacheSize.Load()) - // parent - // \ child + // X(pid:3) + // | + // X(pid:4) resolver.AddForkEntry(child, nil) assert.Equal(t, child.ProcessCacheEntry, resolver.entryCache[child.ProcessCacheEntry.Pid]) assert.Equal(t, 2, len(resolver.entryCache)) assert.Equal(t, parent.ProcessCacheEntry, child.ProcessCacheEntry.Ancestor) assert.EqualValues(t, 2, resolver.cacheSize.Load()) - // [parent] - // \ child + // [X(pid:3)] + // | + // X(pid:4) exit(parent) resolver.AddExitEntry(parent, nil) resolver.DeleteEntry(parent.ProcessContext.Pid, parent.ResolveEventTime()) @@ -314,8 +322,9 @@ func TestForkExecExec(t *testing.T) { assert.Equal(t, 1, len(resolver.entryCache)) assert.Equal(t, parent.ProcessCacheEntry, child.ProcessCacheEntry.Ancestor) - // [parent] - // \ [child] -> exec1 + // [X(pid:3)] + // | + // X(pid:4) -- Y(pid:4) resolver.AddExecEntry(exec1) assert.Equal(t, exec1.ProcessCacheEntry, resolver.entryCache[exec1.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) @@ -323,8 +332,9 @@ func TestForkExecExec(t *testing.T) { assert.Equal(t, parent.ProcessCacheEntry, exec1.ProcessCacheEntry.Ancestor.Ancestor) assert.EqualValues(t, 3, resolver.cacheSize.Load()) - // [parent] - // \ [child] -> exec1 -> exec2 + // [X(pid:3)] + // | + // X(pid:4) -- Y(pid:4) -- Z(pid:4) resolver.AddExecEntry(exec2) assert.Equal(t, exec2.ProcessCacheEntry, resolver.entryCache[exec2.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) @@ -333,7 +343,7 @@ func TestForkExecExec(t *testing.T) { assert.Equal(t, parent.ProcessCacheEntry, exec2.ProcessCacheEntry.Ancestor.Ancestor.Ancestor) assert.EqualValues(t, 4, resolver.cacheSize.Load()) - // nothing + // nothing in the entryCache in the entryCache exit(exec2) resolver.AddExitEntry(exec2, nil) resolver.DeleteEntry(exec1.ProcessCacheEntry.Pid, time.Now()) @@ -354,22 +364,24 @@ func TestForkReuse(t *testing.T) { parent2 := newFakeForkEvent(0, 3, 123, resolver) child2 := newFakeForkEvent(3, 5, 123, resolver) - // parent1 + // X(pid:3) resolver.AddForkEntry(parent1, nil) assert.Equal(t, parent1.ProcessCacheEntry, resolver.entryCache[parent1.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) assert.EqualValues(t, 1, resolver.cacheSize.Load()) - // parent1 - // \ child1 + // X(pid:3) + // | + // X(pid:4) resolver.AddForkEntry(child1, nil) assert.Equal(t, child1.ProcessCacheEntry, resolver.entryCache[child1.ProcessCacheEntry.Pid]) assert.Equal(t, 2, len(resolver.entryCache)) assert.Equal(t, parent1.ProcessCacheEntry, child1.ProcessCacheEntry.Ancestor) assert.EqualValues(t, 2, resolver.cacheSize.Load()) - // [parent1] - // \ child1 + // [X(pid:3)] + // | + // X(pid:4) exit(parent1) resolver.AddExitEntry(parent1, nil) resolver.DeleteEntry(parent1.ProcessContext.Pid, parent1.ResolveEventTime()) @@ -377,8 +389,9 @@ func TestForkReuse(t *testing.T) { assert.Equal(t, 1, len(resolver.entryCache)) assert.Equal(t, parent1.ProcessCacheEntry, child1.ProcessCacheEntry.Ancestor) - // [parent1] - // \ [child1] -> exec1 + // [X(pid:3)] + // | + // X(pid:4) -- Y(pid:4) resolver.AddExecEntry(exec1) assert.Equal(t, exec1.ProcessCacheEntry, resolver.entryCache[exec1.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) @@ -386,36 +399,41 @@ func TestForkReuse(t *testing.T) { assert.Equal(t, parent1.ProcessCacheEntry, exec1.ProcessCacheEntry.Ancestor.Ancestor) assert.EqualValues(t, 3, resolver.cacheSize.Load()) - // [parent1:pid1] - // \ [child1] -> exec1 + // [X(pid:3)] + // | + // X(pid:4) -- Y(pid:4) // - // parent2:pid1 + // Z(pid:3) resolver.AddForkEntry(parent2, nil) assert.Equal(t, parent2.ProcessCacheEntry, resolver.entryCache[parent2.ProcessCacheEntry.Pid]) assert.Equal(t, 2, len(resolver.entryCache)) assert.EqualValues(t, 4, resolver.cacheSize.Load()) - // // [parent1:pid1] - // \ [child1] -> exec1 + // [X(pid:3)] + // | + // X(pid:4) -- Y(pid:4) // - // parent2:pid1 - // \ child2 + // Z(pid:3) + // | + // T(pid:5) resolver.AddForkEntry(child2, nil) assert.Equal(t, child2.ProcessCacheEntry, resolver.entryCache[child2.ProcessCacheEntry.Pid]) assert.Equal(t, 3, len(resolver.entryCache)) assert.Equal(t, parent2.ProcessCacheEntry, child2.ProcessCacheEntry.Ancestor) assert.EqualValues(t, 5, resolver.cacheSize.Load()) - // parent2:pid1 - // \ child2 + // Z(pid:3) + // | + // T(pid:5) exit(exec1) resolver.AddExitEntry(exec1, nil) resolver.DeleteEntry(exec1.ProcessContext.Pid, exec1.ResolveEventTime()) assert.Nil(t, resolver.entryCache[exec1.ProcessCacheEntry.Pid]) assert.Equal(t, 2, len(resolver.entryCache)) - // [parent2:pid1] - // \ child2 + // [Z(pid:3)] + // | + // T(pid:5) exit(parent2) resolver.AddExitEntry(parent2, nil) resolver.DeleteEntry(parent2.ProcessContext.Pid, parent2.ResolveEventTime()) @@ -423,7 +441,7 @@ func TestForkReuse(t *testing.T) { assert.Equal(t, 1, len(resolver.entryCache)) assert.Equal(t, parent2.ProcessCacheEntry, child2.ProcessCacheEntry.Ancestor) - // nothing + // nothing in the entryCache exit(child2) resolver.AddExitEntry(child2, nil) resolver.DeleteEntry(child2.ProcessCacheEntry.Pid, child2.ResolveEventTime()) @@ -443,30 +461,35 @@ func TestForkForkExec(t *testing.T) { grandChild := newFakeForkEvent(4, 5, 123, resolver) childExec := newFakeExecEvent(3, 4, 456, resolver) - // parent + // X(pid:3) resolver.AddForkEntry(parent, nil) assert.Equal(t, parent.ProcessCacheEntry, resolver.entryCache[parent.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) - // parent - // \ child + // X(pid:3) + // | + // X(pid:4) resolver.AddForkEntry(child, nil) assert.Equal(t, child.ProcessCacheEntry, resolver.entryCache[child.ProcessCacheEntry.Pid]) assert.Equal(t, 2, len(resolver.entryCache)) assert.Equal(t, parent.ProcessCacheEntry, child.ProcessCacheEntry.Ancestor) - // parent - // \ child - // \ grandChild + // X(pid:3) + // | + // X(pid:4) + // | + // X(pid:5) resolver.AddForkEntry(grandChild, nil) assert.Equal(t, grandChild.ProcessCacheEntry, resolver.entryCache[grandChild.ProcessCacheEntry.Pid]) assert.Equal(t, 3, len(resolver.entryCache)) assert.Equal(t, child.ProcessCacheEntry, grandChild.ProcessCacheEntry.Ancestor) assert.Equal(t, parent.ProcessCacheEntry, grandChild.ProcessCacheEntry.Ancestor.Ancestor) - // parent - // \ [child] -> childExec - // \ grandChild + // X(pid:3) + // | + // X(pid:4) -- Y(pid:4) + // | + // X(pid:5) resolver.AddExecEntry(childExec) assert.Equal(t, childExec.ProcessCacheEntry, resolver.entryCache[childExec.ProcessCacheEntry.Pid]) assert.Equal(t, 3, len(resolver.entryCache)) @@ -478,6 +501,12 @@ func TestForkForkExec(t *testing.T) { // [parent] // \ [child] -> childExec // \ grandChild + + // [X(pid:3)] + // | + // X(pid:4) -- Y(pid:4) + // | + // X(pid:5) exit(parent) resolver.AddExitEntry(parent, nil) resolver.DeleteEntry(parent.ProcessContext.Pid, parent.ResolveEventTime()) @@ -485,16 +514,18 @@ func TestForkForkExec(t *testing.T) { assert.Nil(t, resolver.entryCache[parent.ProcessCacheEntry.Pid]) assert.Equal(t, 2, len(resolver.entryCache)) - // [parent] - // \ [child] - // \ grandChild + // [X(pid:3)] + // | + // X(pid:4) + // | + // X(pid:5) exit(childExec) resolver.AddExitEntry(childExec, nil) resolver.DeleteEntry(childExec.ProcessContext.Pid, childExec.ResolveEventTime()) assert.Nil(t, resolver.entryCache[childExec.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) - // nothing + // nothing in the entryCache exit(grandChild) resolver.AddExitEntry(grandChild, nil) resolver.DeleteEntry(grandChild.ProcessContext.Pid, grandChild.ResolveEventTime()) @@ -515,21 +546,23 @@ func TestExecBomb(t *testing.T) { exec1 := newFakeExecEvent(3, 4, 456, resolver) exec2 := newFakeExecEvent(3, 4, 456, resolver) - // parent + // X(pid:3) resolver.AddForkEntry(parent, nil) assert.Equal(t, parent.ProcessCacheEntry, resolver.entryCache[parent.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) - // parent - // \ child + // X(pid:3) + // | + // X(pid:4) resolver.AddForkEntry(child, nil) assert.Equal(t, child.ProcessCacheEntry, resolver.entryCache[child.ProcessCacheEntry.Pid]) assert.Equal(t, 2, len(resolver.entryCache)) assert.Equal(t, parent.ProcessCacheEntry, child.ProcessCacheEntry.Ancestor) assert.EqualValues(t, 2, resolver.cacheSize.Load()) - // [parent] - // \ child + // [X(pid:3)] + // | + // X(pid:4) exit(parent) resolver.AddExitEntry(parent, nil) resolver.DeleteEntry(parent.ProcessContext.Pid, parent.ResolveEventTime()) @@ -537,8 +570,9 @@ func TestExecBomb(t *testing.T) { assert.Equal(t, 1, len(resolver.entryCache)) assert.Equal(t, parent.ProcessCacheEntry, child.ProcessCacheEntry.Ancestor) - // [parent] - // \ [child] -> exec + // [X(pid:3)] + // | + // X(pid:4) -- Y(pid:4) resolver.AddExecEntry(exec1) assert.Equal(t, exec1.ProcessCacheEntry, resolver.entryCache[exec1.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) @@ -546,15 +580,16 @@ func TestExecBomb(t *testing.T) { assert.Equal(t, parent.ProcessCacheEntry, exec1.ProcessCacheEntry.Ancestor.Ancestor) assert.EqualValues(t, 3, resolver.cacheSize.Load()) - // [parent] - // \ [child] -> [exec1] -> exec2 + // [X(pid:3)] + // | + // X(pid:4) -- Y(pid:4) -- Y(pid:4) resolver.AddExecEntry(exec2) assert.Equal(t, exec1.ProcessCacheEntry, resolver.entryCache[exec2.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) assert.Equal(t, exec1.ProcessCacheEntry.ExecTime, exec2.ProcessCacheEntry.ExecTime) assert.EqualValues(t, 3, resolver.cacheSize.Load()) - // nothing + // nothing in the entryCache exit(exec1) resolver.AddExitEntry(exec1, nil) resolver.DeleteEntry(exec1.ProcessContext.Pid, exec1.ResolveEventTime()) @@ -578,13 +613,14 @@ func TestExecLostFork(t *testing.T) { child1.ProcessCacheEntry.FileEvent.BasenameStr = "sh" child1.PIDContext.ExecInode = 456 // ExecInode != Inode parent - // parent + // X(pid:3) resolver.AddForkEntry(parent, nil) assert.Equal(t, parent.ProcessCacheEntry, resolver.entryCache[parent.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) - // parent - // \ child + // X(pid:3) + // | + // X(pid:4) resolver.AddForkEntry(child, nil) assert.Equal(t, child.ProcessCacheEntry, resolver.entryCache[child.ProcessCacheEntry.Pid]) assert.Equal(t, 2, len(resolver.entryCache)) @@ -592,9 +628,11 @@ func TestExecLostFork(t *testing.T) { assert.Equal(t, "agent", child.ProcessCacheEntry.FileEvent.BasenameStr) assert.False(t, child.ProcessCacheEntry.IsParentMissing) - // parent - // \ child - // \ child1 + // X(pid:3) + // | + // X(pid:4) + // {|} + // X(pid:5) resolver.AddForkEntry(child1, nil) assert.Equal(t, "agent", child1.ProcessCacheEntry.FileEvent.BasenameStr) assert.True(t, child1.ProcessCacheEntry.IsParentMissing) @@ -615,13 +653,14 @@ func TestExecLostExec(t *testing.T) { child2.ProcessCacheEntry.FileEvent.BasenameStr = "sh" child2.PIDContext.ExecInode = 456 // ExecInode != Inode Ancestor - // parent + // X(pid:3) resolver.AddForkEntry(parent, nil) assert.Equal(t, parent.ProcessCacheEntry, resolver.entryCache[parent.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) - // parent - // \ child1 + // X(pid:3) + // | + // X(pid:4) resolver.AddForkEntry(child1, nil) assert.Equal(t, child1.ProcessCacheEntry, resolver.entryCache[child1.ProcessCacheEntry.Pid]) assert.Equal(t, 2, len(resolver.entryCache)) @@ -629,11 +668,11 @@ func TestExecLostExec(t *testing.T) { assert.Equal(t, "agent", child1.ProcessCacheEntry.FileEvent.BasenameStr) assert.False(t, child1.ProcessCacheEntry.IsParentMissing) - // parent - // \ child1 - // \ child2 - resolver.AddForkEntry(child2, nil) - assert.Equal(t, "agent", child2.ProcessCacheEntry.FileEvent.BasenameStr) + // X(pid:3) + // | + // X(pid:4) -**- Y(pid:4) + resolver.AddExecEntry(child2) + assert.NotEqual(t, "agent", child2.ProcessCacheEntry.FileEvent.BasenameStr) assert.True(t, child2.ProcessCacheEntry.IsParentMissing) } @@ -649,34 +688,32 @@ func TestIsExecExecRuntime(t *testing.T) { child3 := newFakeExecEvent(3, 4, 789, resolver) child4 := newFakeExecEvent(3, 4, 101112, resolver) - // parent + // X(pid:3) resolver.AddForkEntry(parent, nil) assert.Equal(t, parent.ProcessCacheEntry, resolver.entryCache[parent.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) - // parent - // \ child + // X(pid:3) + // | + // X(pid:4) resolver.AddForkEntry(child, nil) assert.Equal(t, child.ProcessCacheEntry, resolver.entryCache[child.ProcessCacheEntry.Pid]) assert.Equal(t, 2, len(resolver.entryCache)) assert.Equal(t, parent.ProcessCacheEntry, child.ProcessCacheEntry.Ancestor) - // parent - // \ child - // \ child2 + // X(pid:3) + // | + // X(pid:4) -- Y(pid:4) resolver.AddExecEntry(child2) - // parent - // \ child - // \ child2 - // \ child3 + // X(pid:3) + // | + // X(pid:4) -- Y(pid:4) -- Z(pid:4) resolver.AddExecEntry(child3) - // parent - // \ child - // \ child2 - // \ child3 - // \ child4 + // X(pid:3) + // | + // X(pid:4) -- Y(pid:4) -- Z(pid:4) -- T(pid:4) resolver.AddExecEntry(child4) assert.False(t, parent.ProcessCacheEntry.IsExecExec) @@ -708,13 +745,14 @@ func TestIsExecExecSnapshot(t *testing.T) { child2 := newFakeExecEvent(3, 4, 456, resolver) child3 := newFakeExecEvent(3, 4, 769, resolver) - // parent + // X(pid:3) resolver.insertEntry(parent.ProcessCacheEntry, nil, model.ProcessCacheEntryFromSnapshot) assert.Equal(t, parent.ProcessCacheEntry, resolver.entryCache[parent.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) - // parent - // \ child + // X(pid:3) + // | + // X(pid:4) resolver.setAncestor(child.ProcessCacheEntry) resolver.insertEntry(child.ProcessCacheEntry, nil, model.ProcessCacheEntryFromSnapshot) assert.Equal(t, child.ProcessCacheEntry, resolver.entryCache[child.ProcessCacheEntry.Pid]) @@ -727,14 +765,17 @@ func TestIsExecExecSnapshot(t *testing.T) { assert.False(t, child.ProcessCacheEntry.IsExecExec) assert.False(t, child.ProcessCacheEntry.IsExec) - // parent - // \ child - // \ child2 + // X(pid:3) + // | + // X(pid:4) -- Y(pid:4) resolver.AddExecEntry(child2) assert.False(t, child2.ProcessCacheEntry.IsExecExec) assert.True(t, child2.ProcessCacheEntry.IsExec) + // X(pid:3) + // | + // X(pid:4) -- Y(pid:4) -- Z(pid:4) resolver.AddExecEntry(child3) assert.True(t, child3.ProcessCacheEntry.IsExecExec) From 7022e55e6b0f2849d4a22a74c8bc58bdf313fc81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Momar=20TOUR=C3=89?= Date: Wed, 18 Dec 2024 15:30:42 +0100 Subject: [PATCH 3/6] changes after review --- pkg/security/probe/probe_ebpf.go | 16 ++++---- .../resolvers/process/resolver_ebpf.go | 30 +++++++-------- .../resolvers/process/resolver_test.go | 38 +++++++++---------- 3 files changed, 41 insertions(+), 43 deletions(-) diff --git a/pkg/security/probe/probe_ebpf.go b/pkg/security/probe/probe_ebpf.go index 7fb1f79751b67..5e2adfc61a3fc 100644 --- a/pkg/security/probe/probe_ebpf.go +++ b/pkg/security/probe/probe_ebpf.go @@ -886,7 +886,10 @@ func (p *EBPFProbe) handleEvent(CPU int, data []byte) { return } - p.Resolvers.ProcessResolver.AddForkEntry(event, newEntryCb) + if err := p.Resolvers.ProcessResolver.AddForkEntry(event, newEntryCb); err != nil { + seclog.Errorf("failed to insert fork event: %s (pid %d, offset %d, len %d)", err, event.PIDContext.Pid, offset, len(data)) + return + } case model.ExecEventType: // unmarshal and fill event.processCacheEntry if _, err = p.unmarshalProcessCacheEntry(event, data[offset:]); err != nil { @@ -896,13 +899,8 @@ func (p *EBPFProbe) handleEvent(CPU int, data []byte) { err = p.Resolvers.ProcessResolver.AddExecEntry(event) if err != nil { - var errResolution *path.ErrPathResolution - if errors.As(err, &errResolution) { - event.SetPathResolutionError(&event.ProcessCacheEntry.FileEvent, err) - } else { - seclog.Errorf("failed to insert exec event: %s (offset %d, len %d)", err, offset, len(data)) - return - } + seclog.Errorf("failed to insert exec event: %s (pid %d, offset %d, len %d)", err, event.PIDContext.Pid, offset, len(data)) + return } } @@ -1015,7 +1013,7 @@ func (p *EBPFProbe) handleEvent(CPU int, data []byte) { seclog.Errorf("failed to decode exit event: %s (offset %d, len %d)", err, offset, len(data)) return } - exists := p.Resolvers.ProcessResolver.AddExitEntry(event, newEntryCb) + exists := p.Resolvers.ProcessResolver.ApplyExitEntry(event, newEntryCb) if !exists { p.Resolvers.MountResolver.DelPid(event.Exit.Pid) // update action reports diff --git a/pkg/security/resolvers/process/resolver_ebpf.go b/pkg/security/resolvers/process/resolver_ebpf.go index e517dc6549505..3d2ca3a0eba03 100644 --- a/pkg/security/resolvers/process/resolver_ebpf.go +++ b/pkg/security/resolvers/process/resolver_ebpf.go @@ -290,21 +290,21 @@ func (p *EBPFResolver) UpdateArgsEnvs(event *model.ArgsEnvsEvent) { } // AddForkEntry adds an entry to the local cache and returns the newly created entry -func (p *EBPFResolver) AddForkEntry(event *model.Event, newEntryCb func(*model.ProcessCacheEntry, error)) { - if IsKThread(event.ProcessCacheEntry.PPid, event.ProcessCacheEntry.Pid) { - return - } - +func (p *EBPFResolver) AddForkEntry(event *model.Event, newEntryCb func(*model.ProcessCacheEntry, error)) error { p.ApplyBootTime(event.ProcessCacheEntry) event.ProcessCacheEntry.SetSpan(event.SpanContext.SpanID, event.SpanContext.TraceID) if event.ProcessCacheEntry.Pid == 0 { - return + return errors.New("no pid") + } + if IsKThread(event.ProcessCacheEntry.PPid, event.ProcessCacheEntry.Pid) { + return errors.New("process is kthread") } p.Lock() defer p.Unlock() p.insertForkEntry(event.ProcessCacheEntry, event.PIDContext.ExecInode, model.ProcessCacheEntryFromEvent, newEntryCb) + return nil } // AddExecEntry adds an entry to the local cache and returns the newly created entry @@ -314,9 +314,13 @@ func (p *EBPFResolver) AddExecEntry(event *model.Event) error { return errors.New("no pid context") } - err := p.ResolveNewProcessCacheEntry(event.ProcessCacheEntry, event.ContainerContext) - if err != nil { - return err + if err := p.ResolveNewProcessCacheEntry(event.ProcessCacheEntry, event.ContainerContext); err != nil { + var errResolution *spath.ErrPathResolution + if errors.As(err, &errResolution) { + event.SetPathResolutionError(&event.ProcessCacheEntry.FileEvent, err) + } else { + return err + } } event.Exec.Process = &event.ProcessCacheEntry.Process @@ -327,8 +331,8 @@ func (p *EBPFResolver) AddExecEntry(event *model.Event) error { return nil } -// AddExitEntry delete entry from the local cache if present -func (p *EBPFResolver) AddExitEntry(event *model.Event, newEntryCb func(*model.ProcessCacheEntry, error)) bool { +// ApplyExitEntry delete entry from the local cache if present +func (p *EBPFResolver) ApplyExitEntry(event *model.Event, newEntryCb func(*model.ProcessCacheEntry, error)) bool { event.ProcessCacheEntry = p.resolve(event.PIDContext.Pid, event.PIDContext.Tid, event.PIDContext.ExecInode, false, newEntryCb) if event.ProcessCacheEntry == nil { // no need to dispatch an exit event that don't have the corresponding cache entry @@ -563,10 +567,6 @@ func (p *EBPFResolver) insertForkEntry(entry *model.ProcessCacheEntry, inode uin } if entry.Pid != 1 { parent := p.entryCache[entry.PPid] - if parent != nil { - fmt.Println(parent.FileEvent.Inode, inode) - } - if entry.PPid >= 1 && inode != 0 && (parent == nil || parent.FileEvent.Inode != inode) { if candidate := p.resolve(entry.PPid, entry.PPid, inode, true, newEntryCb); candidate != nil { parent = candidate diff --git a/pkg/security/resolvers/process/resolver_test.go b/pkg/security/resolvers/process/resolver_test.go index 4fff949db3a3a..16432e67338e1 100644 --- a/pkg/security/resolvers/process/resolver_test.go +++ b/pkg/security/resolvers/process/resolver_test.go @@ -118,7 +118,7 @@ func TestFork1st(t *testing.T) { // X(pid:3) exit(child) - resolver.AddExitEntry(child, nil) + resolver.ApplyExitEntry(child, nil) resolver.DeleteEntry(child.ProcessCacheEntry.Pid, child.ResolveEventTime()) assert.Nil(t, resolver.entryCache[child.ProcessCacheEntry.Pid]) @@ -126,7 +126,7 @@ func TestFork1st(t *testing.T) { // nothing in the entryCache exit(parent) - resolver.AddExitEntry(parent, nil) + resolver.ApplyExitEntry(parent, nil) resolver.DeleteEntry(parent.ProcessCacheEntry.Pid, parent.ResolveEventTime()) assert.Nil(t, resolver.entryCache[parent.ProcessCacheEntry.Pid]) assert.Equal(t, 0, len(resolver.entryCache)) @@ -162,7 +162,7 @@ func TestFork2nd(t *testing.T) { // | // X(pid:4) exit(parent) - resolver.AddExitEntry(parent, nil) + resolver.ApplyExitEntry(parent, nil) resolver.DeleteEntry(parent.ProcessContext.Pid, parent.ResolveEventTime()) assert.Nil(t, resolver.entryCache[parent.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) @@ -170,7 +170,7 @@ func TestFork2nd(t *testing.T) { // nothing in the entryCache exit(child) - resolver.AddExitEntry(child, nil) + resolver.ApplyExitEntry(child, nil) resolver.DeleteEntry(child.ProcessContext.Pid, child.ResolveEventTime()) assert.Nil(t, resolver.entryCache[child.ProcessCacheEntry.Pid]) assert.Equal(t, 0, len(resolver.entryCache)) @@ -217,7 +217,7 @@ func TestForkExec(t *testing.T) { // | // X(pid:4) -- Y(pid:4) exit(parent) - resolver.AddExitEntry(parent, nil) + resolver.ApplyExitEntry(parent, nil) resolver.DeleteEntry(parent.ProcessContext.Pid, parent.ResolveEventTime()) assert.Nil(t, resolver.entryCache[parent.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) @@ -226,7 +226,7 @@ func TestForkExec(t *testing.T) { // nothing in the entryCache exit(child) - resolver.AddExitEntry(child, nil) + resolver.ApplyExitEntry(child, nil) resolver.DeleteEntry(child.ProcessContext.Pid, child.ResolveEventTime()) assert.Zero(t, len(resolver.entryCache)) testCacheSize(t, resolver) @@ -261,7 +261,7 @@ func TestOrphanExec(t *testing.T) { // | // X(pid:4) exit(parent) - resolver.AddExitEntry(parent, nil) + resolver.ApplyExitEntry(parent, nil) resolver.DeleteEntry(parent.ProcessContext.Pid, parent.ResolveEventTime()) assert.Nil(t, resolver.entryCache[parent.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) @@ -279,7 +279,7 @@ func TestOrphanExec(t *testing.T) { // nothing in the entryCache exit(exec) - resolver.AddExitEntry(exec, nil) + resolver.ApplyExitEntry(exec, nil) resolver.DeleteEntry(exec.ProcessCacheEntry.Pid, time.Now()) assert.Zero(t, len(resolver.entryCache)) @@ -316,7 +316,7 @@ func TestForkExecExec(t *testing.T) { // | // X(pid:4) exit(parent) - resolver.AddExitEntry(parent, nil) + resolver.ApplyExitEntry(parent, nil) resolver.DeleteEntry(parent.ProcessContext.Pid, parent.ResolveEventTime()) assert.Nil(t, resolver.entryCache[parent.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) @@ -345,7 +345,7 @@ func TestForkExecExec(t *testing.T) { // nothing in the entryCache in the entryCache exit(exec2) - resolver.AddExitEntry(exec2, nil) + resolver.ApplyExitEntry(exec2, nil) resolver.DeleteEntry(exec1.ProcessCacheEntry.Pid, time.Now()) assert.Zero(t, len(resolver.entryCache)) @@ -383,7 +383,7 @@ func TestForkReuse(t *testing.T) { // | // X(pid:4) exit(parent1) - resolver.AddExitEntry(parent1, nil) + resolver.ApplyExitEntry(parent1, nil) resolver.DeleteEntry(parent1.ProcessContext.Pid, parent1.ResolveEventTime()) assert.Nil(t, resolver.entryCache[parent1.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) @@ -426,7 +426,7 @@ func TestForkReuse(t *testing.T) { // | // T(pid:5) exit(exec1) - resolver.AddExitEntry(exec1, nil) + resolver.ApplyExitEntry(exec1, nil) resolver.DeleteEntry(exec1.ProcessContext.Pid, exec1.ResolveEventTime()) assert.Nil(t, resolver.entryCache[exec1.ProcessCacheEntry.Pid]) assert.Equal(t, 2, len(resolver.entryCache)) @@ -435,7 +435,7 @@ func TestForkReuse(t *testing.T) { // | // T(pid:5) exit(parent2) - resolver.AddExitEntry(parent2, nil) + resolver.ApplyExitEntry(parent2, nil) resolver.DeleteEntry(parent2.ProcessContext.Pid, parent2.ResolveEventTime()) assert.Nil(t, resolver.entryCache[parent2.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) @@ -443,7 +443,7 @@ func TestForkReuse(t *testing.T) { // nothing in the entryCache exit(child2) - resolver.AddExitEntry(child2, nil) + resolver.ApplyExitEntry(child2, nil) resolver.DeleteEntry(child2.ProcessCacheEntry.Pid, child2.ResolveEventTime()) assert.Zero(t, len(resolver.entryCache)) @@ -508,7 +508,7 @@ func TestForkForkExec(t *testing.T) { // | // X(pid:5) exit(parent) - resolver.AddExitEntry(parent, nil) + resolver.ApplyExitEntry(parent, nil) resolver.DeleteEntry(parent.ProcessContext.Pid, parent.ResolveEventTime()) assert.Nil(t, resolver.entryCache[parent.ProcessCacheEntry.Pid]) assert.Nil(t, resolver.entryCache[parent.ProcessCacheEntry.Pid]) @@ -520,14 +520,14 @@ func TestForkForkExec(t *testing.T) { // | // X(pid:5) exit(childExec) - resolver.AddExitEntry(childExec, nil) + resolver.ApplyExitEntry(childExec, nil) resolver.DeleteEntry(childExec.ProcessContext.Pid, childExec.ResolveEventTime()) assert.Nil(t, resolver.entryCache[childExec.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) // nothing in the entryCache exit(grandChild) - resolver.AddExitEntry(grandChild, nil) + resolver.ApplyExitEntry(grandChild, nil) resolver.DeleteEntry(grandChild.ProcessContext.Pid, grandChild.ResolveEventTime()) assert.Zero(t, len(resolver.entryCache)) @@ -564,7 +564,7 @@ func TestExecBomb(t *testing.T) { // | // X(pid:4) exit(parent) - resolver.AddExitEntry(parent, nil) + resolver.ApplyExitEntry(parent, nil) resolver.DeleteEntry(parent.ProcessContext.Pid, parent.ResolveEventTime()) assert.Nil(t, resolver.entryCache[parent.ProcessCacheEntry.Pid]) assert.Equal(t, 1, len(resolver.entryCache)) @@ -591,7 +591,7 @@ func TestExecBomb(t *testing.T) { // nothing in the entryCache exit(exec1) - resolver.AddExitEntry(exec1, nil) + resolver.ApplyExitEntry(exec1, nil) resolver.DeleteEntry(exec1.ProcessContext.Pid, exec1.ResolveEventTime()) assert.Zero(t, len(resolver.entryCache)) From 2dfb01ed40ebc1db38ca8de19b38022f7a2c2052 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Momar=20TOUR=C3=89?= Date: Wed, 18 Dec 2024 16:39:18 +0100 Subject: [PATCH 4/6] fix --- pkg/security/probe/probe_ebpf.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/security/probe/probe_ebpf.go b/pkg/security/probe/probe_ebpf.go index 5e2adfc61a3fc..0d72287a1f1ce 100644 --- a/pkg/security/probe/probe_ebpf.go +++ b/pkg/security/probe/probe_ebpf.go @@ -1014,7 +1014,7 @@ func (p *EBPFProbe) handleEvent(CPU int, data []byte) { return } exists := p.Resolvers.ProcessResolver.ApplyExitEntry(event, newEntryCb) - if !exists { + if exists { p.Resolvers.MountResolver.DelPid(event.Exit.Pid) // update action reports p.processKiller.HandleProcessExited(event) From 56179e1b484c5cce988762f91b09550d7624cf62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Momar=20TOUR=C3=89?= Date: Thu, 19 Dec 2024 11:58:44 +0100 Subject: [PATCH 5/6] test --- .../resolvers/process/resolver_ebpf.go | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/pkg/security/resolvers/process/resolver_ebpf.go b/pkg/security/resolvers/process/resolver_ebpf.go index e877ca260bcb8..074fab6b649d7 100644 --- a/pkg/security/resolvers/process/resolver_ebpf.go +++ b/pkg/security/resolvers/process/resolver_ebpf.go @@ -309,26 +309,25 @@ func (p *EBPFResolver) AddForkEntry(event *model.Event, newEntryCb func(*model.P // AddExecEntry adds an entry to the local cache and returns the newly created entry func (p *EBPFResolver) AddExecEntry(event *model.Event) error { - - if event.ProcessCacheEntry.Pid == 0 { - return errors.New("no pid context") - } - + var err error if err := p.ResolveNewProcessCacheEntry(event.ProcessCacheEntry, event.ContainerContext); err != nil { var errResolution *spath.ErrPathResolution if errors.As(err, &errResolution) { event.SetPathResolutionError(&event.ProcessCacheEntry.FileEvent, err) - } else { - return err } + } else { + if event.ProcessCacheEntry.Pid == 0 { + return errors.New("no pid context") + } + + p.Lock() + defer p.Unlock() + p.insertExecEntry(event.ProcessCacheEntry, event.PIDContext.ExecInode, model.ProcessCacheEntryFromEvent) } event.Exec.Process = &event.ProcessCacheEntry.Process - p.Lock() - defer p.Unlock() - p.insertExecEntry(event.ProcessCacheEntry, event.PIDContext.ExecInode, model.ProcessCacheEntryFromEvent) - return nil + return err } // ApplyExitEntry delete entry from the local cache if present From 38d853dbd3fce7205163af4a67a70cc376a18dde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Momar=20TOUR=C3=89?= Date: Thu, 19 Dec 2024 13:12:01 +0100 Subject: [PATCH 6/6] done --- pkg/security/resolvers/process/resolver_ebpf.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/security/resolvers/process/resolver_ebpf.go b/pkg/security/resolvers/process/resolver_ebpf.go index 074fab6b649d7..dc704155b475e 100644 --- a/pkg/security/resolvers/process/resolver_ebpf.go +++ b/pkg/security/resolvers/process/resolver_ebpf.go @@ -309,6 +309,9 @@ func (p *EBPFResolver) AddForkEntry(event *model.Event, newEntryCb func(*model.P // AddExecEntry adds an entry to the local cache and returns the newly created entry func (p *EBPFResolver) AddExecEntry(event *model.Event) error { + p.Lock() + defer p.Unlock() + var err error if err := p.ResolveNewProcessCacheEntry(event.ProcessCacheEntry, event.ContainerContext); err != nil { var errResolution *spath.ErrPathResolution @@ -319,9 +322,6 @@ func (p *EBPFResolver) AddExecEntry(event *model.Event) error { if event.ProcessCacheEntry.Pid == 0 { return errors.New("no pid context") } - - p.Lock() - defer p.Unlock() p.insertExecEntry(event.ProcessCacheEntry, event.PIDContext.ExecInode, model.ProcessCacheEntryFromEvent) }