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