From 017e55a0f8834618f6c3afc7385948b4f03d6ee8 Mon Sep 17 00:00:00 2001 From: Nikola Grcevski Date: Fri, 26 Jan 2024 12:03:23 -0500 Subject: [PATCH 1/2] Catch pids that are off a parent and not quite ready --- pkg/internal/discover/matcher.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pkg/internal/discover/matcher.go b/pkg/internal/discover/matcher.go index aed7ae38d..896236288 100644 --- a/pkg/internal/discover/matcher.go +++ b/pkg/internal/discover/matcher.go @@ -92,6 +92,17 @@ func (m *matcher) filterCreated(obj processAttrs) (Event[ProcessMatch], bool) { }, true } } + + // We didn't match the process, but let's see if the parent PID is tracked, it might be the child hasn't opened the port yet + if _, ok := m.processHistory[PID(proc.PPid)]; ok { + m.log.Debug("found process by matching the process parent id", "pid", proc.Pid, "ppid", proc.PPid, "comm", proc.ExePath, "metadata", obj.metadata) + m.processHistory[obj.pid] = proc + return Event[ProcessMatch]{ + Type: EventCreated, + Obj: ProcessMatch{Criteria: &m.criteria[0], Process: proc}, + }, true + } + return Event[ProcessMatch]{}, false } From 8a8f252cc23e18a26511bafbbbea1863a7c8a489 Mon Sep 17 00:00:00 2001 From: Nikola Grcevski Date: Fri, 26 Jan 2024 14:14:23 -0500 Subject: [PATCH 2/2] Add test --- pkg/internal/discover/matcher_test.go | 45 +++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/pkg/internal/discover/matcher_test.go b/pkg/internal/discover/matcher_test.go index ff3948fa4..5fdf8781d 100644 --- a/pkg/internal/discover/matcher_test.go +++ b/pkg/internal/discover/matcher_test.go @@ -133,3 +133,48 @@ func TestCriteriaMatcher_MustMatchAllAttributes(t *testing.T) { assert.Equal(t, "foons", m.Obj.Criteria.Namespace) assert.Equal(t, services.ProcessInfo{Pid: 1, ExePath: "/bin/foo", OpenPorts: []uint32{8081}}, *m.Obj.Process) } + +func TestCriteriaMatcherMissingPort(t *testing.T) { + pipeConfig := pipe.Config{} + require.NoError(t, yaml.Unmarshal([]byte(`discovery: + services: + - name: port-only + namespace: foo + open_ports: 80 +`), &pipeConfig)) + + matcherFunc, err := CriteriaMatcherProvider(CriteriaMatcher{Cfg: &pipeConfig}) + require.NoError(t, err) + discoveredProcesses := make(chan []Event[processAttrs], 10) + filteredProcesses := make(chan []Event[ProcessMatch], 10) + go matcherFunc(discoveredProcesses, filteredProcesses) + defer close(discoveredProcesses) + + // it will filter unmatching processes and return a ProcessMatch for these that match + processInfo = func(pp processAttrs) (*services.ProcessInfo, error) { + proc := map[PID]struct { + Exe string + PPid int32 + }{ + 1: {Exe: "/bin/weird33", PPid: 0}, 2: {Exe: "/bin/weird33", PPid: 16}, 3: {Exe: "/bin/weird33", PPid: 1}}[pp.pid] + return &services.ProcessInfo{Pid: int32(pp.pid), ExePath: proc.Exe, PPid: proc.PPid, OpenPorts: pp.openPorts}, nil + } + discoveredProcesses <- []Event[processAttrs]{ + {Type: EventCreated, Obj: processAttrs{pid: 1, openPorts: []uint32{80}}}, // this one is the parent, matches on port + {Type: EventDeleted, Obj: processAttrs{pid: 2, openPorts: []uint32{}}}, // we'll skip 2 since PPid is 16, not 1 + {Type: EventCreated, Obj: processAttrs{pid: 3, openPorts: []uint32{}}}, // this one is the child, without port, but matches the parent by port + } + + matches := testutil.ReadChannel(t, filteredProcesses, testTimeout) + require.Len(t, matches, 2) + m := matches[0] + assert.Equal(t, EventCreated, m.Type) + assert.Equal(t, "port-only", m.Obj.Criteria.Name) + assert.Equal(t, "foo", m.Obj.Criteria.Namespace) + assert.Equal(t, services.ProcessInfo{Pid: 1, ExePath: "/bin/weird33", OpenPorts: []uint32{80}, PPid: 0}, *m.Obj.Process) + m = matches[1] + assert.Equal(t, EventCreated, m.Type) + assert.Equal(t, "port-only", m.Obj.Criteria.Name) + assert.Equal(t, "foo", m.Obj.Criteria.Namespace) + assert.Equal(t, services.ProcessInfo{Pid: 3, ExePath: "/bin/weird33", OpenPorts: []uint32{}, PPid: 1}, *m.Obj.Process) +}