Skip to content

Commit 0556dc1

Browse files
obtain process's parent hierarchy, checksums improvements
- Obtain the process's parent hierarchy. - Display the hierarchy on the pop-ups and the process dialog. - [pop-ups] Added a Detailed view with all the metadata of the process. - [cache-events] Improved the cache of processes. - [ruleseditor] Fixed enabling md5 checksum widget. Related: #413, #406
1 parent 7a04a53 commit 0556dc1

File tree

16 files changed

+1167
-878
lines changed

16 files changed

+1167
-878
lines changed

daemon/conman/connection.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ func newConnectionImpl(nfp *netfilter.Packet, c *Connection, protoType string) (
105105
} else if procmon.MethodIsAudit() {
106106
if aevent := audit.GetEventByPid(pid); aevent != nil {
107107
audit.Lock.RLock()
108-
c.Process = procmon.NewProcess(pid, aevent.ProcName)
108+
c.Process = procmon.NewProcessEmpty(pid, aevent.ProcName)
109109
c.Process.Path = aevent.ProcPath
110110
c.Process.ReadCmdline()
111111
c.Process.CWD = aevent.ProcDir
@@ -117,7 +117,7 @@ func newConnectionImpl(nfp *netfilter.Packet, c *Connection, protoType string) (
117117
c.Process.ReadEnv()
118118
c.Process.CleanPath()
119119

120-
procmon.EventsCache.Add(*c.Process)
120+
procmon.EventsCache.Add(c.Process)
121121
return c, nil
122122
}
123123
log.Debug("[auditd conn] PID not found via auditd, falling back to proc")
@@ -154,7 +154,7 @@ func newConnectionImpl(nfp *netfilter.Packet, c *Connection, protoType string) (
154154
if pid == os.Getpid() {
155155
// return a Process object with our PID, to be able to exclude our own connections
156156
// (to the UI on a local socket for example)
157-
c.Process = procmon.NewProcess(pid, "")
157+
c.Process = procmon.NewProcessEmpty(pid, "")
158158
return c, nil
159159
}
160160

@@ -334,5 +334,6 @@ func (c *Connection) Serialize() *protocol.Connection {
334334
ProcessEnv: c.Process.Env,
335335
ProcessCwd: c.Process.CWD,
336336
ProcessChecksums: c.Process.Checksums,
337+
ProcessTree: c.Process.Tree,
337338
}
338339
}

daemon/procmon/activepids.go

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,26 +30,22 @@ func MonitorProcEvents(stop <-chan struct{}) {
3030
if ev.IsExec() {
3131
// we don't receive the path of the process, therefore we need to discover it,
3232
// to check if the PID has replaced the PPID.
33-
proc := NewProcess(int(ev.PID), "")
34-
proc.GetInfo()
35-
proc.Parent = NewProcess(int(ev.TGID), "")
36-
proc.Parent.GetInfo()
33+
proc := NewProcessWithParent(int(ev.PID), int(ev.TGID), "")
3734

3835
log.Debug("[procmon exec event] %d, pid:%d tgid:%d %s, %s -> %s\n", ev.TimeStamp, ev.PID, ev.TGID, proc.Comm, proc.Path, proc.Parent.Path)
39-
//log.Debug("[procmon exec event] %d, pid:%d tgid:%d\n", ev.TimeStamp, ev.PID, ev.TGID)
40-
if _, needsHashUpdate, found := EventsCache.IsInStore(int(ev.PID), proc); found {
41-
// check if this PID has replaced the PPID:
42-
// systemd, pid:1234 -> curl, pid:1234 -> curl (i.e.: pid 1234) opens x.x.x.x:443
43-
// Without this, we would display that systemd is connecting to x.x.x.x:443
44-
// The previous pid+path will still exist as parent of the new child, in proc.Parent
45-
if needsHashUpdate {
46-
//log.Debug("[procmon inCache REPLACEMENT] rehashing, new: %d, %s -> inCache: %d -> %s", proc.ID, proc.Path, item.Proc.ID, item.Proc.Path)
36+
if _, needsUpdate, found := EventsCache.IsInStore(int(ev.PID), proc); found {
37+
if needsUpdate {
4738
EventsCache.ComputeChecksums(proc)
39+
EventsCache.UpdateItemDetails(proc)
4840
}
4941
log.Debug("[procmon exec event inCache] %d, pid:%d tgid:%d\n", ev.TimeStamp, ev.PID, ev.TGID)
5042
continue
5143
}
52-
EventsCache.Add(*proc)
44+
// adding item to cache in 2 steps:
45+
// 1. with basic information, to have it readily available
46+
// 2. getting the rest of the process details
47+
EventsCache.Add(proc)
48+
EventsCache.UpdateItemDetails(proc)
5349
} else if ev.IsExit() {
5450
p, _, found := EventsCache.IsInStore(int(ev.PID), nil)
5551
if found && p.Proc.IsAlive() == false {

daemon/procmon/cache_events.go

Lines changed: 47 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ type ProcessEvent struct {
3737

3838
// ExecEventItem represents an item of the cache
3939
type ExecEventItem struct {
40-
Proc Process
40+
sync.RWMutex
41+
Proc *Process
4142
LastSeen int64
4243
TTL int32
4344
}
@@ -56,7 +57,6 @@ type EventsStore struct {
5657
eventByPath map[string]*ExecEventItem
5758
checksums map[string]uint
5859
mu *sync.RWMutex
59-
hashed uint64
6060
checksumsEnabled bool
6161
}
6262

@@ -69,54 +69,50 @@ func NewEventsStore() *EventsStore {
6969

7070
return &EventsStore{
7171
mu: &sync.RWMutex{},
72-
checksums: make(map[string]uint),
73-
eventByPID: make(map[int]*ExecEventItem),
74-
eventByPath: make(map[string]*ExecEventItem),
72+
checksums: make(map[string]uint, 5000),
73+
eventByPID: make(map[int]*ExecEventItem, 5000),
74+
eventByPath: make(map[string]*ExecEventItem, 5000),
7575
}
7676
}
7777

7878
// Add adds a new process to cache.
7979
// If computing checksums is enabled, new checksums will be computed if needed,
8080
// or reused existing ones otherwise.
81-
func (e *EventsStore) Add(proc Process) {
81+
func (e *EventsStore) Add(proc *Process) {
8282
log.Debug("[cache] EventsStore.Add() %d, %s", proc.ID, proc.Path)
83+
// add the item to cache ASAP
84+
// then calculate the checksums if needed.
85+
e.UpdateItem(proc)
8386
if e.GetComputeChecksums() {
84-
e.ComputeChecksums(&proc)
87+
e.ComputeChecksums(proc)
88+
e.UpdateItem(proc)
8589
}
86-
87-
e.updateItem(&proc)
8890
}
8991

90-
func (e *EventsStore) updateItem(proc *Process) {
91-
log.Debug("[cache] updateItem() adding to events store (total: %d, hashed:%d), pid: %d, paths: %s", e.Len(), e.hashed, proc.ID, proc.Path)
92+
// UpdateItem updates a cache item
93+
func (e *EventsStore) UpdateItem(proc *Process) {
94+
log.Debug("[cache] updateItem() adding to events store (total: %d), pid: %d, paths: %s", e.Len(), proc.ID, proc.Path)
9295
if proc.Path == "" {
9396
return
9497
}
95-
96-
e.mu.Lock()
97-
defer e.mu.Unlock()
98-
9998
ev := &ExecEventItem{
100-
Proc: *proc,
99+
Proc: proc,
101100
LastSeen: time.Now().UnixNano(),
102101
}
102+
e.mu.Lock()
103103
e.eventByPID[proc.ID] = ev
104104
e.eventByPath[proc.Path] = ev
105+
e.mu.Unlock()
105106
}
106107

107108
// IsInStore checks if a PID is in the store.
108109
// If the PID is in cache, we may need to update it if the PID
109110
// is reusing the PID of the parent.
110-
func (e *EventsStore) IsInStore(key int, proc *Process) (item *ExecEventItem, needsHashUpdate bool, found bool) {
111-
//fmt.Printf("IsInStore()\n")
111+
func (e *EventsStore) IsInStore(key int, proc *Process) (item *ExecEventItem, needsUpdate bool, found bool) {
112112
item, found = e.IsInStoreByPID(key)
113113
if !found {
114114
return
115115
}
116-
/*if e.checksumsEnabled && len(item.Proc.Checksums) == 0 {
117-
log.Info("RECALCULATING STORED item: %s", item.Proc.Path)
118-
item.Proc.ComputeChecksums(e.checksums)
119-
}*/
120116
log.Debug("[cache] Event found by PID: %d, %s", key, item.Proc.Path)
121117

122118
// check if this PID has replaced the PPID:
@@ -126,9 +122,8 @@ func (e *EventsStore) IsInStore(key int, proc *Process) (item *ExecEventItem, ne
126122
// The previous pid+path will still exist as parent of the new child, in proc.Parent
127123
if proc != nil && proc.Path != "" && item.Proc.Path != proc.Path {
128124
log.Debug("[event inCache, replacement] new: %d, %s -> inCache: %d -> %s", proc.ID, proc.Path, item.Proc.ID, item.Proc.Path)
129-
//e.ComputeChecksums(proc)
130-
e.updateItem(proc)
131-
needsHashUpdate = true
125+
//e.UpdateItem(proc)
126+
needsUpdate = true
132127
}
133128

134129
return
@@ -137,19 +132,19 @@ func (e *EventsStore) IsInStore(key int, proc *Process) (item *ExecEventItem, ne
137132
// IsInStoreByPID checks if a pid exists in cache.
138133
func (e *EventsStore) IsInStoreByPID(key int) (item *ExecEventItem, found bool) {
139134
e.mu.RLock()
140-
defer e.mu.RUnlock()
141135
item, found = e.eventByPID[key]
136+
e.mu.RUnlock()
142137
return
143138
}
144139

145140
// IsInStoreByPath checks if a process exists in cache by path.
146141
func (e *EventsStore) IsInStoreByPath(path string) (item *ExecEventItem, found bool) {
147-
e.mu.RLock()
148-
defer e.mu.RUnlock()
149142
if path == "" || path == KernelConnection {
150143
return
151144
}
145+
e.mu.RLock()
152146
item, found = e.eventByPath[path]
147+
e.mu.RUnlock()
153148
if found {
154149
log.Debug("[cache] event found by path: %s", path)
155150
}
@@ -159,14 +154,14 @@ func (e *EventsStore) IsInStoreByPath(path string) (item *ExecEventItem, found b
159154
// Delete an item from cache
160155
func (e *EventsStore) Delete(key int) {
161156
e.mu.Lock()
162-
defer e.mu.Unlock()
163157
delete(e.eventByPID, key)
158+
e.mu.Unlock()
164159
}
165160

166161
// Len returns the number of items in cache.
167162
func (e *EventsStore) Len() int {
168163
e.mu.RLock()
169-
e.mu.RUnlock()
164+
defer e.mu.RUnlock()
170165
return len(e.eventByPID)
171166
}
172167

@@ -190,6 +185,14 @@ func (e *EventsStore) DeleteOldItems() {
190185
}
191186
}
192187

188+
func (e *EventsStore) UpdateItemDetails(proc *Process) {
189+
proc.GetParent()
190+
proc.GetTree()
191+
proc.ReadCwd()
192+
proc.ReadEnv()
193+
e.UpdateItem(proc)
194+
}
195+
193196
// -------------------------------------------------------------------------
194197
// TODO: Move to its own package.
195198
// A hashing service than runs in background, and accepts paths to hash
@@ -210,13 +213,12 @@ func (e *EventsStore) ComputeChecksums(proc *Process) {
210213
// and because of this sometimes we don't receive the event of the parent.
211214
item, _, found := e.IsInStore(proc.ID, proc)
212215
if !found {
213-
//log.Debug("cache.reuseChecksums() %d not inCache, %s", proc.ID, proc.Path)
216+
log.Debug("cache.reuseChecksums() %d not inCache, %s", proc.ID, proc.Path)
214217

215218
// if parent path and current path are equal, and the parent is alive, see if we have the hash of the parent path
216219
if !proc.IsChild() {
217-
log.Debug("[cache] reuseChecksums() pid not in cache, not child of parent: %d, %s - %d", proc.ID, proc.Path, proc.Starttime)
218220
proc.ComputeChecksums(e.checksums)
219-
e.hashed++
221+
log.Debug("[cache] reuseChecksums() pid not in cache, not child of parent: %d, %s - %d - %v", proc.ID, proc.Path, proc.Starttime, proc.Checksums)
220222
return
221223
}
222224

@@ -244,14 +246,16 @@ func (e *EventsStore) ComputeChecksums(proc *Process) {
244246
// pid found in cache
245247
// we should check other parameters to see if the pid is really the same process
246248
// proc/<pid>/maps
247-
if len(item.Proc.Checksums) > 0 && (item.Proc.IsAlive() && item.Proc.Path == proc.Path) {
248-
log.Debug("[cache] reuseChecksums() cached PID alive, already hashed:%v, %s new: %s", item.Proc.Checksums, item.Proc.Path, proc.Path)
249+
item.RLock()
250+
checksumsNum := len(item.Proc.Checksums)
251+
item.RUnlock()
252+
if checksumsNum > 0 && (item.Proc.IsAlive() && item.Proc.Path == proc.Path) {
253+
log.Debug("[cache] reuseChecksums() cached PID alive, already hashed: %v, %s new: %s", item.Proc.Checksums, item.Proc.Path, proc.Path)
249254
proc.Checksums = item.Proc.Checksums
250255
return
251256
}
252257
log.Debug("[cache] reuseChecksums() PID found inCache, computing hashes: %s new: %s - hashes: |%v<>%v|", item.Proc.Path, proc.Path, item.Proc.Checksums, proc.Checksums)
253258
proc.ComputeChecksums(e.checksums)
254-
e.hashed++
255259
}
256260

257261
// AddChecksumHash adds a new hash algorithm to compute checksums
@@ -270,10 +274,10 @@ func (e *EventsStore) DelChecksumHash(hash string) {
270274
e.mu.Unlock()
271275
}
272276

273-
// SetComputeChecksums configures if we compute checksums of processes
274-
// They can be disabled for example if there's no rule that requires checksums.
277+
// SetComputeChecksums configures if we compute checksums of processes.
278+
// They will be disabled if there's no rule that requires checksums.
275279
// When enabling this functionality, some already stored process may don't have
276-
// the checksums computed, so when enabling compute them.
280+
// the checksums computed yet, so when enabling compute them.
277281
func (e *EventsStore) SetComputeChecksums(compute bool) {
278282
e.mu.Lock()
279283
defer e.mu.Unlock()
@@ -293,7 +297,7 @@ func (e *EventsStore) SetComputeChecksums(compute bool) {
293297
}
294298
}
295299

296-
// DisableChecksums disables computing checksums functionality
300+
// DisableChecksums disables computing checksums functionality.
297301
func (e *EventsStore) DisableChecksums() {
298302
e.mu.Lock()
299303
defer e.mu.Unlock()
@@ -302,10 +306,10 @@ func (e *EventsStore) DisableChecksums() {
302306
}
303307

304308
// GetComputeChecksums returns if computing checksums is enabled or not.
305-
// Disabled -> if there're no rules with checksum field
309+
// Disabled -> if there're no rules with checksum field.
306310
// Disabled -> if events monitors are not available.
307-
// TODO: Disabled -> if there were n rules with checksums, but the user delete them, or
308-
// unchecked checksums.
311+
// Disabled -> if the user disables it globally.
312+
// TODO: Disabled -> if there were n rules with checksums, but the user delete them.
309313
func (e *EventsStore) GetComputeChecksums() bool {
310314
e.mu.RLock()
311315
defer e.mu.RUnlock()

0 commit comments

Comments
 (0)