diff --git a/cmd/tracee-rules/output_test.go b/cmd/tracee-rules/output_test.go index f20a739b924f..43de5abb5e9d 100644 --- a/cmd/tracee-rules/output_test.go +++ b/cmd/tracee-rules/output_test.go @@ -255,7 +255,7 @@ func TestOutputTemplates(t *testing.T) { "a":123,"b":"c","d":true,"f":{"123":"456","foo":"bar"} }, "Context":{ - "timestamp":1321321,"processorId":0,"processId":21312,"threadId":0,"threadStartTime":0,"parentProcessId":0,"hostProcessId":0,"hostThreadId":0,"hostParentProcessId":0,"userId":0,"mountNamespace":0,"pidNamespace":0,"processName":"","hostName":"","cgroupId":0,"container":{"id":"abbc123"},"kubernetes":{},"eventId":"0","eventName":"execve","argsNum":0,"returnValue":0,"syscall":"execve","stackAddresses":null,"args":null,"contextFlags":{"containerStarted":true,"isCompat":false} + "timestamp":1321321,"processorId":0,"processId":21312,"threadId":0,"threadStartTime":0,"parentProcessId":0,"hostProcessId":0,"hostThreadId":0,"hostParentProcessId":0,"userId":0,"mountNamespace":0,"pidNamespace":0,"processName":"","hostName":"","cgroupId":0,"container":{"id":"abbc123"},"kubernetes":{},"eventId":"0","eventName":"execve","argsNum":0,"returnValue":0,"syscall":"execve","stackAddresses":null,"args":null,"contextFlags":{"containerStarted":true,"isCompat":false},"ancestors":null,"executedBinary":{"ctime":0,"device":0,"inode":0, "path":""} }, "SigMetadata":{ "ID":"TRC-1","EventName": "stdio","Version":"0.1.0","Name":"Standard Input/Output Over Socket","Description":"Redirection of process's standard input/output to socket","Tags":["linux","container"],"Properties":{"MITRE ATT\u0026CK":"Persistence: Server Software Component","Severity":3} diff --git a/pkg/ebpf/events_pipeline.go b/pkg/ebpf/events_pipeline.go index 2afb8a8f09ed..7fc0784466a8 100644 --- a/pkg/ebpf/events_pipeline.go +++ b/pkg/ebpf/events_pipeline.go @@ -49,6 +49,9 @@ func (t *Tracee) handleEvents(ctx context.Context) { eventsChan, errc = t.processTree.StartProcessingPipeline(ctx, eventsChan) errcList = append(errcList, errc) + eventsChan, errc = t.enrichProcess(ctx, eventsChan) + errcList = append(errcList, errc) + // Enrichment stage // In this stage container events are enriched with additional runtime data // Events may be enriched in the initial decode state if the enrichment data has been stored in the Containers structure @@ -558,6 +561,55 @@ func (t *Tracee) getStackAddresses(stackID uint32) ([]uint64, error) { return stackAddresses[0:stackCounter], nil } +func (t *Tracee) enrichProcess(ctx context.Context, in <-chan *trace.Event) (<-chan *trace.Event, <-chan error) { + out := make(chan *trace.Event) + errc := make(chan error, 1) + + go func() { + defer close(out) + defer close(errc) + + for { + select { + case event := <-in: + currentProcess, err := t.processTree.GetProcessInfo(event.HostProcessID, event.Timestamp) + if err != nil { + logger.Errorw("error enriching event with process info", "error", err) + } else { + event.ExecutedBinary = trace.BinaryInfo{ + Inode: currentProcess.ExecutionBinary.Inode, + Device: currentProcess.ExecutionBinary.Device, + Ctime: int(currentProcess.ExecutionBinary.Ctime), + Path: currentProcess.ExecutionBinary.Path, + } + + // Currently we only add parent information, as each new field we add increase the load significantly. + // We don't necessary have information on the parent process, so we do best effort. + parentProcess, err := t.processTree.GetProcessInfo(event.HostParentProcessID, event.Timestamp) + if err == nil { + parent := trace.Process{ + ID: parentProcess.InHostIDs.Pid, + Name: parentProcess.ProcessName, + Binary: trace.BinaryInfo{ + Inode: parentProcess.ExecutionBinary.Inode, + Device: parentProcess.ExecutionBinary.Device, + Ctime: int(parentProcess.ExecutionBinary.Ctime), + Path: parentProcess.ExecutionBinary.Path, + }, + } + event.Ancestors = append(event.Ancestors, parent) + } + } + out <- event + case <-ctx.Done(): + return + } + } + }() + + return out, errc +} + // WaitForPipeline waits for results from all error channels. func (t *Tracee) WaitForPipeline(errs ...<-chan error) error { errc := MergeErrors(errs...) diff --git a/pkg/ebpf/tracee.go b/pkg/ebpf/tracee.go index fa0f5b827689..94ca127ac1a3 100644 --- a/pkg/ebpf/tracee.go +++ b/pkg/ebpf/tracee.go @@ -222,9 +222,9 @@ func (t *Tracee) Stats() *metrics.Stats { func GetEssentialEventsList() map[events.ID]eventConfig { // Set essential events return map[events.ID]eventConfig{ - events.SchedProcessExec: {}, - events.SchedProcessExit: {}, - events.SchedProcessFork: {}, + events.SchedProcessExec: {submit: 0xFFFFFFFFFFFFFFFF}, + events.SchedProcessExit: {submit: 0xFFFFFFFFFFFFFFFF}, + events.SchedProcessFork: {submit: 0xFFFFFFFFFFFFFFFF}, events.CgroupMkdir: {submit: 0xFFFFFFFFFFFFFFFF}, events.CgroupRmdir: {submit: 0xFFFFFFFFFFFFFFFF}, } diff --git a/types/trace/trace.go b/types/trace/trace.go index ecf5988da80c..d756f1ad16ad 100644 --- a/types/trace/trace.go +++ b/types/trace/trace.go @@ -28,6 +28,7 @@ type Event struct { MountNS int `json:"mountNamespace"` PIDNS int `json:"pidNamespace"` ProcessName string `json:"processName"` + ExecutedBinary BinaryInfo `json:"executedBinary"` HostName string `json:"hostName"` Container Container `json:"container,omitempty"` Kubernetes Kubernetes `json:"kubernetes,omitempty"` @@ -40,6 +41,7 @@ type Event struct { Syscall string `json:"syscall"` StackAddresses []uint64 `json:"stackAddresses"` ContextFlags ContextFlags `json:"contextFlags"` + Ancestors []Process `json:"ancestors"` Args []Argument `json:"args"` // Arguments are ordered according their appearance in the original event Metadata *Metadata `json:"metadata,omitempty"` } @@ -72,6 +74,19 @@ type ContextFlags struct { IsCompat bool `json:"isCompat"` } +type BinaryInfo struct { + Inode uint `json:"inode"` + Device uint `json:"device"` + Ctime int `json:"ctime"` + Path string `json:"path"` +} + +type Process struct { + ID int `json:"id"` + Name string `json:"name"` + Binary BinaryInfo `json:"binary"` +} + // EventOrigin is where a trace.Event occured, it can either be from the host machine or from a container type EventOrigin string