-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
process_cache_entry_unix.go
184 lines (152 loc) · 5.33 KB
/
process_cache_entry_unix.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2016-present Datadog, Inc.
//go:build unix
// Package model holds model related files
package model
import (
"time"
)
// SetAncestor sets the ancestor
func (pc *ProcessCacheEntry) SetAncestor(parent *ProcessCacheEntry) {
if pc.Ancestor == parent {
return
}
if pc.Ancestor != nil {
pc.Ancestor.Release()
}
pc.hasValidLineage = nil
pc.Ancestor = parent
pc.Parent = &parent.Process
parent.Retain()
}
func hasValidLineage(pc *ProcessCacheEntry) (bool, error) {
var (
pid, ppid uint32
ctrID string
err error
)
for pc != nil {
if pc.hasValidLineage != nil {
return *pc.hasValidLineage, pc.lineageError
}
pid, ppid, ctrID = pc.Pid, pc.PPid, pc.ContainerID
if pc.IsParentMissing {
err = &ErrProcessMissingParentNode{PID: pid, PPID: ppid, ContainerID: ctrID}
}
if pc.Pid == 1 {
if pc.Ancestor == nil {
return err == nil, err
}
return false, &ErrProcessWrongParentNode{PID: pid, PPID: pc.Ancestor.Pid, ContainerID: ctrID}
}
pc = pc.Ancestor
}
return false, &ErrProcessIncompleteLineage{PID: pid, PPID: ppid, ContainerID: ctrID}
}
// 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
func (pc *ProcessCacheEntry) HasValidLineage() (bool, error) {
res, err := hasValidLineage(pc)
pc.hasValidLineage, pc.lineageError = &res, err
return res, err
}
// Exit a process
func (pc *ProcessCacheEntry) Exit(exitTime time.Time) {
pc.ExitTime = exitTime
}
func copyProcessContext(parent, child *ProcessCacheEntry) {
// inherit the container ID from the parent if necessary. If a container is already running when system-probe
// starts, the in-kernel process cache will have out of sync container ID values for the processes of that
// container (the snapshot doesn't update the in-kernel cache with the container IDs). This can also happen if
// the proc_cache LRU ejects an entry.
// WARNING: this is why the user space cache should not be used to detect container breakouts. Dedicated
// in-kernel probes will need to be added.
if len(parent.ContainerID) > 0 && len(child.ContainerID) == 0 {
child.ContainerID = parent.ContainerID
}
}
// ApplyExecTimeOf replace previous entry values by the given one
func (pc *ProcessCacheEntry) ApplyExecTimeOf(entry *ProcessCacheEntry) {
pc.ExecTime = entry.ExecTime
}
// Exec replace a process
func (pc *ProcessCacheEntry) Exec(entry *ProcessCacheEntry) {
entry.SetAncestor(pc)
// use exec time as exit time
pc.Exit(entry.ExecTime)
entry.Process.IsExecExec = !pc.IsThread
// keep some context
copyProcessContext(pc, entry)
}
// GetContainerPIDs return the pids
func (pc *ProcessCacheEntry) GetContainerPIDs() []uint32 {
var pids []uint32
for pc != nil {
if pc.ContainerID == "" {
break
}
pids = append(pids, pc.Pid)
pc = pc.Ancestor
}
return pids
}
// SetParentOfForkChild set the parent of a fork child
func (pc *ProcessCacheEntry) SetParentOfForkChild(parent *ProcessCacheEntry) {
pc.SetAncestor(parent)
if parent != nil {
pc.ArgsEntry = parent.ArgsEntry
pc.EnvsEntry = parent.EnvsEntry
}
pc.IsThread = true
}
// Fork returns a copy of the current ProcessCacheEntry
func (pc *ProcessCacheEntry) Fork(childEntry *ProcessCacheEntry) {
childEntry.PPid = pc.Pid
childEntry.TTYName = pc.TTYName
childEntry.Comm = pc.Comm
childEntry.FileEvent = pc.FileEvent
childEntry.ContainerID = pc.ContainerID
childEntry.ExecTime = pc.ExecTime
childEntry.Credentials = pc.Credentials
childEntry.LinuxBinprm = pc.LinuxBinprm
childEntry.Cookie = pc.Cookie
childEntry.SetParentOfForkChild(pc)
}
// Equals returns whether process cache entries share the same values for file and args/envs
func (pc *ProcessCacheEntry) Equals(entry *ProcessCacheEntry) bool {
return (pc.FileEvent.Equals(&entry.FileEvent) &&
pc.Credentials.Equals(&entry.Credentials) &&
pc.ArgsEntry.Equals(entry.ArgsEntry) &&
pc.EnvsEntry.Equals(entry.EnvsEntry))
}
func (pc *ProcessCacheEntry) markFileEventAsResolved() {
// mark file path as resolved
pc.FileEvent.SetPathnameStr("")
pc.FileEvent.SetBasenameStr("")
// mark interpreter as resolved too
pc.LinuxBinprm.FileEvent.SetPathnameStr("")
pc.LinuxBinprm.FileEvent.SetBasenameStr("")
}
// NewPlaceholderProcessCacheEntry returns a new empty process cache entry for failed process resolutions
func NewPlaceholderProcessCacheEntry(pid uint32, tid uint32, isKworker bool) *ProcessCacheEntry {
entry := &ProcessCacheEntry{
ProcessContext: ProcessContext{
Process: Process{
PIDContext: PIDContext{Pid: pid, Tid: tid, IsKworker: isKworker},
Source: ProcessCacheEntryFromPlaceholder,
},
},
}
entry.markFileEventAsResolved()
return entry
}
var processContextZero = ProcessCacheEntry{ProcessContext: ProcessContext{Process: Process{Source: ProcessCacheEntryFromPlaceholder}}}
// GetPlaceholderProcessCacheEntry returns an empty process cache entry for failed process resolutions
func GetPlaceholderProcessCacheEntry(pid uint32, tid uint32, isKworker bool) *ProcessCacheEntry {
processContextZero.Pid = pid
processContextZero.Tid = tid
processContextZero.IsKworker = isKworker
processContextZero.markFileEventAsResolved()
return &processContextZero
}