Skip to content

Commit 5f8f6df

Browse files
authored
[CWS] allow caching valid lineage result in whole pce tree (#44127)
### What does this PR do? When we check the validity of a process lineage, we currently cache the result of the top level pce we checked. This PR improves this system by making sure we cache the result for the whole tree of pces we looked at (that all have the same lineage validity by definition). ### Motivation ### Describe how you validated your changes ### Additional Notes Co-authored-by: paul.cacheux <paul.cacheux@datadoghq.com>
1 parent a009fab commit 5f8f6df

File tree

4 files changed

+41
-8
lines changed

4 files changed

+41
-8
lines changed

pkg/security/secl/model/errors.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ var ErrNoProcessContext = errors.New("process context not resolved")
8080
// ErrFailedDNSPacketDecoding defines a dns packet that failed to be decoded
8181
var ErrFailedDNSPacketDecoding = errors.New("dns packet couldn't be decoded")
8282

83+
// ErrCycleInProcessLineage is returned when a cycle is detected in the process lineage
84+
var ErrCycleInProcessLineage = errors.New("cycle detected in process lineage")
85+
8386
// ErrProcessBrokenLineage returned when a process lineage is broken
8487
type ErrProcessBrokenLineage struct {
8588
Err error

pkg/security/secl/model/model_unix.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -382,12 +382,16 @@ type Process struct {
382382
Source uint64 `field:"-"`
383383

384384
// lineage
385-
hasValidLineage *bool `field:"-"`
386-
lineageError error `field:"-"`
385+
validLineageResult *validLineageResult `field:"-"`
387386

388387
IsThroughSymLink bool `field:"-"` // Indicates whether the process is through a symlink
389388
}
390389

390+
type validLineageResult struct {
391+
valid bool
392+
err error
393+
}
394+
391395
// SetAncestorFields force the process cache entry to be valid
392396
func SetAncestorFields(pce *ProcessCacheEntry, subField string, _ interface{}) (bool, error) {
393397
if subField != "is_kworker" {

pkg/security/secl/model/process_cache_entry_unix.go

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,22 +26,23 @@ func (pc *ProcessCacheEntry) SetAncestor(parent *ProcessCacheEntry) {
2626
pc.Ancestor.Release()
2727
}
2828

29-
pc.hasValidLineage = nil
29+
pc.validLineageResult = nil
3030
pc.Ancestor = parent
3131
pc.Parent = &parent.Process
3232
parent.Retain()
3333
}
3434

35-
func hasValidLineage(pc *ProcessCacheEntry) (bool, error) {
35+
func hasValidLineage(pc *ProcessCacheEntry, result *validLineageResult) (bool, error) {
3636
var (
3737
pid, ppid uint32
3838
ctrID containerutils.ContainerID
3939
)
4040

4141
for pc != nil {
42-
if pc.hasValidLineage != nil {
43-
return *pc.hasValidLineage, pc.lineageError
42+
if pc.validLineageResult != nil {
43+
return pc.validLineageResult.valid, pc.validLineageResult.err
4444
}
45+
pc.validLineageResult = result
4546

4647
pid, ppid, ctrID = pc.Pid, pc.PPid, pc.ContainerContext.ContainerID
4748

@@ -63,8 +64,18 @@ func hasValidLineage(pc *ProcessCacheEntry) (bool, error) {
6364

6465
// HasValidLineage returns false if, from the entry, we cannot ascend the ancestors list to PID 1 or if a new is having a missing parent
6566
func (pc *ProcessCacheEntry) HasValidLineage() (bool, error) {
66-
res, err := hasValidLineage(pc)
67-
pc.hasValidLineage, pc.lineageError = &res, err
67+
vlres := &validLineageResult{
68+
valid: false,
69+
// if this error is returned, it means that we saw this cache entry in
70+
// an ancestor of the current pce, hence a cycle
71+
err: ErrCycleInProcessLineage,
72+
}
73+
74+
res, err := hasValidLineage(pc, vlres)
75+
76+
vlres.valid = res
77+
vlres.err = err
78+
6879
return res, err
6980
}
7081

pkg/security/secl/model/process_cache_entry_unix_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,21 @@ func TestHasValidLineage(t *testing.T) {
8282
var mn *ErrProcessMissingParentNode
8383
assert.ErrorAs(t, err, &mn)
8484
})
85+
86+
t.Run("cycle-detection", func(t *testing.T) {
87+
pid1 := newPCE(2, nil, false)
88+
child1 := newPCE(3, pid1, false)
89+
child2 := newPCE(4, child1, false)
90+
91+
// create cycle
92+
pid1.SetAncestor(child2)
93+
94+
isValid, err := child2.HasValidLineage()
95+
assert.False(t, isValid)
96+
assert.NotNil(t, err)
97+
98+
assert.ErrorIs(t, err, ErrCycleInProcessLineage)
99+
})
85100
}
86101

87102
func TestEntryEquals(t *testing.T) {

0 commit comments

Comments
 (0)