/
syscalls_monitor.go
111 lines (92 loc) · 2.91 KB
/
syscalls_monitor.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2016-present Datadog, Inc.
//go:build linux
// Package syscalls holds syscalls related files
package syscalls
import (
"encoding/binary"
"fmt"
"github.com/DataDog/datadog-agent/pkg/security/ebpf"
"github.com/DataDog/datadog-agent/pkg/security/metrics"
"github.com/DataDog/datadog-agent/pkg/security/probe/managerhelper"
"github.com/DataDog/datadog-agent/pkg/security/utils"
manager "github.com/DataDog/ebpf-manager"
lib "github.com/cilium/ebpf"
"github.com/DataDog/datadog-agent/pkg/security/secl/model"
"github.com/DataDog/datadog-go/v5/statsd"
)
// Monitor defines an approver monitor
type Monitor struct {
statsdClient statsd.ClientInterface
stats *lib.Map
enabled *lib.Map
numCPU int
}
// SendStats send stats
func (d *Monitor) SendStats() error {
iterator := d.stats.Iterate()
statsAcrossAllCPUs := make([][8]byte, d.numCPU)
statsByEventType := make([]int32, model.MaxAllEventType)
var eventType uint32
for iterator.Next(&eventType, &statsAcrossAllCPUs) {
if int(eventType) >= cap(statsByEventType) {
// this should never happen
continue
}
// aggregate all cpu stats
for _, stat := range statsAcrossAllCPUs {
statsByEventType[eventType] += int32(binary.NativeEndian.Uint32(stat[0:4]))
}
}
for eventType, inflight := range statsByEventType {
eventTypeTag := fmt.Sprintf("event_type:%s", model.EventType(eventType).String())
tagsEvents := []string{
eventTypeTag,
}
_ = d.statsdClient.Gauge(metrics.MetricSyscallsInFlight, float64(inflight), tagsEvents, 1.0)
}
return nil
}
// Enable the monitor
func (d *Monitor) Enable() error {
enabled := uint32(1)
return d.enabled.Put(ebpf.ZeroUint32MapItem, enabled)
}
// Disable the monitor
func (d *Monitor) Disable() error {
enabled := uint32(0)
return d.enabled.Put(ebpf.ZeroUint32MapItem, enabled)
}
// Flush flush stat entries
func (d *Monitor) Flush() error {
stats := make([][8]byte, d.numCPU)
for key := uint32(0); key != uint32(model.MaxKernelEventType); key++ {
_ = d.stats.Update(key, stats, lib.UpdateAny)
}
return nil
}
// NewSyscallsMonitor returns a new Monitor
func NewSyscallsMonitor(manager *manager.Manager, statsdClient statsd.ClientInterface) (*Monitor, error) {
numCPU, err := utils.NumCPU()
if err != nil {
return nil, fmt.Errorf("couldn't fetch the host CPU count: %w", err)
}
monitor := &Monitor{
statsdClient: statsdClient,
numCPU: numCPU,
}
stats, err := managerhelper.Map(manager, "syscalls_stats")
if err != nil {
return nil, err
}
monitor.stats = stats
// kprobes & kretprobes should be now all installed
enabled, err := managerhelper.Map(manager, "syscalls_stats_enabled")
if err != nil {
return nil, err
}
monitor.enabled = enabled
return monitor, nil
}