Skip to content

Commit

Permalink
fim(ebpf): enrich file events with process data
Browse files Browse the repository at this point in the history
  • Loading branch information
mmat11 committed Mar 6, 2024
1 parent ae312c5 commit 83d9ec6
Show file tree
Hide file tree
Showing 9 changed files with 363 additions and 18 deletions.
70 changes: 70 additions & 0 deletions auditbeat/docs/fields.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -18578,6 +18578,76 @@ type: keyword
--
[float]
=== process
These fields contains process and user information. Available only on Linux using the eBPF backend.
*`process.entity_id`*::
+
--
Globally unique identifier for a process.
type: keyword
--
*`process.executable`*::
+
--
Process command.
type: keyword
--
*`process.pid`*::
+
--
PID.
type: integer
--
*`process.user.id`*::
+
--
User ID (euid).
type: integer
--
*`process.user.name`*::
+
--
User name.
type: keyword
--
*`process.group.id`*::
+
--
Group ID (egid).
type: integer
--
*`process.group.name`*::
+
--
Group name.
type: keyword
--
[[exported-fields-host-processor]]
== Host fields
Expand Down
35 changes: 35 additions & 0 deletions auditbeat/module/file_integrity/_meta/fields.yml
Original file line number Diff line number Diff line change
Expand Up @@ -411,3 +411,38 @@
- name: xxh64
type: keyword
description: XX64 hash of the file.

- name: process
type: group
description: >
These fields contains process and user information.
Available only on Linux using the eBPF backend.
fields:
- name: entity_id
type: keyword
description: Globally unique identifier for a process.

- name: executable
type: keyword
description: Process command.

- name: pid
type: integer
description: PID.

- name: user.id
type: integer
description: User ID (euid).

- name: user.name
type: keyword
description: User name.

- name: group.id
type: integer
description: Group ID (egid).

- name: group.name
type: keyword
description: Group name.
29 changes: 29 additions & 0 deletions auditbeat/module/file_integrity/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,13 +134,42 @@ type Event struct {
Action Action `json:"action"` // Action (like created, updated).
Hashes map[HashType]Digest `json:"hash,omitempty"` // File hashes.
ParserResults mapstr.M `json:"file,omitempty"` // Results from running file parsers.
Process Process `json:"process,omitempty"` // Process data. Available only on Linux when using the eBPF backend.
// TODO(matt): ContainerID string `json:"container_id,omitempty"` // Unique container ID. Available only on Linux when using the eBPF backend.

// Metadata
rtt time.Duration // Time taken to collect the info.
errors []error // Errors that occurred while collecting the info.
hashFailed bool // Set when hashing the file failed.
}

// Process contain information about a process.
// These fields can help you correlate metrics information with a process id/name from a log message. The `process.pid` often stays in the metric itself and is copied to the global field for correlation.
type Process struct {
// Unique identifier for the process.
// The implementation of this is specified by the data source, but some examples of what could be used here are a process-generated UUID, Sysmon Process GUIDs, or a hash of some uniquely identifying components of a process.
// Constructing a globally unique identifier is a common practice to mitigate PID reuse as well as to identify a specific process over time, across multiple monitored hosts.
EntityID string `json:"entity_id,omitempty"`
// Process name. Sometimes called program name or similar.
Name string `json:"name,omitempty"`
// The effective user (euid).
User struct {
// Unique identifier of the user.
ID string `json:"id,omitempty"`
// Short name or login of the user.
Name string `json:"name,omitempty"`
} `json:"user,omitempty"`
// The effective group (egid).
Group struct {
// Unique identifier for the group on the system/platform.
ID string `json:"id,omitempty"`
// Name of the group.
Name string `json:"name,omitempty"`
} `json:"group,omitempty"`
// Process id.
PID uint32 `json:"pid,omitempty"`
}

// Metadata contains file metadata.
type Metadata struct {
Inode uint64 `json:"inode"`
Expand Down
90 changes: 85 additions & 5 deletions auditbeat/module/file_integrity/event_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"strconv"
"time"

"github.com/elastic/beats/v7/libbeat/ebpf/sys"
"github.com/elastic/ebpfevents"
)

Expand All @@ -41,7 +42,9 @@ func NewEventFromEbpfEvent(
path, target string
action Action
metadata Metadata
process Process
err error
errors = make([]error, 0)
)
switch ee.Type {
case ebpfevents.EventTypeFileCreate:
Expand All @@ -54,7 +57,16 @@ func NewEventFromEbpfEvent(
return event, false
}
target = fileCreateEvent.SymlinkTargetPath

metadata, err = metadataFromFileCreate(fileCreateEvent)
if err != nil {
errors = append(errors, err)
}

process, err = processFromFileCreate(fileCreateEvent)
if err != nil {
errors = append(errors, err)
}
case ebpfevents.EventTypeFileRename:
action = Moved

Expand All @@ -65,7 +77,16 @@ func NewEventFromEbpfEvent(
return event, false
}
target = fileRenameEvent.SymlinkTargetPath

metadata, err = metadataFromFileRename(fileRenameEvent)
if err != nil {
errors = append(errors, err)
}

process, err = processFromFileRename(fileRenameEvent)
if err != nil {
errors = append(errors, err)
}
case ebpfevents.EventTypeFileDelete:
action = Deleted

Expand All @@ -76,6 +97,11 @@ func NewEventFromEbpfEvent(
return event, false
}
target = fileDeleteEvent.SymlinkTargetPath

process, err = processFromFileDelete(fileDeleteEvent)
if err != nil {
errors = append(errors, err)
}
case ebpfevents.EventTypeFileModify:
fileModifyEvent := ee.Body.(*ebpfevents.FileModify)

Expand All @@ -92,7 +118,16 @@ func NewEventFromEbpfEvent(
return event, false
}
target = fileModifyEvent.SymlinkTargetPath

metadata, err = metadataFromFileModify(fileModifyEvent)
if err != nil {
errors = append(errors, err)
}

process, err = processFromFileModify(fileModifyEvent)
if err != nil {
errors = append(errors, err)
}
}

event := Event{
Expand All @@ -102,10 +137,8 @@ func NewEventFromEbpfEvent(
Info: &metadata,
Source: SourceEBPF,
Action: action,
errors: make([]error, 0),
}
if err != nil {
event.errors = append(event.errors, err)
Process: process,
errors: errors,
}

if event.Action == Deleted {
Expand All @@ -115,7 +148,6 @@ func NewEventFromEbpfEvent(
case FileType:
fillHashes(&event, path, maxFileSize, hashTypes, fileParsers)
case SymlinkType:
var err error
event.TargetPath, err = filepath.EvalSymlinks(event.Path)
if err != nil {
event.errors = append(event.errors, err)
Expand Down Expand Up @@ -147,6 +179,54 @@ func metadataFromFileModify(evt *ebpfevents.FileModify) (Metadata, error) {
return md, err
}

func newProcess(pid uint32, start uint64, comm string, euid, egid uint32) (Process, error) {
var (
p Process
err error
)

p.EntityID, err = sys.EntityID(pid, sys.TimeFromNsSinceBoot(start))
if err != nil {
return p, err
}
p.Name = comm
p.PID = pid

p.User.ID = strconv.FormatUint(uint64(euid), 10)
u, err := user.LookupId(p.User.ID)
if err == nil {
p.User.Name = u.Name
} else {
p.User.Name = "n/a"
}

p.Group.ID = strconv.FormatUint(uint64(egid), 10)
g, err := user.LookupId(p.Group.ID)
if err == nil {
p.Group.Name = g.Name
} else {
p.Group.Name = "n/a"
}

return p, err
}

func processFromFileCreate(evt *ebpfevents.FileCreate) (Process, error) {
return newProcess(evt.Pids.Tgid, evt.Pids.StartTimeNs, evt.Comm, evt.Creds.Euid, evt.Creds.Egid)
}

func processFromFileRename(evt *ebpfevents.FileRename) (Process, error) {
return newProcess(evt.Pids.Tgid, evt.Pids.StartTimeNs, evt.Comm, evt.Creds.Euid, evt.Creds.Egid)
}

func processFromFileModify(evt *ebpfevents.FileModify) (Process, error) {
return newProcess(evt.Pids.Tgid, evt.Pids.StartTimeNs, evt.Comm, evt.Creds.Euid, evt.Creds.Egid)
}

func processFromFileDelete(evt *ebpfevents.FileDelete) (Process, error) {
return newProcess(evt.Pids.Tgid, evt.Pids.StartTimeNs, evt.Comm, evt.Creds.Euid, evt.Creds.Egid)
}

func fillFileInfo(md *Metadata, finfo ebpfevents.FileInfo) error {
md.Inode = finfo.Inode
md.UID = finfo.Uid
Expand Down
2 changes: 1 addition & 1 deletion auditbeat/module/file_integrity/fields.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 6 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
module github.com/elastic/beats/v7

go 1.21
go 1.21.0

toolchain go1.22.0

require (
cloud.google.com/go/bigquery v1.55.0
Expand Down Expand Up @@ -200,7 +202,7 @@ require (
github.com/aws/smithy-go v1.13.5
github.com/awslabs/kinesis-aggregation/go/v2 v2.0.0-20220623125934-28468a6701b5
github.com/elastic/bayeux v1.0.5
github.com/elastic/ebpfevents v0.4.0
github.com/elastic/ebpfevents v0.5.0
github.com/elastic/elastic-agent-autodiscover v0.6.7
github.com/elastic/elastic-agent-libs v0.7.5
github.com/elastic/elastic-agent-shipper-client v0.5.1-0.20230228231646-f04347b666f3
Expand All @@ -223,6 +225,7 @@ require (
github.com/pkg/xattr v0.4.9
github.com/sergi/go-diff v1.3.1
github.com/shirou/gopsutil/v3 v3.22.10
github.com/tklauser/go-sysconf v0.3.10
go.elastic.co/apm/module/apmelasticsearch/v2 v2.4.8
go.elastic.co/apm/module/apmhttp/v2 v2.4.8
go.elastic.co/apm/v2 v2.4.8
Expand Down Expand Up @@ -270,7 +273,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.5 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash v1.1.0 // indirect
github.com/cilium/ebpf v0.12.3 // indirect
github.com/cilium/ebpf v0.13.2 // indirect
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
Expand Down Expand Up @@ -359,7 +362,6 @@ require (
github.com/sirupsen/logrus v1.9.0 // indirect
github.com/stoewer/go-strcase v1.2.0 // indirect
github.com/stretchr/objx v0.5.0 // indirect
github.com/tklauser/go-sysconf v0.3.10 // indirect
github.com/tklauser/numcpus v0.4.0 // indirect
github.com/urso/diag v0.0.0-20200210123136-21b3cc8eb797 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
Expand Down
Loading

0 comments on commit 83d9ec6

Please sign in to comment.