From c5e150e9358b7609680c469e83c91f468b73a1a6 Mon Sep 17 00:00:00 2001 From: daemon1024 Date: Thu, 18 Jan 2024 23:24:13 +0530 Subject: [PATCH] fix(monitor): Missing Source in Telemetry We did not have fallback logic to read from procfs in case of operation File/Network Enabled the fallback logic for file/network telemetry Signed-off-by: daemon1024 --- KubeArmor/enforcer/bpflsm/enforcer.go | 2 +- KubeArmor/monitor/logUpdate.go | 30 ++++++++--------- KubeArmor/monitor/processTree.go | 48 +++++++++++++++++++++------ KubeArmor/monitor/systemMonitor.go | 8 ++--- 4 files changed, 56 insertions(+), 32 deletions(-) diff --git a/KubeArmor/enforcer/bpflsm/enforcer.go b/KubeArmor/enforcer/bpflsm/enforcer.go index ef7c91a779..69dea05639 100644 --- a/KubeArmor/enforcer/bpflsm/enforcer.go +++ b/KubeArmor/enforcer/bpflsm/enforcer.go @@ -311,7 +311,7 @@ func (be *BPFEnforcer) TraceEvents() { HostPID: event.HostPID, HostPPID: event.HostPPID, }, - }) + }, false) switch event.EventID { diff --git a/KubeArmor/monitor/logUpdate.go b/KubeArmor/monitor/logUpdate.go index 922df4cc24..8522f96125 100644 --- a/KubeArmor/monitor/logUpdate.go +++ b/KubeArmor/monitor/logUpdate.go @@ -49,7 +49,7 @@ func (mon *SystemMonitor) UpdateContainerInfoByContainerID(log tp.Log) tp.Log { } // BuildLogBase Function -func (mon *SystemMonitor) BuildLogBase(eventID int32, msg ContextCombined) tp.Log { +func (mon *SystemMonitor) BuildLogBase(eventID int32, msg ContextCombined, readlink bool) tp.Log { log := tp.Log{} timestamp, updatedTime := kl.GetDateTimeNow() @@ -78,41 +78,37 @@ func (mon *SystemMonitor) BuildLogBase(eventID int32, msg ContextCombined) tp.Lo log.PID = int32(msg.ContextSys.PID) log.UID = int32(msg.ContextSys.UID) + log.ProcessName = mon.GetExecPath(msg.ContainerID, msg.ContextSys, readlink) + log.ParentProcessName = mon.GetParentExecPath(msg.ContainerID, msg.ContextSys, readlink) + if msg.ContextSys.EventID == SysExecve || msg.ContextSys.EventID == SysExecveAt { - log.Source = mon.GetParentExecPath(msg.ContainerID, msg.ContextSys.HostPID, false) + log.Source = mon.GetParentExecPath(msg.ContainerID, msg.ContextSys, readlink) } else { - log.Source = mon.GetCommand(msg.ContainerID, msg.ContextSys.HostPID, false) + log.Source = mon.GetCommand(msg.ContainerID, msg.ContextSys, readlink) } log.Cwd = strings.TrimRight(string(msg.ContextSys.Cwd[:]), "\x00") + "/" log.OID = int32(msg.ContextSys.OID) - log.ParentProcessName = mon.GetExecPath(msg.ContainerID, msg.ContextSys.HostPPID, false) - log.ProcessName = mon.GetExecPath(msg.ContainerID, msg.ContextSys.HostPID, false) - return log } // UpdateLogBase Function (SYS_EXECVE, SYS_EXECVEAT) -func (mon *SystemMonitor) UpdateLogBase(eventID int32, log tp.Log) tp.Log { +func (mon *SystemMonitor) UpdateLogBase(ctx SyscallContext, log tp.Log) tp.Log { // update the process paths, since we would have received actual exec paths from bprm hook // in case bprm hook has not populated the map with full path, we will fallback to reading from procfs // else we will send out relative path - parentProcessName := mon.GetParentExecPath(log.ContainerID, uint32(log.HostPID), true) - if parentProcessName != "" { - log.ParentProcessName = parentProcessName - } - - processName := mon.GetExecPath(log.ContainerID, uint32(log.HostPID), true) + processName := mon.GetExecPath(log.ContainerID, ctx, true) if processName != "" { log.ProcessName = processName } - source := mon.GetExecPath(log.ContainerID, uint32(log.HostPPID), true) - if source != "" { - log.Source = source + parentProcessName := mon.GetParentExecPath(log.ContainerID, ctx, true) + if parentProcessName != "" { + log.ParentProcessName = parentProcessName + log.Source = parentProcessName } return log @@ -131,7 +127,7 @@ func (mon *SystemMonitor) UpdateLogs() { } // generate a log - log := mon.BuildLogBase(msg.ContextSys.EventID, msg) + log := mon.BuildLogBase(msg.ContextSys.EventID, msg, true) switch msg.ContextSys.EventID { case SysOpen: diff --git a/KubeArmor/monitor/processTree.go b/KubeArmor/monitor/processTree.go index 028e24e1d4..4565340327 100644 --- a/KubeArmor/monitor/processTree.go +++ b/KubeArmor/monitor/processTree.go @@ -136,7 +136,7 @@ func (mon *SystemMonitor) BuildPidNode(containerID string, ctx SyscallContext, e node.PID = ctx.PID node.UID = ctx.UID - node.ParentExecPath = mon.GetExecPath(containerID, ctx.HostPPID, false) + node.ParentExecPath = mon.GetParentExecPath(containerID, ctx, false) node.ExecPath = execPath node.Source = execPath @@ -204,7 +204,7 @@ func (mon *SystemMonitor) UpdateExecPath(containerID string, hostPid uint32, exe } // GetParentExecPath Function -func (mon *SystemMonitor) GetParentExecPath(containerID string, hostPid uint32, readlink bool) string { +func (mon *SystemMonitor) GetParentExecPath(containerID string, ctx SyscallContext, readlink bool) string { ActiveHostPidMap := *(mon.ActiveHostPidMap) ActivePidMapLock := *(mon.ActivePidMapLock) @@ -214,17 +214,35 @@ func (mon *SystemMonitor) GetParentExecPath(containerID string, hostPid uint32, path := "" if pidMap, ok := ActiveHostPidMap[containerID]; ok { - if node, ok := pidMap[hostPid]; ok { + if node, ok := pidMap[ctx.HostPID]; ok { path = node.ParentExecPath if path != "/" && strings.HasPrefix(path, "/") { return path } } + // check if parent pid node exists + if node, ok := pidMap[ctx.HostPPID]; ok { + path = node.ExecPath + if path != "/" && strings.HasPrefix(path, "/") { + return path + } + } } if readlink { // just in case that it couldn't still get the full path - if data, err := os.Readlink("/proc/" + strconv.FormatUint(uint64(hostPid), 10) + "/exe"); err == nil && data != "" && data != "/" { + if data, err := os.Readlink("/proc/" + strconv.FormatUint(uint64(ctx.HostPPID), 10) + "/exe"); err == nil && data != "" && data != "/" { + // // Store it in the ActiveHostPidMap so we don't need to read procfs again + // // We don't call BuildPidNode Here cause that will put this into a cyclic function call loop + // if pidMap, ok := ActiveHostPidMap[containerID]; ok { + // if node, ok := pidMap[ctx.HostPPID]; ok { + // node.ExecPath = data + // pidMap[ctx.HostPPID] = node + // } else if node, ok := pidMap[ctx.HostPID]; ok { + // node.ExecPath = data + // pidMap[ctx.HostPID] = node + // } + // } return data } else if err != nil { mon.Logger.Debugf("Could not read path from procfs due to %s", err.Error()) @@ -238,7 +256,7 @@ func (mon *SystemMonitor) GetParentExecPath(containerID string, hostPid uint32, } // GetExecPath Function -func (mon *SystemMonitor) GetExecPath(containerID string, hostPid uint32, readlink bool) string { +func (mon *SystemMonitor) GetExecPath(containerID string, ctx SyscallContext, readlink bool) string { ActiveHostPidMap := *(mon.ActiveHostPidMap) ActivePidMapLock := *(mon.ActivePidMapLock) @@ -248,7 +266,7 @@ func (mon *SystemMonitor) GetExecPath(containerID string, hostPid uint32, readli path := "" if pidMap, ok := ActiveHostPidMap[containerID]; ok { - if node, ok := pidMap[hostPid]; ok { + if node, ok := pidMap[ctx.HostPID]; ok { path = node.ExecPath if path != "/" && strings.HasPrefix(path, "/") { return path @@ -258,7 +276,17 @@ func (mon *SystemMonitor) GetExecPath(containerID string, hostPid uint32, readli if readlink { // just in case that it couldn't still get the full path - if data, err := os.Readlink("/proc/" + strconv.FormatUint(uint64(hostPid), 10) + "/exe"); err == nil && data != "" && data != "/" { + if data, err := os.Readlink("/proc/" + strconv.FormatUint(uint64(ctx.HostPID), 10) + "/exe"); err == nil && data != "" && data != "/" { + // // Store it in the ActiveHostPidMap so we don't need to read procfs again + // if pidMap, ok := ActiveHostPidMap[containerID]; ok { + // if node, ok := pidMap[ctx.HostPID]; ok { + // node.ExecPath = data + // pidMap[ctx.HostPID] = node + // } else { + // newPidNode := mon.BuildPidNode(containerID, ctx, data, []string{}) + // pidMap[ctx.HostPID] = newPidNode + // } + // } return data } else if err != nil { mon.Logger.Debugf("Could not read path from procfs due to %s", err.Error()) @@ -272,7 +300,7 @@ func (mon *SystemMonitor) GetExecPath(containerID string, hostPid uint32, readli } // GetCommand Function -func (mon *SystemMonitor) GetCommand(containerID string, hostPid uint32, readlink bool) string { +func (mon *SystemMonitor) GetCommand(containerID string, ctx SyscallContext, readlink bool) string { ActiveHostPidMap := *(mon.ActiveHostPidMap) ActivePidMapLock := *(mon.ActivePidMapLock) @@ -280,7 +308,7 @@ func (mon *SystemMonitor) GetCommand(containerID string, hostPid uint32, readlin defer ActivePidMapLock.Unlock() if pidMap, ok := ActiveHostPidMap[containerID]; ok { - if node, ok := pidMap[hostPid]; ok { + if node, ok := pidMap[ctx.HostPID]; ok { if node.Args != "" { return node.Source + " " + node.Args } @@ -290,7 +318,7 @@ func (mon *SystemMonitor) GetCommand(containerID string, hostPid uint32, readlin if readlink { // just in case that it couldn't still get the full path - if data, err := os.Readlink("/proc/" + strconv.FormatUint(uint64(hostPid), 10) + "/exe"); err == nil && data != "" && data != "/" { + if data, err := os.Readlink("/proc/" + strconv.FormatUint(uint64(ctx.HostPID), 10) + "/exe"); err == nil && data != "" && data != "/" { return data } else if err != nil { mon.Logger.Debugf("Could not read path from procfs due to %s", err.Error()) diff --git a/KubeArmor/monitor/systemMonitor.go b/KubeArmor/monitor/systemMonitor.go index f35a80cc0f..36b9c0f2c5 100644 --- a/KubeArmor/monitor/systemMonitor.go +++ b/KubeArmor/monitor/systemMonitor.go @@ -762,7 +762,7 @@ func (mon *SystemMonitor) TraceSyscall() { mon.AddActivePid(containerID, pidNode) // generate a log with the base information - log := mon.BuildLogBase(ctx.EventID, ContextCombined{ContainerID: containerID, ContextSys: ctx}) + log := mon.BuildLogBase(ctx.EventID, ContextCombined{ContainerID: containerID, ContextSys: ctx}, false) // add arguments log.Resource = execPath @@ -789,7 +789,7 @@ func (mon *SystemMonitor) TraceSyscall() { mon.execLogMapLock.Unlock() // update the log again - log = mon.UpdateLogBase(ctx.EventID, log) + log = mon.UpdateLogBase(ctx, log) // get error message if ctx.Retval < 0 { @@ -817,7 +817,7 @@ func (mon *SystemMonitor) TraceSyscall() { mon.AddActivePid(containerID, pidNode) // generate a log with the base information - log := mon.BuildLogBase(ctx.EventID, ContextCombined{ContainerID: containerID, ContextSys: ctx}) + log := mon.BuildLogBase(ctx.EventID, ContextCombined{ContainerID: containerID, ContextSys: ctx}, false) fd := "" procExecFlag := "" @@ -861,7 +861,7 @@ func (mon *SystemMonitor) TraceSyscall() { mon.execLogMapLock.Unlock() // update the log again - log = mon.UpdateLogBase(ctx.EventID, log) + log = mon.UpdateLogBase(ctx, log) // get error message if ctx.Retval < 0 {