Skip to content

Commit

Permalink
[CWS] sysctl_snapshot event (#34599)
Browse files Browse the repository at this point in the history
  • Loading branch information
Gui774ume authored Mar 5, 2025
1 parent 533a6f7 commit 1f25cd9
Show file tree
Hide file tree
Showing 15 changed files with 653 additions and 76 deletions.
9 changes: 9 additions & 0 deletions docs/cloud-workload-security/backend_linux.md
Original file line number Diff line number Diff line change
Expand Up @@ -1622,6 +1622,10 @@ CSM Threats event for Linux systems have the following JSON schema:
},
"SysCtlEvent": {
"properties": {
"proc": {
"type": "object",
"description": "Proc contains the /proc system control parameters and their values"
},
"action": {
"type": "string",
"description": "action performed on the system control parameter"
Expand Down Expand Up @@ -4399,6 +4403,10 @@ CSM Threats event for Linux systems have the following JSON schema:
{{< code-block lang="json" collapsible="true" >}}
{
"properties": {
"proc": {
"type": "object",
"description": "Proc contains the /proc system control parameters and their values"
},
"action": {
"type": "string",
"description": "action performed on the system control parameter"
Expand Down Expand Up @@ -4441,6 +4449,7 @@ CSM Threats event for Linux systems have the following JSON schema:

| Field | Description |
| ----- | ----------- |
| `proc` | Proc contains the /proc system control parameters and their values |
| `action` | action performed on the system control parameter |
| `file_position` | file_position is the position in the sysctl control parameter file at which the action occurred |
| `name` | name is the name of the system control parameter |
Expand Down
4 changes: 4 additions & 0 deletions docs/cloud-workload-security/backend_linux.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1611,6 +1611,10 @@
},
"SysCtlEvent": {
"properties": {
"proc": {
"type": "object",
"description": "Proc contains the /proc system control parameters and their values"
},
"action": {
"type": "string",
"description": "action performed on the system control parameter"
Expand Down
6 changes: 6 additions & 0 deletions pkg/config/setup/system_probe_cws.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,12 @@ func initCWSSystemProbeConfig(cfg pkgconfigmodel.Config) {
cfg.BindEnvAndSetDefault("runtime_security_config.hash_resolver.cache_size", 500)
cfg.BindEnvAndSetDefault("runtime_security_config.hash_resolver.replace", map[string]string{})

// CWS - SysCtl
cfg.BindEnvAndSetDefault("runtime_security_config.sysctl.enabled", true)
cfg.BindEnvAndSetDefault("runtime_security_config.sysctl.snapshot.enabled", true)
cfg.BindEnvAndSetDefault("runtime_security_config.sysctl.snapshot.period", "1h")
cfg.BindEnvAndSetDefault("runtime_security_config.sysctl.snapshot.ignored_base_names", []string{"netdev_rss_key", "stable_secret"})

// CWS - UserSessions
cfg.BindEnvAndSetDefault("runtime_security_config.user_sessions.cache_size", 1024)

Expand Down
15 changes: 15 additions & 0 deletions pkg/security/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,15 @@ type RuntimeSecurityConfig struct {
// HashResolverReplace is used to apply specific hash to specific file path
HashResolverReplace map[string]string

// SysCtlEnabled defines if the sysctl event should be enabled
SysCtlEnabled bool
// SysCtlSnapshotEnabled defines if the sysctl snapshot feature should be enabled
SysCtlSnapshotEnabled bool
// SysCtlSnapshotPeriod defines at which time interval a new snapshot of sysctl parameters should be sent
SysCtlSnapshotPeriod time.Duration
// SysCtlSnapshotIgnoredBaseNames defines the list of basenaes that should be ignored from the snapshot
SysCtlSnapshotIgnoredBaseNames []string

// UserSessionsCacheSize defines the size of the User Sessions cache size
UserSessionsCacheSize int

Expand Down Expand Up @@ -413,6 +422,12 @@ func NewRuntimeSecurityConfig() (*RuntimeSecurityConfig, error) {
HashResolverCacheSize: pkgconfigsetup.SystemProbe().GetInt("runtime_security_config.hash_resolver.cache_size"),
HashResolverReplace: pkgconfigsetup.SystemProbe().GetStringMapString("runtime_security_config.hash_resolver.replace"),

// SysCtl config parameter
SysCtlEnabled: pkgconfigsetup.SystemProbe().GetBool("runtime_security_config.sysctl.enabled"),
SysCtlSnapshotEnabled: pkgconfigsetup.SystemProbe().GetBool("runtime_security_config.sysctl.snapshot.enabled"),
SysCtlSnapshotPeriod: pkgconfigsetup.SystemProbe().GetDuration("runtime_security_config.sysctl.snapshot.period"),
SysCtlSnapshotIgnoredBaseNames: pkgconfigsetup.SystemProbe().GetStringSlice("runtime_security_config.sysctl.snapshot.ignored_base_names"),

// security profiles
SecurityProfileEnabled: pkgconfigsetup.SystemProbe().GetBool("runtime_security_config.security_profile.enabled"),
SecurityProfileMaxImageTags: pkgconfigsetup.SystemProbe().GetInt("runtime_security_config.security_profile.max_image_tags"),
Expand Down
6 changes: 6 additions & 0 deletions pkg/security/events/custom.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ const (
InternalCoreDumpRuleID = "internal_core_dump"
// InternalCoreDumpRuleDesc internal core dump
InternalCoreDumpRuleDesc = "Internal Core Dump"

// SysCtlSnapshotRuleID is the rule ID used when sending a sysctl snapshot event
SysCtlSnapshotRuleID = "sysctl_snapshot"
// SysCtlSnapshotRuleDesc is the description of the sysctl snapshot rule
SysCtlSnapshotRuleDesc = "A new sysctl snapshot was generated"
)

// AgentContainerContext is like model.ContainerContext, but without event based resolvers
Expand Down Expand Up @@ -105,6 +110,7 @@ func AllCustomRuleIDs() []string {
NoProcessContextErrorRuleID,
BrokenProcessLineageErrorRuleID,
InternalCoreDumpRuleID,
SysCtlSnapshotRuleID,
}
}

Expand Down
5 changes: 5 additions & 0 deletions pkg/security/probe/probe.go
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,11 @@ func (p *Probe) IsNetworkFlowMonitorEnabled() bool {
return p.IsNetworkEnabled() && p.Config.Probe.NetworkFlowMonitorEnabled
}

// IsSysctlEventEnabled returns whether the sysctl event is enabled
func (p *Probe) IsSysctlEventEnabled() bool {
return p.Config.RuntimeSecurity.SysCtlEnabled
}

// IsActivityDumpEnabled returns whether activity dump is enabled
func (p *Probe) IsActivityDumpEnabled() bool {
return p.Config.RuntimeSecurity.ActivityDumpEnabled
Expand Down
64 changes: 51 additions & 13 deletions pkg/security/probe/probe_ebpf.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import (
"github.com/DataDog/datadog-agent/pkg/security/probe/eventstream/ringbuffer"
"github.com/DataDog/datadog-agent/pkg/security/probe/kfilters"
"github.com/DataDog/datadog-agent/pkg/security/probe/managerhelper"
"github.com/DataDog/datadog-agent/pkg/security/probe/sysctl"
"github.com/DataDog/datadog-agent/pkg/security/resolvers"
"github.com/DataDog/datadog-agent/pkg/security/resolvers/mount"
"github.com/DataDog/datadog-agent/pkg/security/resolvers/netns"
Expand Down Expand Up @@ -149,15 +150,14 @@ type EBPFProbe struct {
supportsBPFSendSignal bool
processKiller *ProcessKiller

isRuntimeDiscarded bool
constantOffsets map[string]uint64
runtimeCompiled bool
useSyscallWrapper bool
useFentry bool
useRingBuffers bool
useMmapableMaps bool
cgroupSysctlSupported bool
cgroup2MountPath string
isRuntimeDiscarded bool
constantOffsets map[string]uint64
runtimeCompiled bool
useSyscallWrapper bool
useFentry bool
useRingBuffers bool
useMmapableMaps bool
cgroup2MountPath string

// On demand
onDemandManager *OnDemandProbesManager
Expand Down Expand Up @@ -271,6 +271,10 @@ func (p *EBPFProbe) selectFentryMode() {
p.useFentry = true
}

func (p *EBPFProbe) isCgroupSysCtlNotSupported() bool {
return IsCgroupSysCtlNotSupported(p.kernelVersion, p.cgroup2MountPath)
}

func (p *EBPFProbe) isNetworkNotSupported() bool {
return IsNetworkNotSupported(p.kernelVersion)
}
Expand Down Expand Up @@ -309,10 +313,15 @@ func (p *EBPFProbe) sanityChecks() error {
}

if p.config.Probe.NetworkFlowMonitorEnabled && p.isNetworkFlowMonitorNotSupported() {
seclog.Warnf("The network flow monitor feature of CWS requires a more recent kernel (at least 5.13) with support the bpf_for_each_elem map helper, setting event_monitoring_config.network.flow_monitor.enabled to false")
seclog.Warnf("The network flow monitor feature of CWS requires a more recent kernel (at least 5.13) with support for the bpf_for_each_elem map helper, setting event_monitoring_config.network.flow_monitor.enabled to false")
p.config.Probe.NetworkFlowMonitorEnabled = false
}

if p.config.RuntimeSecurity.SysCtlEnabled && p.isCgroupSysCtlNotSupported() {
seclog.Warnf("The sysctl tracking feature of CWS requires a more recent kernel with support for the cgroup/sysctl program type, setting runtime_security_config.sysctl.enabled to false")
p.config.RuntimeSecurity.SysCtlEnabled = false
}

return nil
}

Expand Down Expand Up @@ -597,6 +606,11 @@ func (p *EBPFProbe) Start() error {
// start new tc classifier loop
go p.startSetupNewTCClassifierLoop()

if p.config.RuntimeSecurity.SysCtlSnapshotEnabled {
// start sysctl snapshot loop
go p.startSysCtlSnapshotLoop()
}

return p.eventStream.Start(&p.wg)
}

Expand Down Expand Up @@ -1520,7 +1534,7 @@ func (p *EBPFProbe) validEventTypeForConfig(eventType string) bool {
case "network_flow_monitor":
return p.probe.IsNetworkFlowMonitorEnabled()
case "sysctl":
return p.cgroupSysctlSupported
return p.probe.IsSysctlEventEnabled()
}
return true
}
Expand Down Expand Up @@ -1755,6 +1769,31 @@ func (p *EBPFProbe) Close() error {
return p.Resolvers.Close()
}

func (p *EBPFProbe) startSysCtlSnapshotLoop() {
ticker := time.NewTicker(p.config.RuntimeSecurity.SysCtlSnapshotPeriod)
defer ticker.Stop()
for {
select {
case <-p.ctx.Done():
return
case <-ticker.C:
// create the sysctl snapshot
event, err := sysctl.NewSnapshotEvent(p.config.RuntimeSecurity.SysCtlSnapshotIgnoredBaseNames)
if err != nil {
seclog.Errorf("sysctl snapshot failed: %v", err)
continue
}

// send a sysctl snapshot event
rule := events.NewCustomRule(events.SysCtlSnapshotRuleID, events.SysCtlSnapshotRuleDesc)
customEvent := events.NewCustomEvent(model.CustomEventType, event)

p.probe.DispatchCustomEvent(rule, customEvent)
seclog.Tracef("sysctl snapshot sent !")
}
}
}

// QueuedNetworkDeviceError is used to indicate that the new network device was queued until its namespace handle is
// resolved.
type QueuedNetworkDeviceError struct {
Expand Down Expand Up @@ -2223,7 +2262,7 @@ func (p *EBPFProbe) initManagerOptionsExcludedFunctions() error {
p.managerOptions.AdditionalExcludedFunctionCollector = afBasedExcluder
}

if !p.cgroupSysctlSupported {
if !p.config.RuntimeSecurity.SysCtlEnabled {
p.managerOptions.ExcludedFunctions = append(p.managerOptions.ExcludedFunctions, probes.GetSysCtlProbeFunctionName())
}
return nil
Expand Down Expand Up @@ -2320,7 +2359,6 @@ func NewEBPFProbe(probe *Probe, config *config.Config, opts Opts) (*EBPFProbe, e
p.selectRingBuffersMode()
p.useMmapableMaps = p.kernelVersion.HaveMmapableMaps()
p.initCgroup2MountPath()
p.cgroupSysctlSupported = len(p.cgroup2MountPath) > 0 && p.kernelVersion.HasCgroupSysctlSupportWithRingbuf()

p.Manager = ebpf.NewRuntimeSecurityManager(p.useRingBuffers)

Expand Down
5 changes: 5 additions & 0 deletions pkg/security/probe/probe_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ func IsNetworkNotSupported(kv *kernel.Version) bool {
return kv.IsRH7Kernel() || kv.IsOracleUEKKernel()
}

// IsCgroupSysCtlNotSupported returns if the cgroup/sysctl program is supported
func IsCgroupSysCtlNotSupported(kv *kernel.Version, cgroup2MountPath string) bool {
return len(cgroup2MountPath) > 0 && kv.HasCgroupSysctlSupportWithRingbuf()
}

// IsNetworkFlowMonitorNotSupported returns if the network flow monitor feature is supported
func IsNetworkFlowMonitorNotSupported(kv *kernel.Version) bool {
return IsNetworkNotSupported(kv) || !kv.IsMapValuesToMapHelpersAllowed() || !kv.HasBPFForEachMapElemHelper()
Expand Down
Loading

0 comments on commit 1f25cd9

Please sign in to comment.