diff --git a/CHANGELOG.next.asciidoc b/CHANGELOG.next.asciidoc index 37fc00bd926..5eda4571a92 100644 --- a/CHANGELOG.next.asciidoc +++ b/CHANGELOG.next.asciidoc @@ -208,7 +208,7 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff] *Libbeat* - +- Add support for linux capabilities in add_process_metadata. {pull}38252[38252] *Heartbeat* - Added status to monitor run log report. diff --git a/libbeat/processors/add_process_metadata/add_process_metadata.go b/libbeat/processors/add_process_metadata/add_process_metadata.go index 60a533a8e77..054d6d133e6 100644 --- a/libbeat/processors/add_process_metadata/add_process_metadata.go +++ b/libbeat/processors/add_process_metadata/add_process_metadata.go @@ -73,6 +73,7 @@ type processMetadata struct { env map[string]string startTime time.Time pid, ppid int + capEffective, capPermitted []string // fields mapstr.M } @@ -332,6 +333,12 @@ func (p *processMetadata) toMap() mapstr.M { } process["owner"] = user } + if len(p.capEffective) > 0 { + process.Put("thread.capabilities.effective", p.capEffective) + } + if len(p.capPermitted) > 0 { + process.Put("thread.capabilities.permitted", p.capPermitted) + } return mapstr.M{ "process": process, diff --git a/libbeat/processors/add_process_metadata/add_process_metadata_test.go b/libbeat/processors/add_process_metadata/add_process_metadata_test.go index 9dd1a7eb4dd..81816f1a87a 100644 --- a/libbeat/processors/add_process_metadata/add_process_metadata_test.go +++ b/libbeat/processors/add_process_metadata/add_process_metadata_test.go @@ -30,6 +30,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/elastic/beats/v7/libbeat/beat" + "github.com/elastic/beats/v7/libbeat/common/capabilities" conf "github.com/elastic/elastic-agent-libs/config" "github.com/elastic/elastic-agent-libs/logp" "github.com/elastic/elastic-agent-libs/mapstr" @@ -40,6 +41,10 @@ import ( func TestAddProcessMetadata(t *testing.T) { logp.TestingSetup(logp.WithSelectors(processorName)) + capMock, err := capabilities.FromUint64(0xabacabb) + if err != nil { + t.Fatalf("could not instantiate capabilities: %s", err) + } startTime := time.Now() testProcs := testProvider{ 1: { @@ -53,11 +58,13 @@ func TestAddProcessMetadata(t *testing.T) { "BOOT_IMAGE": "/boot/vmlinuz-4.11.8-300.fc26.x86_64", "LANG": "en_US.UTF-8", }, - pid: 1, - ppid: 0, - startTime: startTime, - username: "root", - userid: "0", + pid: 1, + ppid: 0, + startTime: startTime, + username: "root", + userid: "0", + capEffective: capMock, + capPermitted: capMock, }, 3: { name: "systemd", @@ -70,11 +77,13 @@ func TestAddProcessMetadata(t *testing.T) { "BOOT_IMAGE": "/boot/vmlinuz-4.11.8-300.fc26.x86_64", "LANG": "en_US.UTF-8", }, - pid: 1, - ppid: 0, - startTime: startTime, - username: "user", - userid: "1001", + pid: 1, + ppid: 0, + startTime: startTime, + username: "user", + userid: "1001", + capEffective: capMock, + capPermitted: capMock, }, } @@ -162,6 +171,12 @@ func TestAddProcessMetadata(t *testing.T) { "name": "root", "id": "0", }, + "thread": mapstr.M{ + "capabilities": mapstr.M{ + "effective": capMock, + "permitted": capMock, + }, + }, }, "container": mapstr.M{ "id": "b5285682fba7449c86452b89a800609440ecc88a7ba5f2d38bedfb85409b30b1", @@ -247,6 +262,12 @@ func TestAddProcessMetadata(t *testing.T) { "name": "root", "id": "0", }, + "thread": mapstr.M{ + "capabilities": mapstr.M{ + "effective": capMock, + "permitted": capMock, + }, + }, }, "container": mapstr.M{ "id": "b5285682fba7449c86452b89a800609440ecc88a7ba5f2d38bedfb85409b30b1", @@ -287,6 +308,12 @@ func TestAddProcessMetadata(t *testing.T) { "name": "root", "id": "0", }, + "thread": mapstr.M{ + "capabilities": mapstr.M{ + "effective": capMock, + "permitted": capMock, + }, + }, }, "container": mapstr.M{ "id": "b5285682fba7449c86452b89a800609440ecc88a7ba5f2d38bedfb85409b30b1", @@ -328,6 +355,12 @@ func TestAddProcessMetadata(t *testing.T) { "name": "root", "id": "0", }, + "thread": mapstr.M{ + "capabilities": mapstr.M{ + "effective": capMock, + "permitted": capMock, + }, + }, }, }, }, @@ -520,6 +553,12 @@ func TestAddProcessMetadata(t *testing.T) { "name": "root", "id": "0", }, + "thread": mapstr.M{ + "capabilities": mapstr.M{ + "effective": capMock, + "permitted": capMock, + }, + }, }, "container": mapstr.M{ "id": "b5285682fba7449c86452b89a800609440ecc88a7ba5f2d38bedfb85409b30b1", @@ -645,6 +684,12 @@ func TestAddProcessMetadata(t *testing.T) { "name": "user", "id": "1001", }, + "thread": mapstr.M{ + "capabilities": mapstr.M{ + "effective": capMock, + "permitted": capMock, + }, + }, }, }, }, diff --git a/libbeat/processors/add_process_metadata/config.go b/libbeat/processors/add_process_metadata/config.go index f16ba6771a8..1f2e9920da1 100644 --- a/libbeat/processors/add_process_metadata/config.go +++ b/libbeat/processors/add_process_metadata/config.go @@ -85,6 +85,12 @@ var defaultFields = mapstr.M{ "name": nil, "id": nil, }, + "thread": mapstr.M{ + "capabilities": mapstr.M{ + "effective": nil, + "permitted": nil, + }, + }, }, "container": mapstr.M{ "id": nil, diff --git a/libbeat/processors/add_process_metadata/gosysinfo_provider.go b/libbeat/processors/add_process_metadata/gosysinfo_provider.go index ecc94233dce..70d6e2a2c33 100644 --- a/libbeat/processors/add_process_metadata/gosysinfo_provider.go +++ b/libbeat/processors/add_process_metadata/gosysinfo_provider.go @@ -21,6 +21,7 @@ import ( "os/user" "strings" + "github.com/elastic/beats/v7/libbeat/common/capabilities" "github.com/elastic/go-sysinfo" "github.com/elastic/go-sysinfo/types" ) @@ -52,17 +53,25 @@ func (p gosysinfoProvider) GetProcessMetadata(pid int) (result *processMetadata, } } + // Capabilities are linux only and other systems will fail + // with ErrUnsupported. In the event of any errors, we simply + // don't report the capabilities. + capPermitted, _ := capabilities.FromPid(capabilities.Permitted, pid) + capEffective, _ := capabilities.FromPid(capabilities.Effective, pid) + r := processMetadata{ - name: info.Name, - args: info.Args, - env: env, - title: strings.Join(info.Args, " "), - exe: info.Exe, - pid: info.PID, - ppid: info.PPID, - startTime: info.StartTime, - username: username, - userid: userid, + name: info.Name, + args: info.Args, + env: env, + title: strings.Join(info.Args, " "), + exe: info.Exe, + pid: info.PID, + ppid: info.PPID, + capEffective: capEffective, + capPermitted: capPermitted, + startTime: info.StartTime, + username: username, + userid: userid, } r.fields = r.toMap() return &r, nil