Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CWS] sysctl_snapshot event #34599

Merged
merged 2 commits into from
Mar 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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